1
The following changes since commit fc3dbb90f2eb069801bfb4cfe9cbc83cf9c5f4a9:
1
The following changes since commit 30aa19446d82358a30eac3b556b4d6641e00b7c1:
2
2
3
Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging (2019-02-21 13:09:33 +0000)
3
Merge remote-tracking branch 'remotes/cschoenebeck/tags/pull-9p-20200812' into staging (2020-08-24 16:39:53 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/stefanha/qemu.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-08-25
8
8
9
for you to fetch changes up to 9a9f4b74fa547b68edb38fa414999836770a4735:
9
for you to fetch changes up to c576fd97d4ca77b5a1a27728df11a61083dbfa98:
10
10
11
tests/virtio-blk: add test for DISCARD command (2019-02-22 09:42:17 +0000)
11
iotests: Add tests for qcow2 images with extended L2 entries (2020-08-25 10:20:18 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Block patches:
15
- qcow2 subclusters (extended L2 entries)
15
16
16
----------------------------------------------------------------
17
----------------------------------------------------------------
18
Alberto Garcia (34):
19
qcow2: Make Qcow2AioTask store the full host offset
20
qcow2: Convert qcow2_get_cluster_offset() into qcow2_get_host_offset()
21
qcow2: Add calculate_l2_meta()
22
qcow2: Split cluster_needs_cow() out of count_cow_clusters()
23
qcow2: Process QCOW2_CLUSTER_ZERO_ALLOC clusters in handle_copied()
24
qcow2: Add get_l2_entry() and set_l2_entry()
25
qcow2: Document the Extended L2 Entries feature
26
qcow2: Add dummy has_subclusters() function
27
qcow2: Add subcluster-related fields to BDRVQcow2State
28
qcow2: Add offset_to_sc_index()
29
qcow2: Add offset_into_subcluster() and size_to_subclusters()
30
qcow2: Add l2_entry_size()
31
qcow2: Update get/set_l2_entry() and add get/set_l2_bitmap()
32
qcow2: Add QCow2SubclusterType and qcow2_get_subcluster_type()
33
qcow2: Add qcow2_get_subcluster_range_type()
34
qcow2: Add qcow2_cluster_is_allocated()
35
qcow2: Add cluster type parameter to qcow2_get_host_offset()
36
qcow2: Replace QCOW2_CLUSTER_* with QCOW2_SUBCLUSTER_*
37
qcow2: Handle QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC
38
qcow2: Add subcluster support to calculate_l2_meta()
39
qcow2: Add subcluster support to qcow2_get_host_offset()
40
qcow2: Add subcluster support to zero_in_l2_slice()
41
qcow2: Add subcluster support to discard_in_l2_slice()
42
qcow2: Add subcluster support to check_refcounts_l2()
43
qcow2: Update L2 bitmap in qcow2_alloc_cluster_link_l2()
44
qcow2: Clear the L2 bitmap when allocating a compressed cluster
45
qcow2: Add subcluster support to handle_alloc_space()
46
qcow2: Add subcluster support to qcow2_co_pwrite_zeroes()
47
qcow2: Add subcluster support to qcow2_measure()
48
qcow2: Add prealloc field to QCowL2Meta
49
qcow2: Add the 'extended_l2' option and the QCOW2_INCOMPAT_EXTL2 bit
50
qcow2: Allow preallocation and backing files if extended_l2 is set
51
qcow2: Assert that expand_zero_clusters_in_l1() does not support
52
subclusters
53
iotests: Add tests for qcow2 images with extended L2 entries
17
54
18
Stefano Garzarella (10):
55
docs/interop/qcow2.txt | 68 ++-
19
virtio-blk: add acct_failed param to virtio_blk_handle_rw_error()
56
docs/qcow2-cache.txt | 19 +-
20
virtio-blk: add host_features field in VirtIOBlock
57
qapi/block-core.json | 7 +
21
virtio-blk: add "discard" and "write-zeroes" properties
58
block/qcow2.h | 211 ++++++-
22
virtio-net: make VirtIOFeature usable for other virtio devices
59
include/block/block_int.h | 1 +
23
virtio-blk: set config size depending on the features enabled
60
block/qcow2-cluster.c | 906 +++++++++++++++++++++----------
24
virtio-blk: add DISCARD and WRITE_ZEROES features
61
block/qcow2-refcount.c | 47 +-
25
tests/virtio-blk: change assert on data_size in virtio_blk_request()
62
block/qcow2.c | 302 +++++++----
26
tests/virtio-blk: add virtio_blk_fix_dwz_hdr() function
63
block/trace-events | 2 +-
27
tests/virtio-blk: add test for WRITE_ZEROES command
64
tests/qemu-iotests/031.out | 8 +-
28
tests/virtio-blk: add test for DISCARD command
65
tests/qemu-iotests/036.out | 4 +-
29
66
tests/qemu-iotests/049.out | 102 ++--
30
Vladimir Sementsov-Ogievskiy (17):
67
tests/qemu-iotests/060.out | 3 +-
31
block: enhance QEMUIOVector structure
68
tests/qemu-iotests/061 | 6 +
32
block/io: use qemu_iovec_init_buf
69
tests/qemu-iotests/061.out | 25 +-
33
block/block-backend: use QEMU_IOVEC_INIT_BUF
70
tests/qemu-iotests/065 | 12 +-
34
block/backup: use qemu_iovec_init_buf
71
tests/qemu-iotests/082.out | 39 +-
35
block/commit: use QEMU_IOVEC_INIT_BUF
72
tests/qemu-iotests/085.out | 38 +-
36
block/stream: use QEMU_IOVEC_INIT_BUF
73
tests/qemu-iotests/144.out | 4 +-
37
block/parallels: use QEMU_IOVEC_INIT_BUF
74
tests/qemu-iotests/182.out | 2 +-
38
block/qcow: use qemu_iovec_init_buf
75
tests/qemu-iotests/185.out | 8 +-
39
block/qcow2: use qemu_iovec_init_buf
76
tests/qemu-iotests/198 | 2 +
40
block/qed: use qemu_iovec_init_buf
77
tests/qemu-iotests/206.out | 6 +-
41
block/vmdk: use qemu_iovec_init_buf
78
tests/qemu-iotests/242.out | 5 +
42
qemu-img: use qemu_iovec_init_buf
79
tests/qemu-iotests/255.out | 8 +-
43
migration/block: use qemu_iovec_init_buf
80
tests/qemu-iotests/271 | 901 ++++++++++++++++++++++++++++++
44
tests/test-bdrv-drain: use QEMU_IOVEC_INIT_BUF
81
tests/qemu-iotests/271.out | 726 +++++++++++++++++++++++++
45
hw/ide: drop iov field from IDEState
82
tests/qemu-iotests/274.out | 49 +-
46
hw/ide: drop iov field from IDEBufferedRequest
83
tests/qemu-iotests/280.out | 2 +-
47
hw/ide: drop iov field from IDEDMA
84
tests/qemu-iotests/291.out | 2 +
48
85
tests/qemu-iotests/302.out | 1 +
49
include/hw/ide/internal.h | 3 -
86
tests/qemu-iotests/303.out | 4 +-
50
include/hw/virtio/virtio-blk.h | 6 +-
87
tests/qemu-iotests/common.filter | 1 +
51
include/hw/virtio/virtio.h | 15 ++
88
tests/qemu-iotests/group | 1 +
52
include/qemu/iov.h | 64 ++++++++-
89
34 files changed, 2952 insertions(+), 570 deletions(-)
53
block/backup.c | 5 +-
90
create mode 100755 tests/qemu-iotests/271
54
block/block-backend.c | 13 +-
91
create mode 100644 tests/qemu-iotests/271.out
55
block/commit.c | 7 +-
56
block/io.c | 89 +++---------
57
block/parallels.c | 13 +-
58
block/qcow.c | 21 +--
59
block/qcow2.c | 12 +-
60
block/qed-table.c | 16 +--
61
block/qed.c | 31 ++---
62
block/stream.c | 7 +-
63
block/vmdk.c | 7 +-
64
hw/block/virtio-blk.c | 245 ++++++++++++++++++++++++++++++---
65
hw/core/machine.c | 2 +
66
hw/ide/atapi.c | 14 +-
67
hw/ide/core.c | 19 ++-
68
hw/net/virtio-net.c | 31 +----
69
hw/virtio/virtio.c | 15 ++
70
migration/block.c | 10 +-
71
qemu-img.c | 10 +-
72
tests/test-bdrv-drain.c | 29 +---
73
tests/virtio-blk-test.c | 127 ++++++++++++++++-
74
25 files changed, 525 insertions(+), 286 deletions(-)
75
92
76
--
93
--
77
2.20.1
94
2.26.2
78
95
79
96
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
The file_cluster_offset field of Qcow2AioTask stores a cluster-aligned
4
host offset. In practice this is not very useful because all users(*)
5
of this structure need the final host offset into the cluster, which
6
they calculate using
7
8
host_offset = file_cluster_offset + offset_into_cluster(s, offset)
9
10
There is no reason why Qcow2AioTask cannot store host_offset directly
11
and that is what this patch does.
12
13
(*) compressed clusters are the exception: in this case what
14
file_cluster_offset was storing was the full compressed cluster
15
descriptor (offset + size). This does not change with this patch
16
but it is documented now.
17
18
Signed-off-by: Alberto Garcia <berto@igalia.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Reviewed-by: Max Reitz <mreitz@redhat.com>
21
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
22
Message-Id: <07c4b15c644dcf06c9459f98846ac1c4ea96e26f.1594396418.git.berto@igalia.com>
23
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
25
block/qcow2.c | 69 ++++++++++++++++++++++------------------------
26
block/trace-events | 2 +-
27
2 files changed, 34 insertions(+), 37 deletions(-)
28
29
diff --git a/block/qcow2.c b/block/qcow2.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2.c
32
+++ b/block/qcow2.c
33
@@ -XXX,XX +XXX,XX @@ typedef struct {
34
35
static int coroutine_fn
36
qcow2_co_preadv_compressed(BlockDriverState *bs,
37
- uint64_t file_cluster_offset,
38
+ uint64_t cluster_descriptor,
39
uint64_t offset,
40
uint64_t bytes,
41
QEMUIOVector *qiov,
42
@@ -XXX,XX +XXX,XX @@ out:
43
44
static coroutine_fn int
45
qcow2_co_preadv_encrypted(BlockDriverState *bs,
46
- uint64_t file_cluster_offset,
47
+ uint64_t host_offset,
48
uint64_t offset,
49
uint64_t bytes,
50
QEMUIOVector *qiov,
51
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_encrypted(BlockDriverState *bs,
52
}
53
54
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
55
- ret = bdrv_co_pread(s->data_file,
56
- file_cluster_offset + offset_into_cluster(s, offset),
57
- bytes, buf, 0);
58
+ ret = bdrv_co_pread(s->data_file, host_offset, bytes, buf, 0);
59
if (ret < 0) {
60
goto fail;
61
}
62
63
- if (qcow2_co_decrypt(bs,
64
- file_cluster_offset + offset_into_cluster(s, offset),
65
- offset, buf, bytes) < 0)
66
+ if (qcow2_co_decrypt(bs, host_offset, offset, buf, bytes) < 0)
67
{
68
ret = -EIO;
69
goto fail;
70
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2AioTask {
71
72
BlockDriverState *bs;
73
QCow2ClusterType cluster_type; /* only for read */
74
- uint64_t file_cluster_offset;
75
+ uint64_t host_offset; /* or full descriptor in compressed clusters */
76
uint64_t offset;
77
uint64_t bytes;
78
QEMUIOVector *qiov;
79
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
80
AioTaskPool *pool,
81
AioTaskFunc func,
82
QCow2ClusterType cluster_type,
83
- uint64_t file_cluster_offset,
84
+ uint64_t host_offset,
85
uint64_t offset,
86
uint64_t bytes,
87
QEMUIOVector *qiov,
88
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
89
.bs = bs,
90
.cluster_type = cluster_type,
91
.qiov = qiov,
92
- .file_cluster_offset = file_cluster_offset,
93
+ .host_offset = host_offset,
94
.offset = offset,
95
.bytes = bytes,
96
.qiov_offset = qiov_offset,
97
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
98
99
trace_qcow2_add_task(qemu_coroutine_self(), bs, pool,
100
func == qcow2_co_preadv_task_entry ? "read" : "write",
101
- cluster_type, file_cluster_offset, offset, bytes,
102
+ cluster_type, host_offset, offset, bytes,
103
qiov, qiov_offset);
104
105
if (!pool) {
106
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
107
108
static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
109
QCow2ClusterType cluster_type,
110
- uint64_t file_cluster_offset,
111
+ uint64_t host_offset,
112
uint64_t offset, uint64_t bytes,
113
QEMUIOVector *qiov,
114
size_t qiov_offset)
115
{
116
BDRVQcow2State *s = bs->opaque;
117
- int offset_in_cluster = offset_into_cluster(s, offset);
118
119
switch (cluster_type) {
120
case QCOW2_CLUSTER_ZERO_PLAIN:
121
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
122
qiov, qiov_offset, 0);
123
124
case QCOW2_CLUSTER_COMPRESSED:
125
- return qcow2_co_preadv_compressed(bs, file_cluster_offset,
126
+ return qcow2_co_preadv_compressed(bs, host_offset,
127
offset, bytes, qiov, qiov_offset);
128
129
case QCOW2_CLUSTER_NORMAL:
130
- assert(offset_into_cluster(s, file_cluster_offset) == 0);
131
if (bs->encrypted) {
132
- return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
133
+ return qcow2_co_preadv_encrypted(bs, host_offset,
134
offset, bytes, qiov, qiov_offset);
135
}
136
137
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
138
- return bdrv_co_preadv_part(s->data_file,
139
- file_cluster_offset + offset_in_cluster,
140
+ return bdrv_co_preadv_part(s->data_file, host_offset,
141
bytes, qiov, qiov_offset, 0);
142
143
default:
144
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
145
146
assert(!t->l2meta);
147
148
- return qcow2_co_preadv_task(t->bs, t->cluster_type, t->file_cluster_offset,
149
+ return qcow2_co_preadv_task(t->bs, t->cluster_type, t->host_offset,
150
t->offset, t->bytes, t->qiov, t->qiov_offset);
151
}
152
153
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
154
{
155
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
156
} else {
157
+ /*
158
+ * For compressed clusters the variable cluster_offset
159
+ * does not actually store the offset but the full
160
+ * descriptor. We need to leave it unchanged because
161
+ * that's what qcow2_co_preadv_compressed() expects.
162
+ */
163
+ uint64_t host_offset = (ret == QCOW2_CLUSTER_COMPRESSED) ?
164
+ cluster_offset :
165
+ cluster_offset + offset_into_cluster(s, offset);
166
if (!aio && cur_bytes != bytes) {
167
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
168
}
169
ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, ret,
170
- cluster_offset, offset, cur_bytes,
171
+ host_offset, offset, cur_bytes,
172
qiov, qiov_offset, NULL);
173
if (ret < 0) {
174
goto out;
175
@@ -XXX,XX +XXX,XX @@ static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
176
* not use it somehow after qcow2_co_pwritev_task() call
177
*/
178
static coroutine_fn int qcow2_co_pwritev_task(BlockDriverState *bs,
179
- uint64_t file_cluster_offset,
180
+ uint64_t host_offset,
181
uint64_t offset, uint64_t bytes,
182
QEMUIOVector *qiov,
183
uint64_t qiov_offset,
184
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_task(BlockDriverState *bs,
185
int ret;
186
BDRVQcow2State *s = bs->opaque;
187
void *crypt_buf = NULL;
188
- int offset_in_cluster = offset_into_cluster(s, offset);
189
QEMUIOVector encrypted_qiov;
190
191
if (bs->encrypted) {
192
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_task(BlockDriverState *bs,
193
}
194
qemu_iovec_to_buf(qiov, qiov_offset, crypt_buf, bytes);
195
196
- if (qcow2_co_encrypt(bs, file_cluster_offset + offset_in_cluster,
197
- offset, crypt_buf, bytes) < 0)
198
- {
199
+ if (qcow2_co_encrypt(bs, host_offset, offset, crypt_buf, bytes) < 0) {
200
ret = -EIO;
201
goto out_unlocked;
202
}
203
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_task(BlockDriverState *bs,
204
*/
205
if (!merge_cow(offset, bytes, qiov, qiov_offset, l2meta)) {
206
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
207
- trace_qcow2_writev_data(qemu_coroutine_self(),
208
- file_cluster_offset + offset_in_cluster);
209
- ret = bdrv_co_pwritev_part(s->data_file,
210
- file_cluster_offset + offset_in_cluster,
211
+ trace_qcow2_writev_data(qemu_coroutine_self(), host_offset);
212
+ ret = bdrv_co_pwritev_part(s->data_file, host_offset,
213
bytes, qiov, qiov_offset, 0);
214
if (ret < 0) {
215
goto out_unlocked;
216
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task)
217
218
assert(!t->cluster_type);
219
220
- return qcow2_co_pwritev_task(t->bs, t->file_cluster_offset,
221
+ return qcow2_co_pwritev_task(t->bs, t->host_offset,
222
t->offset, t->bytes, t->qiov, t->qiov_offset,
223
t->l2meta);
224
}
225
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
226
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
227
}
228
ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_task_entry, 0,
229
- cluster_offset, offset, cur_bytes,
230
- qiov, qiov_offset, l2meta);
231
+ cluster_offset + offset_in_cluster, offset,
232
+ cur_bytes, qiov, qiov_offset, l2meta);
233
l2meta = NULL; /* l2meta is consumed by qcow2_co_pwritev_task() */
234
if (ret < 0) {
235
goto fail_nometa;
236
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
237
238
static int coroutine_fn
239
qcow2_co_preadv_compressed(BlockDriverState *bs,
240
- uint64_t file_cluster_offset,
241
+ uint64_t cluster_descriptor,
242
uint64_t offset,
243
uint64_t bytes,
244
QEMUIOVector *qiov,
245
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
246
uint8_t *buf, *out_buf;
247
int offset_in_cluster = offset_into_cluster(s, offset);
248
249
- coffset = file_cluster_offset & s->cluster_offset_mask;
250
- nb_csectors = ((file_cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
251
+ coffset = cluster_descriptor & s->cluster_offset_mask;
252
+ nb_csectors = ((cluster_descriptor >> s->csize_shift) & s->csize_mask) + 1;
253
csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
254
(coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
255
256
diff --git a/block/trace-events b/block/trace-events
257
index XXXXXXX..XXXXXXX 100644
258
--- a/block/trace-events
259
+++ b/block/trace-events
260
@@ -XXX,XX +XXX,XX @@ luring_io_uring_submit(void *s, int ret) "LuringState %p ret %d"
261
luring_resubmit_short_read(void *s, void *luringcb, int nread) "LuringState %p luringcb %p nread %d"
262
263
# qcow2.c
264
-qcow2_add_task(void *co, void *bs, void *pool, const char *action, int cluster_type, uint64_t file_cluster_offset, uint64_t offset, uint64_t bytes, void *qiov, size_t qiov_offset) "co %p bs %p pool %p: %s: cluster_type %d file_cluster_offset %" PRIu64 " offset %" PRIu64 " bytes %" PRIu64 " qiov %p qiov_offset %zu"
265
+qcow2_add_task(void *co, void *bs, void *pool, const char *action, int cluster_type, uint64_t host_offset, uint64_t offset, uint64_t bytes, void *qiov, size_t qiov_offset) "co %p bs %p pool %p: %s: cluster_type %d file_cluster_offset %" PRIu64 " offset %" PRIu64 " bytes %" PRIu64 " qiov %p qiov_offset %zu"
266
qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset 0x%" PRIx64 " bytes %d"
267
qcow2_writev_done_req(void *co, int ret) "co %p ret %d"
268
qcow2_writev_start_part(void *co) "co %p"
269
--
270
2.26.2
271
272
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
qcow2_get_cluster_offset() takes an (unaligned) guest offset and
4
returns the (aligned) offset of the corresponding cluster in the qcow2
5
image.
6
7
In practice none of the callers need to know where the cluster starts
8
so this patch makes the function calculate and return the final host
9
offset directly. The function is also renamed accordingly.
10
11
There is a pre-existing exception with compressed clusters: in this
12
case the function returns the complete cluster descriptor (containing
13
the offset and size of the compressed data). This does not change with
14
this patch but it is now documented.
15
16
Signed-off-by: Alberto Garcia <berto@igalia.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Message-Id: <ffae6cdc5ca8950e8280ac0f696dcc376cb07095.1594396418.git.berto@igalia.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
---
21
block/qcow2.h | 4 ++--
22
block/qcow2-cluster.c | 41 +++++++++++++++++++++++------------------
23
block/qcow2.c | 24 +++++++-----------------
24
3 files changed, 32 insertions(+), 37 deletions(-)
25
26
diff --git a/block/qcow2.h b/block/qcow2.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/qcow2.h
29
+++ b/block/qcow2.h
30
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
31
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
32
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
33
34
-int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
35
- unsigned int *bytes, uint64_t *cluster_offset);
36
+int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
37
+ unsigned int *bytes, uint64_t *host_offset);
38
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
39
unsigned int *bytes, uint64_t *host_offset,
40
QCowL2Meta **m);
41
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/block/qcow2-cluster.c
44
+++ b/block/qcow2-cluster.c
45
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
46
47
48
/*
49
- * get_cluster_offset
50
+ * get_host_offset
51
*
52
- * For a given offset of the virtual disk, find the cluster type and offset in
53
- * the qcow2 file. The offset is stored in *cluster_offset.
54
+ * For a given offset of the virtual disk find the equivalent host
55
+ * offset in the qcow2 file and store it in *host_offset. Neither
56
+ * offset needs to be aligned to a cluster boundary.
57
+ *
58
+ * If the cluster is unallocated then *host_offset will be 0.
59
+ * If the cluster is compressed then *host_offset will contain the
60
+ * complete compressed cluster descriptor.
61
*
62
* On entry, *bytes is the maximum number of contiguous bytes starting at
63
* offset that we are interested in.
64
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
65
* Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
66
* cases.
67
*/
68
-int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
69
- unsigned int *bytes, uint64_t *cluster_offset)
70
+int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
71
+ unsigned int *bytes, uint64_t *host_offset)
72
{
73
BDRVQcow2State *s = bs->opaque;
74
unsigned int l2_index;
75
- uint64_t l1_index, l2_offset, *l2_slice;
76
+ uint64_t l1_index, l2_offset, *l2_slice, l2_entry;
77
int c;
78
unsigned int offset_in_cluster;
79
uint64_t bytes_available, bytes_needed, nb_clusters;
80
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
81
bytes_needed = bytes_available;
82
}
83
84
- *cluster_offset = 0;
85
+ *host_offset = 0;
86
87
/* seek to the l2 offset in the l1 table */
88
89
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
90
/* find the cluster offset for the given disk offset */
91
92
l2_index = offset_to_l2_slice_index(s, offset);
93
- *cluster_offset = be64_to_cpu(l2_slice[l2_index]);
94
+ l2_entry = be64_to_cpu(l2_slice[l2_index]);
95
96
nb_clusters = size_to_clusters(s, bytes_needed);
97
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
98
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
99
* true */
100
assert(nb_clusters <= INT_MAX);
101
102
- type = qcow2_get_cluster_type(bs, *cluster_offset);
103
+ type = qcow2_get_cluster_type(bs, l2_entry);
104
if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||
105
type == QCOW2_CLUSTER_ZERO_ALLOC)) {
106
qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
107
@@ -XXX,XX +XXX,XX @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
108
}
109
/* Compressed clusters can only be processed one by one */
110
c = 1;
111
- *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
112
+ *host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;
113
break;
114
case QCOW2_CLUSTER_ZERO_PLAIN:
115
case QCOW2_CLUSTER_UNALLOCATED:
116
/* how many empty clusters ? */
117
c = count_contiguous_clusters_unallocated(bs, nb_clusters,
118
&l2_slice[l2_index], type);
119
- *cluster_offset = 0;
120
break;
121
case QCOW2_CLUSTER_ZERO_ALLOC:
122
- case QCOW2_CLUSTER_NORMAL:
123
+ case QCOW2_CLUSTER_NORMAL: {
124
+ uint64_t host_cluster_offset = l2_entry & L2E_OFFSET_MASK;
125
+ *host_offset = host_cluster_offset + offset_in_cluster;
126
/* how many allocated clusters ? */
127
c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
128
&l2_slice[l2_index], QCOW_OFLAG_ZERO);
129
- *cluster_offset &= L2E_OFFSET_MASK;
130
- if (offset_into_cluster(s, *cluster_offset)) {
131
+ if (offset_into_cluster(s, host_cluster_offset)) {
132
qcow2_signal_corruption(bs, true, -1, -1,
133
"Cluster allocation offset %#"
134
PRIx64 " unaligned (L2 offset: %#" PRIx64
135
- ", L2 index: %#x)", *cluster_offset,
136
+ ", L2 index: %#x)", host_cluster_offset,
137
l2_offset, l2_index);
138
ret = -EIO;
139
goto fail;
140
}
141
- if (has_data_file(bs) && *cluster_offset != offset - offset_in_cluster)
142
- {
143
+ if (has_data_file(bs) && *host_offset != offset) {
144
qcow2_signal_corruption(bs, true, -1, -1,
145
"External data file host cluster offset %#"
146
PRIx64 " does not match guest cluster "
147
"offset: %#" PRIx64
148
- ", L2 index: %#x)", *cluster_offset,
149
+ ", L2 index: %#x)", host_cluster_offset,
150
offset - offset_in_cluster, l2_index);
151
ret = -EIO;
152
goto fail;
153
}
154
break;
155
+ }
156
default:
157
abort();
158
}
159
diff --git a/block/qcow2.c b/block/qcow2.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/qcow2.c
162
+++ b/block/qcow2.c
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
164
BlockDriverState **file)
165
{
166
BDRVQcow2State *s = bs->opaque;
167
- uint64_t cluster_offset;
168
+ uint64_t host_offset;
169
unsigned int bytes;
170
int ret, status = 0;
171
172
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
173
}
174
175
bytes = MIN(INT_MAX, count);
176
- ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
177
+ ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset);
178
qemu_co_mutex_unlock(&s->lock);
179
if (ret < 0) {
180
return ret;
181
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
182
183
if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
184
!s->crypto) {
185
- *map = cluster_offset | offset_into_cluster(s, offset);
186
+ *map = host_offset;
187
*file = s->data_file->bs;
188
status |= BDRV_BLOCK_OFFSET_VALID;
189
}
190
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
191
BDRVQcow2State *s = bs->opaque;
192
int ret = 0;
193
unsigned int cur_bytes; /* number of bytes in current iteration */
194
- uint64_t cluster_offset = 0;
195
+ uint64_t host_offset = 0;
196
AioTaskPool *aio = NULL;
197
198
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
199
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
200
}
201
202
qemu_co_mutex_lock(&s->lock);
203
- ret = qcow2_get_cluster_offset(bs, offset, &cur_bytes, &cluster_offset);
204
+ ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset);
205
qemu_co_mutex_unlock(&s->lock);
206
if (ret < 0) {
207
goto out;
208
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
209
{
210
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
211
} else {
212
- /*
213
- * For compressed clusters the variable cluster_offset
214
- * does not actually store the offset but the full
215
- * descriptor. We need to leave it unchanged because
216
- * that's what qcow2_co_preadv_compressed() expects.
217
- */
218
- uint64_t host_offset = (ret == QCOW2_CLUSTER_COMPRESSED) ?
219
- cluster_offset :
220
- cluster_offset + offset_into_cluster(s, offset);
221
if (!aio && cur_bytes != bytes) {
222
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
223
}
224
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
225
offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
226
bytes = s->cluster_size;
227
nr = s->cluster_size;
228
- ret = qcow2_get_cluster_offset(bs, offset, &nr, &off);
229
+ ret = qcow2_get_host_offset(bs, offset, &nr, &off);
230
if (ret != QCOW2_CLUSTER_UNALLOCATED &&
231
ret != QCOW2_CLUSTER_ZERO_PLAIN &&
232
ret != QCOW2_CLUSTER_ZERO_ALLOC) {
233
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
234
cur_bytes = MIN(bytes, INT_MAX);
235
cur_write_flags = write_flags;
236
237
- ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes, &copy_offset);
238
+ ret = qcow2_get_host_offset(bs, src_offset, &cur_bytes, &copy_offset);
239
if (ret < 0) {
240
goto out;
241
}
242
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
243
244
case QCOW2_CLUSTER_NORMAL:
245
child = s->data_file;
246
- copy_offset += offset_into_cluster(s, src_offset);
247
break;
248
249
default:
250
--
251
2.26.2
252
253
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
If the WRITE_ZEROES feature is enabled, we check this command
3
handle_alloc() creates a QCowL2Meta structure in order to update the
4
in the test_basic().
4
image metadata and perform the necessary copy-on-write operations.
5
5
6
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
6
This patch moves that code to a separate function so it can be used
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
from other places.
8
Acked-by: Thomas Huth <thuth@redhat.com>
8
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Message-id: 20190221103314.58500-10-sgarzare@redhat.com
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-Id: <20190221103314.58500-10-sgarzare@redhat.com>
11
Message-Id: <e5bc4a648dac31972bfa7a0e554be8064be78799.1594396418.git.berto@igalia.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
13
---
14
tests/virtio-blk-test.c | 62 +++++++++++++++++++++++++++++++++++++++++
14
block/qcow2-cluster.c | 77 +++++++++++++++++++++++++++++--------------
15
1 file changed, 62 insertions(+)
15
1 file changed, 53 insertions(+), 24 deletions(-)
16
16
17
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/virtio-blk-test.c
19
--- a/block/qcow2-cluster.c
20
+++ b/tests/virtio-blk-test.c
20
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
21
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
22
22
}
23
guest_free(alloc, req_addr);
23
}
24
24
25
+ if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
25
+/*
26
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
26
+ * For a given write request, create a new QCowL2Meta structure, add
27
+ void *expected;
27
+ * it to @m and the BDRVQcow2State.cluster_allocs list.
28
+ *
29
+ * @host_cluster_offset points to the beginning of the first cluster.
30
+ *
31
+ * @guest_offset and @bytes indicate the offset and length of the
32
+ * request.
33
+ *
34
+ * If @keep_old is true it means that the clusters were already
35
+ * allocated and will be overwritten. If false then the clusters are
36
+ * new and we have to decrease the reference count of the old ones.
37
+ */
38
+static void calculate_l2_meta(BlockDriverState *bs,
39
+ uint64_t host_cluster_offset,
40
+ uint64_t guest_offset, unsigned bytes,
41
+ QCowL2Meta **m, bool keep_old)
42
+{
43
+ BDRVQcow2State *s = bs->opaque;
44
+ unsigned cow_start_from = 0;
45
+ unsigned cow_start_to = offset_into_cluster(s, guest_offset);
46
+ unsigned cow_end_from = cow_start_to + bytes;
47
+ unsigned cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
48
+ unsigned nb_clusters = size_to_clusters(s, cow_end_from);
49
+ QCowL2Meta *old_m = *m;
28
+
50
+
29
+ /*
51
+ *m = g_malloc0(sizeof(**m));
30
+ * WRITE_ZEROES request on the same sector of previous test where
52
+ **m = (QCowL2Meta) {
31
+ * we wrote "TEST".
53
+ .next = old_m,
32
+ */
33
+ req.type = VIRTIO_BLK_T_WRITE_ZEROES;
34
+ req.data = (char *) &dwz_hdr;
35
+ dwz_hdr.sector = 0;
36
+ dwz_hdr.num_sectors = 1;
37
+ dwz_hdr.flags = 0;
38
+
54
+
39
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
55
+ .alloc_offset = host_cluster_offset,
56
+ .offset = start_of_cluster(s, guest_offset),
57
+ .nb_clusters = nb_clusters,
40
+
58
+
41
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
59
+ .keep_old_clusters = keep_old,
42
+
60
+
43
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
61
+ .cow_start = {
44
+ qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true);
62
+ .offset = cow_start_from,
45
+ qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
63
+ .nb_bytes = cow_start_to - cow_start_from,
64
+ },
65
+ .cow_end = {
66
+ .offset = cow_end_from,
67
+ .nb_bytes = cow_end_to - cow_end_from,
68
+ },
69
+ };
46
+
70
+
47
+ qvirtqueue_kick(dev, vq, free_head);
71
+ qemu_co_queue_init(&(*m)->dependent_requests);
72
+ QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
73
+}
48
+
74
+
49
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
75
/*
50
+ QVIRTIO_BLK_TIMEOUT_US);
76
* Returns the number of contiguous clusters that can be used for an allocating
51
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
77
* write, but require COW to be performed (this includes yet unallocated space,
52
+ g_assert_cmpint(status, ==, 0);
78
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
79
uint64_t requested_bytes = *bytes + offset_into_cluster(s, guest_offset);
80
int avail_bytes = nb_clusters << s->cluster_bits;
81
int nb_bytes = MIN(requested_bytes, avail_bytes);
82
- QCowL2Meta *old_m = *m;
83
-
84
- *m = g_malloc0(sizeof(**m));
85
-
86
- **m = (QCowL2Meta) {
87
- .next = old_m,
88
-
89
- .alloc_offset = alloc_cluster_offset,
90
- .offset = start_of_cluster(s, guest_offset),
91
- .nb_clusters = nb_clusters,
92
-
93
- .keep_old_clusters = keep_old_clusters,
94
-
95
- .cow_start = {
96
- .offset = 0,
97
- .nb_bytes = offset_into_cluster(s, guest_offset),
98
- },
99
- .cow_end = {
100
- .offset = nb_bytes,
101
- .nb_bytes = avail_bytes - nb_bytes,
102
- },
103
- };
104
- qemu_co_queue_init(&(*m)->dependent_requests);
105
- QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
106
107
*host_offset = alloc_cluster_offset + offset_into_cluster(s, guest_offset);
108
*bytes = MIN(*bytes, nb_bytes - offset_into_cluster(s, guest_offset));
109
assert(*bytes != 0);
110
111
+ calculate_l2_meta(bs, alloc_cluster_offset, guest_offset, *bytes,
112
+ m, keep_old_clusters);
53
+
113
+
54
+ guest_free(alloc, req_addr);
114
return 1;
55
+
115
56
+ /* Read request to check if the sector contains all zeroes */
116
fail:
57
+ req.type = VIRTIO_BLK_T_IN;
58
+ req.ioprio = 1;
59
+ req.sector = 0;
60
+ req.data = g_malloc0(512);
61
+
62
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
63
+
64
+ g_free(req.data);
65
+
66
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
67
+ qvirtqueue_add(vq, req_addr + 16, 512, true, true);
68
+ qvirtqueue_add(vq, req_addr + 528, 1, true, false);
69
+
70
+ qvirtqueue_kick(dev, vq, free_head);
71
+
72
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
73
+ QVIRTIO_BLK_TIMEOUT_US);
74
+ status = readb(req_addr + 528);
75
+ g_assert_cmpint(status, ==, 0);
76
+
77
+ data = g_malloc(512);
78
+ expected = g_malloc0(512);
79
+ memread(req_addr + 16, data, 512);
80
+ g_assert_cmpmem(data, 512, expected, 512);
81
+ g_free(expected);
82
+ g_free(data);
83
+
84
+ guest_free(alloc, req_addr);
85
+ }
86
+
87
if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
88
/* Write and read with 2 descriptor layout */
89
/* Write request */
90
--
117
--
91
2.20.1
118
2.26.2
92
119
93
120
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
We add acct_failed param in order to use virtio_blk_handle_rw_error()
3
We are going to need it in other places.
4
also when is not required to call block_acct_failed(). (eg. a discard
5
operation is failed)
6
4
7
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20190221103314.58500-2-sgarzare@redhat.com
8
Message-Id: <65e5d9627ca2ebe7e62deaeddf60949c33067d9d.1594396418.git.berto@igalia.com>
11
Message-Id: <20190221103314.58500-2-sgarzare@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
10
---
14
hw/block/virtio-blk.c | 10 ++++++----
11
block/qcow2-cluster.c | 34 +++++++++++++++++++---------------
15
1 file changed, 6 insertions(+), 4 deletions(-)
12
1 file changed, 19 insertions(+), 15 deletions(-)
16
13
17
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
14
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/virtio-blk.c
16
--- a/block/qcow2-cluster.c
20
+++ b/hw/block/virtio-blk.c
17
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
18
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
19
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
22
}
20
}
23
21
24
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
22
+/* Returns true if writing to a cluster requires COW */
25
- bool is_read)
23
+static bool cluster_needs_cow(BlockDriverState *bs, uint64_t l2_entry)
26
+ bool is_read, bool acct_failed)
24
+{
27
{
25
+ switch (qcow2_get_cluster_type(bs, l2_entry)) {
28
VirtIOBlock *s = req->dev;
26
+ case QCOW2_CLUSTER_NORMAL:
29
BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
27
+ if (l2_entry & QCOW_OFLAG_COPIED) {
30
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
28
+ return false;
31
s->rq = req;
32
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
33
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
34
- block_acct_failed(blk_get_stats(s->blk), &req->acct);
35
+ if (acct_failed) {
36
+ block_acct_failed(blk_get_stats(s->blk), &req->acct);
37
+ }
29
+ }
38
virtio_blk_free_request(req);
30
+ case QCOW2_CLUSTER_UNALLOCATED:
39
}
31
+ case QCOW2_CLUSTER_COMPRESSED:
40
32
+ case QCOW2_CLUSTER_ZERO_PLAIN:
41
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
33
+ case QCOW2_CLUSTER_ZERO_ALLOC:
42
* the memory until the request is completed (which will
34
+ return true;
43
* happen on the other side of the migration).
35
+ default:
44
*/
36
+ abort();
45
- if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
37
+ }
46
+ if (virtio_blk_handle_rw_error(req, -ret, is_read, true)) {
38
+}
47
continue;
39
+
48
}
40
/*
49
}
41
* Returns the number of contiguous clusters that can be used for an allocating
50
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_flush_complete(void *opaque, int ret)
42
* write, but require COW to be performed (this includes yet unallocated space,
51
43
@@ -XXX,XX +XXX,XX @@ static int count_cow_clusters(BlockDriverState *bs, int nb_clusters,
52
aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
44
53
if (ret) {
45
for (i = 0; i < nb_clusters; i++) {
54
- if (virtio_blk_handle_rw_error(req, -ret, 0)) {
46
uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
55
+ if (virtio_blk_handle_rw_error(req, -ret, 0, true)) {
47
- QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry);
56
goto out;
48
-
49
- switch(cluster_type) {
50
- case QCOW2_CLUSTER_NORMAL:
51
- if (l2_entry & QCOW_OFLAG_COPIED) {
52
- goto out;
53
- }
54
+ if (!cluster_needs_cow(bs, l2_entry)) {
55
break;
56
- case QCOW2_CLUSTER_UNALLOCATED:
57
- case QCOW2_CLUSTER_COMPRESSED:
58
- case QCOW2_CLUSTER_ZERO_PLAIN:
59
- case QCOW2_CLUSTER_ZERO_ALLOC:
60
- break;
61
- default:
62
- abort();
57
}
63
}
58
}
64
}
65
66
-out:
67
assert(i <= nb_clusters);
68
return i;
69
}
59
--
70
--
60
2.20.1
71
2.26.2
61
72
62
73
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
The size of data in the virtio_blk_request must be a multiple
3
When writing to a qcow2 file there are two functions that take a
4
of 512 bytes for IN and OUT requests, or a multiple of the size
4
virtual offset and return a host offset, possibly allocating new
5
of struct virtio_blk_discard_write_zeroes for DISCARD and
5
clusters if necessary:
6
WRITE_ZEROES requests.
6
7
7
- handle_copied() looks for normal data clusters that are already
8
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8
allocated and have a reference count of 1. In those clusters we
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
can simply write the data and there is no need to perform any
10
Reviewed-by: Thomas Huth <thuth@redhat.com>
10
copy-on-write.
11
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
11
12
Message-id: 20190221103314.58500-8-sgarzare@redhat.com
12
- handle_alloc() looks for clusters that do need copy-on-write,
13
Message-Id: <20190221103314.58500-8-sgarzare@redhat.com>
13
either because they haven't been allocated yet, because their
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
reference count is != 1 or because they are ZERO_ALLOC clusters.
15
16
The ZERO_ALLOC case is a bit special because those are clusters that
17
are already allocated and they could perfectly be dealt with in
18
handle_copied() (as long as copy-on-write is performed when required).
19
20
In fact, there is extra code specifically for them in handle_alloc()
21
that tries to reuse the existing allocation if possible and frees them
22
otherwise.
23
24
This patch changes the handling of ZERO_ALLOC clusters so the
25
semantics of these two functions are now like this:
26
27
- handle_copied() looks for clusters that are already allocated and
28
which we can overwrite (NORMAL and ZERO_ALLOC clusters with a
29
reference count of 1).
30
31
- handle_alloc() looks for clusters for which we need a new
32
allocation (all other cases).
33
34
One important difference after this change is that clusters found
35
in handle_copied() may now require copy-on-write, but this will be
36
necessary anyway once we add support for subclusters.
37
38
Signed-off-by: Alberto Garcia <berto@igalia.com>
39
Reviewed-by: Eric Blake <eblake@redhat.com>
40
Reviewed-by: Max Reitz <mreitz@redhat.com>
41
Message-Id: <eb17fc938f6be7be2e8d8ff42763d2c19241f866.1594396418.git.berto@igalia.com>
42
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
43
---
16
tests/virtio-blk-test.c | 15 ++++++++++++++-
44
block/qcow2-cluster.c | 252 +++++++++++++++++++++++-------------------
17
1 file changed, 14 insertions(+), 1 deletion(-)
45
1 file changed, 139 insertions(+), 113 deletions(-)
18
46
19
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
47
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/virtio-blk-test.c
49
--- a/block/qcow2-cluster.c
22
+++ b/tests/virtio-blk-test.c
50
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
51
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
24
uint64_t addr;
52
25
uint8_t status = 0xFF;
53
/*
26
54
* For a given write request, create a new QCowL2Meta structure, add
27
- g_assert_cmpuint(data_size % 512, ==, 0);
55
- * it to @m and the BDRVQcow2State.cluster_allocs list.
28
+ switch (req->type) {
56
+ * it to @m and the BDRVQcow2State.cluster_allocs list. If the write
29
+ case VIRTIO_BLK_T_IN:
57
+ * request does not need copy-on-write or changes to the L2 metadata
30
+ case VIRTIO_BLK_T_OUT:
58
+ * then this function does nothing.
31
+ g_assert_cmpuint(data_size % 512, ==, 0);
59
*
32
+ break;
60
* @host_cluster_offset points to the beginning of the first cluster.
33
+ case VIRTIO_BLK_T_DISCARD:
61
*
34
+ case VIRTIO_BLK_T_WRITE_ZEROES:
62
* @guest_offset and @bytes indicate the offset and length of the
35
+ g_assert_cmpuint(data_size %
63
* request.
36
+ sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
64
*
37
+ break;
65
+ * @l2_slice contains the L2 entries of all clusters involved in this
38
+ default:
66
+ * write request.
39
+ g_assert_cmpuint(data_size, ==, 0);
67
+ *
68
* If @keep_old is true it means that the clusters were already
69
* allocated and will be overwritten. If false then the clusters are
70
* new and we have to decrease the reference count of the old ones.
71
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
72
static void calculate_l2_meta(BlockDriverState *bs,
73
uint64_t host_cluster_offset,
74
uint64_t guest_offset, unsigned bytes,
75
- QCowL2Meta **m, bool keep_old)
76
+ uint64_t *l2_slice, QCowL2Meta **m, bool keep_old)
77
{
78
BDRVQcow2State *s = bs->opaque;
79
- unsigned cow_start_from = 0;
80
+ int l2_index = offset_to_l2_slice_index(s, guest_offset);
81
+ uint64_t l2_entry;
82
+ unsigned cow_start_from, cow_end_to;
83
unsigned cow_start_to = offset_into_cluster(s, guest_offset);
84
unsigned cow_end_from = cow_start_to + bytes;
85
- unsigned cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
86
unsigned nb_clusters = size_to_clusters(s, cow_end_from);
87
QCowL2Meta *old_m = *m;
88
+ QCow2ClusterType type;
89
+
90
+ assert(nb_clusters <= s->l2_slice_size - l2_index);
91
+
92
+ /* Return if there's no COW (all clusters are normal and we keep them) */
93
+ if (keep_old) {
94
+ int i;
95
+ for (i = 0; i < nb_clusters; i++) {
96
+ l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
97
+ if (qcow2_get_cluster_type(bs, l2_entry) != QCOW2_CLUSTER_NORMAL) {
98
+ break;
99
+ }
100
+ }
101
+ if (i == nb_clusters) {
102
+ return;
103
+ }
40
+ }
104
+ }
41
+
105
+
42
addr = guest_alloc(alloc, sizeof(*req) + data_size);
106
+ /* Get the L2 entry of the first cluster */
43
107
+ l2_entry = be64_to_cpu(l2_slice[l2_index]);
44
virtio_blk_fix_request(d, req);
108
+ type = qcow2_get_cluster_type(bs, l2_entry);
109
+
110
+ if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
111
+ cow_start_from = cow_start_to;
112
+ } else {
113
+ cow_start_from = 0;
114
+ }
115
+
116
+ /* Get the L2 entry of the last cluster */
117
+ l2_entry = be64_to_cpu(l2_slice[l2_index + nb_clusters - 1]);
118
+ type = qcow2_get_cluster_type(bs, l2_entry);
119
+
120
+ if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
121
+ cow_end_to = cow_end_from;
122
+ } else {
123
+ cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
124
+ }
125
126
*m = g_malloc0(sizeof(**m));
127
**m = (QCowL2Meta) {
128
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
129
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
130
}
131
132
-/* Returns true if writing to a cluster requires COW */
133
-static bool cluster_needs_cow(BlockDriverState *bs, uint64_t l2_entry)
134
+/*
135
+ * Returns true if writing to the cluster pointed to by @l2_entry
136
+ * requires a new allocation (that is, if the cluster is unallocated
137
+ * or has refcount > 1 and therefore cannot be written in-place).
138
+ */
139
+static bool cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
140
{
141
switch (qcow2_get_cluster_type(bs, l2_entry)) {
142
case QCOW2_CLUSTER_NORMAL:
143
+ case QCOW2_CLUSTER_ZERO_ALLOC:
144
if (l2_entry & QCOW_OFLAG_COPIED) {
145
return false;
146
}
147
case QCOW2_CLUSTER_UNALLOCATED:
148
case QCOW2_CLUSTER_COMPRESSED:
149
case QCOW2_CLUSTER_ZERO_PLAIN:
150
- case QCOW2_CLUSTER_ZERO_ALLOC:
151
return true;
152
default:
153
abort();
154
@@ -XXX,XX +XXX,XX @@ static bool cluster_needs_cow(BlockDriverState *bs, uint64_t l2_entry)
155
}
156
157
/*
158
- * Returns the number of contiguous clusters that can be used for an allocating
159
- * write, but require COW to be performed (this includes yet unallocated space,
160
- * which must copy from the backing file)
161
+ * Returns the number of contiguous clusters that can be written to
162
+ * using one single write request, starting from @l2_index.
163
+ * At most @nb_clusters are checked.
164
+ *
165
+ * If @new_alloc is true this counts clusters that are either
166
+ * unallocated, or allocated but with refcount > 1 (so they need to be
167
+ * newly allocated and COWed).
168
+ *
169
+ * If @new_alloc is false this counts clusters that are already
170
+ * allocated and can be overwritten in-place (this includes clusters
171
+ * of type QCOW2_CLUSTER_ZERO_ALLOC).
172
*/
173
-static int count_cow_clusters(BlockDriverState *bs, int nb_clusters,
174
- uint64_t *l2_slice, int l2_index)
175
+static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
176
+ uint64_t *l2_slice, int l2_index,
177
+ bool new_alloc)
178
{
179
+ BDRVQcow2State *s = bs->opaque;
180
+ uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index]);
181
+ uint64_t expected_offset = l2_entry & L2E_OFFSET_MASK;
182
int i;
183
184
for (i = 0; i < nb_clusters; i++) {
185
- uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
186
- if (!cluster_needs_cow(bs, l2_entry)) {
187
+ l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
188
+ if (cluster_needs_new_alloc(bs, l2_entry) != new_alloc) {
189
break;
190
}
191
+ if (!new_alloc) {
192
+ if (expected_offset != (l2_entry & L2E_OFFSET_MASK)) {
193
+ break;
194
+ }
195
+ expected_offset += s->cluster_size;
196
+ }
197
}
198
199
assert(i <= nb_clusters);
200
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
201
}
202
203
/*
204
- * Checks how many already allocated clusters that don't require a copy on
205
- * write there are at the given guest_offset (up to *bytes). If *host_offset is
206
- * not INV_OFFSET, only physically contiguous clusters beginning at this host
207
- * offset are counted.
208
+ * Checks how many already allocated clusters that don't require a new
209
+ * allocation there are at the given guest_offset (up to *bytes).
210
+ * If *host_offset is not INV_OFFSET, only physically contiguous clusters
211
+ * beginning at this host offset are counted.
212
*
213
* Note that guest_offset may not be cluster aligned. In this case, the
214
* returned *host_offset points to exact byte referenced by guest_offset and
215
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
216
* Returns:
217
* 0: if no allocated clusters are available at the given offset.
218
* *bytes is normally unchanged. It is set to 0 if the cluster
219
- * is allocated and doesn't need COW, but doesn't have the right
220
- * physical offset.
221
+ * is allocated and can be overwritten in-place but doesn't have
222
+ * the right physical offset.
223
*
224
- * 1: if allocated clusters that don't require a COW are available at
225
- * the requested offset. *bytes may have decreased and describes
226
- * the length of the area that can be written to.
227
+ * 1: if allocated clusters that can be overwritten in place are
228
+ * available at the requested offset. *bytes may have decreased
229
+ * and describes the length of the area that can be written to.
230
*
231
* -errno: in error cases
232
*/
233
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
234
{
235
BDRVQcow2State *s = bs->opaque;
236
int l2_index;
237
- uint64_t cluster_offset;
238
+ uint64_t l2_entry, cluster_offset;
239
uint64_t *l2_slice;
240
uint64_t nb_clusters;
241
unsigned int keep_clusters;
242
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
243
244
l2_index = offset_to_l2_slice_index(s, guest_offset);
245
nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
246
- assert(nb_clusters <= INT_MAX);
247
+ /* Limit total byte count to BDRV_REQUEST_MAX_BYTES */
248
+ nb_clusters = MIN(nb_clusters, BDRV_REQUEST_MAX_BYTES >> s->cluster_bits);
249
250
/* Find L2 entry for the first involved cluster */
251
ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
252
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
253
return ret;
254
}
255
256
- cluster_offset = be64_to_cpu(l2_slice[l2_index]);
257
-
258
- /* Check how many clusters are already allocated and don't need COW */
259
- if (qcow2_get_cluster_type(bs, cluster_offset) == QCOW2_CLUSTER_NORMAL
260
- && (cluster_offset & QCOW_OFLAG_COPIED))
261
- {
262
- /* If a specific host_offset is required, check it */
263
- bool offset_matches =
264
- (cluster_offset & L2E_OFFSET_MASK) == *host_offset;
265
-
266
- if (offset_into_cluster(s, cluster_offset & L2E_OFFSET_MASK)) {
267
- qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset "
268
- "%#llx unaligned (guest offset: %#" PRIx64
269
- ")", cluster_offset & L2E_OFFSET_MASK,
270
- guest_offset);
271
+ l2_entry = be64_to_cpu(l2_slice[l2_index]);
272
+ cluster_offset = l2_entry & L2E_OFFSET_MASK;
273
+
274
+ if (!cluster_needs_new_alloc(bs, l2_entry)) {
275
+ if (offset_into_cluster(s, cluster_offset)) {
276
+ qcow2_signal_corruption(bs, true, -1, -1, "%s cluster offset "
277
+ "%#" PRIx64 " unaligned (guest offset: %#"
278
+ PRIx64 ")", l2_entry & QCOW_OFLAG_ZERO ?
279
+ "Preallocated zero" : "Data",
280
+ cluster_offset, guest_offset);
281
ret = -EIO;
282
goto out;
283
}
284
285
- if (*host_offset != INV_OFFSET && !offset_matches) {
286
+ /* If a specific host_offset is required, check it */
287
+ if (*host_offset != INV_OFFSET && cluster_offset != *host_offset) {
288
*bytes = 0;
289
ret = 0;
290
goto out;
291
}
292
293
/* We keep all QCOW_OFLAG_COPIED clusters */
294
- keep_clusters =
295
- count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
296
- &l2_slice[l2_index],
297
- QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
298
+ keep_clusters = count_single_write_clusters(bs, nb_clusters, l2_slice,
299
+ l2_index, false);
300
assert(keep_clusters <= nb_clusters);
301
302
*bytes = MIN(*bytes,
303
keep_clusters * s->cluster_size
304
- offset_into_cluster(s, guest_offset));
305
+ assert(*bytes != 0);
306
+
307
+ calculate_l2_meta(bs, cluster_offset, guest_offset,
308
+ *bytes, l2_slice, m, true);
309
310
ret = 1;
311
} else {
312
@@ -XXX,XX +XXX,XX @@ out:
313
/* Only return a host offset if we actually made progress. Otherwise we
314
* would make requirements for handle_alloc() that it can't fulfill */
315
if (ret > 0) {
316
- *host_offset = (cluster_offset & L2E_OFFSET_MASK)
317
- + offset_into_cluster(s, guest_offset);
318
+ *host_offset = cluster_offset + offset_into_cluster(s, guest_offset);
319
}
320
321
return ret;
322
@@ -XXX,XX +XXX,XX @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
323
}
324
325
/*
326
- * Allocates new clusters for an area that either is yet unallocated or needs a
327
- * copy on write. If *host_offset is not INV_OFFSET, clusters are only
328
- * allocated if the new allocation can match the specified host offset.
329
+ * Allocates new clusters for an area that is either still unallocated or
330
+ * cannot be overwritten in-place. If *host_offset is not INV_OFFSET,
331
+ * clusters are only allocated if the new allocation can match the specified
332
+ * host offset.
333
*
334
* Note that guest_offset may not be cluster aligned. In this case, the
335
* returned *host_offset points to exact byte referenced by guest_offset and
336
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
337
BDRVQcow2State *s = bs->opaque;
338
int l2_index;
339
uint64_t *l2_slice;
340
- uint64_t entry;
341
uint64_t nb_clusters;
342
int ret;
343
- bool keep_old_clusters = false;
344
345
- uint64_t alloc_cluster_offset = INV_OFFSET;
346
+ uint64_t alloc_cluster_offset;
347
348
trace_qcow2_handle_alloc(qemu_coroutine_self(), guest_offset, *host_offset,
349
*bytes);
350
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
351
352
l2_index = offset_to_l2_slice_index(s, guest_offset);
353
nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
354
- assert(nb_clusters <= INT_MAX);
355
-
356
- /* Limit total allocation byte count to INT_MAX */
357
- nb_clusters = MIN(nb_clusters, INT_MAX >> s->cluster_bits);
358
+ /* Limit total allocation byte count to BDRV_REQUEST_MAX_BYTES */
359
+ nb_clusters = MIN(nb_clusters, BDRV_REQUEST_MAX_BYTES >> s->cluster_bits);
360
361
/* Find L2 entry for the first involved cluster */
362
ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
363
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
364
return ret;
365
}
366
367
- entry = be64_to_cpu(l2_slice[l2_index]);
368
- nb_clusters = count_cow_clusters(bs, nb_clusters, l2_slice, l2_index);
369
+ nb_clusters = count_single_write_clusters(bs, nb_clusters,
370
+ l2_slice, l2_index, true);
371
372
/* This function is only called when there were no non-COW clusters, so if
373
* we can't find any unallocated or COW clusters either, something is
374
* wrong with our code. */
375
assert(nb_clusters > 0);
376
377
- if (qcow2_get_cluster_type(bs, entry) == QCOW2_CLUSTER_ZERO_ALLOC &&
378
- (entry & QCOW_OFLAG_COPIED) &&
379
- (*host_offset == INV_OFFSET ||
380
- start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK)))
381
- {
382
- int preallocated_nb_clusters;
383
-
384
- if (offset_into_cluster(s, entry & L2E_OFFSET_MASK)) {
385
- qcow2_signal_corruption(bs, true, -1, -1, "Preallocated zero "
386
- "cluster offset %#llx unaligned (guest "
387
- "offset: %#" PRIx64 ")",
388
- entry & L2E_OFFSET_MASK, guest_offset);
389
- ret = -EIO;
390
- goto fail;
391
- }
392
-
393
- /* Try to reuse preallocated zero clusters; contiguous normal clusters
394
- * would be fine, too, but count_cow_clusters() above has limited
395
- * nb_clusters already to a range of COW clusters */
396
- preallocated_nb_clusters =
397
- count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
398
- &l2_slice[l2_index], QCOW_OFLAG_COPIED);
399
- assert(preallocated_nb_clusters > 0);
400
-
401
- nb_clusters = preallocated_nb_clusters;
402
- alloc_cluster_offset = entry & L2E_OFFSET_MASK;
403
-
404
- /* We want to reuse these clusters, so qcow2_alloc_cluster_link_l2()
405
- * should not free them. */
406
- keep_old_clusters = true;
407
+ /* Allocate at a given offset in the image file */
408
+ alloc_cluster_offset = *host_offset == INV_OFFSET ? INV_OFFSET :
409
+ start_of_cluster(s, *host_offset);
410
+ ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset,
411
+ &nb_clusters);
412
+ if (ret < 0) {
413
+ goto out;
414
}
415
416
- qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
417
-
418
- if (alloc_cluster_offset == INV_OFFSET) {
419
- /* Allocate, if necessary at a given offset in the image file */
420
- alloc_cluster_offset = *host_offset == INV_OFFSET ? INV_OFFSET :
421
- start_of_cluster(s, *host_offset);
422
- ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset,
423
- &nb_clusters);
424
- if (ret < 0) {
425
- goto fail;
426
- }
427
-
428
- /* Can't extend contiguous allocation */
429
- if (nb_clusters == 0) {
430
- *bytes = 0;
431
- return 0;
432
- }
433
-
434
- assert(alloc_cluster_offset != INV_OFFSET);
435
+ /* Can't extend contiguous allocation */
436
+ if (nb_clusters == 0) {
437
+ *bytes = 0;
438
+ ret = 0;
439
+ goto out;
440
}
441
442
+ assert(alloc_cluster_offset != INV_OFFSET);
443
+
444
/*
445
* Save info needed for meta data update.
446
*
447
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
448
*bytes = MIN(*bytes, nb_bytes - offset_into_cluster(s, guest_offset));
449
assert(*bytes != 0);
450
451
- calculate_l2_meta(bs, alloc_cluster_offset, guest_offset, *bytes,
452
- m, keep_old_clusters);
453
+ calculate_l2_meta(bs, alloc_cluster_offset, guest_offset, *bytes, l2_slice,
454
+ m, false);
455
456
- return 1;
457
+ ret = 1;
458
459
-fail:
460
- if (*m && (*m)->nb_clusters > 0) {
461
+out:
462
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
463
+ if (ret < 0 && *m && (*m)->nb_clusters > 0) {
464
QLIST_REMOVE(*m, next_in_flight);
465
}
466
return ret;
45
--
467
--
46
2.20.1
468
2.26.2
47
469
48
470
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
The size of an L2 entry is 64 bits, but if we want to have subclusters
4
we need extended L2 entries. This means that we have to access L2
5
tables and slices differently depending on whether an image has
6
extended L2 entries or not.
7
8
This patch replaces all l2_slice[] accesses with calls to
9
get_l2_entry() and set_l2_entry().
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
Message-Id: <9586363531fec125ba1386e561762d3e4224e9fc.1594396418.git.berto@igalia.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
block/qcow2.h | 12 ++++++++
19
block/qcow2-cluster.c | 63 ++++++++++++++++++++++--------------------
20
block/qcow2-refcount.c | 17 ++++++------
21
3 files changed, 54 insertions(+), 38 deletions(-)
22
23
diff --git a/block/qcow2.h b/block/qcow2.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/qcow2.h
26
+++ b/block/qcow2.h
27
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
28
29
#define INV_OFFSET (-1ULL)
30
31
+static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
32
+ int idx)
33
+{
34
+ return be64_to_cpu(l2_slice[idx]);
35
+}
36
+
37
+static inline void set_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
38
+ int idx, uint64_t entry)
39
+{
40
+ l2_slice[idx] = cpu_to_be64(entry);
41
+}
42
+
43
static inline bool has_data_file(BlockDriverState *bs)
44
{
45
BDRVQcow2State *s = bs->opaque;
46
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/qcow2-cluster.c
49
+++ b/block/qcow2-cluster.c
50
@@ -XXX,XX +XXX,XX @@ fail:
51
* cluster which may require a different handling)
52
*/
53
static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
54
- int cluster_size, uint64_t *l2_slice, uint64_t stop_flags)
55
+ int cluster_size, uint64_t *l2_slice, int l2_index, uint64_t stop_flags)
56
{
57
+ BDRVQcow2State *s = bs->opaque;
58
int i;
59
QCow2ClusterType first_cluster_type;
60
uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;
61
- uint64_t first_entry = be64_to_cpu(l2_slice[0]);
62
+ uint64_t first_entry = get_l2_entry(s, l2_slice, l2_index);
63
uint64_t offset = first_entry & mask;
64
65
first_cluster_type = qcow2_get_cluster_type(bs, first_entry);
66
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
67
first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
68
69
for (i = 0; i < nb_clusters; i++) {
70
- uint64_t l2_entry = be64_to_cpu(l2_slice[i]) & mask;
71
+ uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index + i) & mask;
72
if (offset + (uint64_t) i * cluster_size != l2_entry) {
73
break;
74
}
75
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
76
static int count_contiguous_clusters_unallocated(BlockDriverState *bs,
77
int nb_clusters,
78
uint64_t *l2_slice,
79
+ int l2_index,
80
QCow2ClusterType wanted_type)
81
{
82
+ BDRVQcow2State *s = bs->opaque;
83
int i;
84
85
assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||
86
wanted_type == QCOW2_CLUSTER_UNALLOCATED);
87
for (i = 0; i < nb_clusters; i++) {
88
- uint64_t entry = be64_to_cpu(l2_slice[i]);
89
+ uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
90
QCow2ClusterType type = qcow2_get_cluster_type(bs, entry);
91
92
if (type != wanted_type) {
93
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
94
/* find the cluster offset for the given disk offset */
95
96
l2_index = offset_to_l2_slice_index(s, offset);
97
- l2_entry = be64_to_cpu(l2_slice[l2_index]);
98
+ l2_entry = get_l2_entry(s, l2_slice, l2_index);
99
100
nb_clusters = size_to_clusters(s, bytes_needed);
101
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
102
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
103
case QCOW2_CLUSTER_UNALLOCATED:
104
/* how many empty clusters ? */
105
c = count_contiguous_clusters_unallocated(bs, nb_clusters,
106
- &l2_slice[l2_index], type);
107
+ l2_slice, l2_index, type);
108
break;
109
case QCOW2_CLUSTER_ZERO_ALLOC:
110
case QCOW2_CLUSTER_NORMAL: {
111
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
112
*host_offset = host_cluster_offset + offset_in_cluster;
113
/* how many allocated clusters ? */
114
c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
115
- &l2_slice[l2_index], QCOW_OFLAG_ZERO);
116
+ l2_slice, l2_index, QCOW_OFLAG_ZERO);
117
if (offset_into_cluster(s, host_cluster_offset)) {
118
qcow2_signal_corruption(bs, true, -1, -1,
119
"Cluster allocation offset %#"
120
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
121
122
/* Compression can't overwrite anything. Fail if the cluster was already
123
* allocated. */
124
- cluster_offset = be64_to_cpu(l2_slice[l2_index]);
125
+ cluster_offset = get_l2_entry(s, l2_slice, l2_index);
126
if (cluster_offset & L2E_OFFSET_MASK) {
127
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
128
return -EIO;
129
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
130
131
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
132
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
133
- l2_slice[l2_index] = cpu_to_be64(cluster_offset);
134
+ set_l2_entry(s, l2_slice, l2_index, cluster_offset);
135
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
136
137
*host_offset = cluster_offset & s->cluster_offset_mask;
138
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
139
* cluster the second one has to do RMW (which is done above by
140
* perform_cow()), update l2 table with its cluster pointer and free
141
* old cluster. This is what this loop does */
142
- if (l2_slice[l2_index + i] != 0) {
143
- old_cluster[j++] = l2_slice[l2_index + i];
144
+ if (get_l2_entry(s, l2_slice, l2_index + i) != 0) {
145
+ old_cluster[j++] = get_l2_entry(s, l2_slice, l2_index + i);
146
}
147
148
/* The offset must fit in the offset field of the L2 table entry */
149
assert((offset & L2E_OFFSET_MASK) == offset);
150
151
- l2_slice[l2_index + i] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
152
+ set_l2_entry(s, l2_slice, l2_index + i, offset | QCOW_OFLAG_COPIED);
153
}
154
155
156
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
157
*/
158
if (!m->keep_old_clusters && j != 0) {
159
for (i = 0; i < j; i++) {
160
- qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1,
161
- QCOW2_DISCARD_NEVER);
162
+ qcow2_free_any_clusters(bs, old_cluster[i], 1, QCOW2_DISCARD_NEVER);
163
}
164
}
165
166
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
167
if (keep_old) {
168
int i;
169
for (i = 0; i < nb_clusters; i++) {
170
- l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
171
+ l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
172
if (qcow2_get_cluster_type(bs, l2_entry) != QCOW2_CLUSTER_NORMAL) {
173
break;
174
}
175
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
176
}
177
178
/* Get the L2 entry of the first cluster */
179
- l2_entry = be64_to_cpu(l2_slice[l2_index]);
180
+ l2_entry = get_l2_entry(s, l2_slice, l2_index);
181
type = qcow2_get_cluster_type(bs, l2_entry);
182
183
if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
184
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
185
}
186
187
/* Get the L2 entry of the last cluster */
188
- l2_entry = be64_to_cpu(l2_slice[l2_index + nb_clusters - 1]);
189
+ l2_entry = get_l2_entry(s, l2_slice, l2_index + nb_clusters - 1);
190
type = qcow2_get_cluster_type(bs, l2_entry);
191
192
if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
193
@@ -XXX,XX +XXX,XX @@ static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
194
bool new_alloc)
195
{
196
BDRVQcow2State *s = bs->opaque;
197
- uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index]);
198
+ uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index);
199
uint64_t expected_offset = l2_entry & L2E_OFFSET_MASK;
200
int i;
201
202
for (i = 0; i < nb_clusters; i++) {
203
- l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
204
+ l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
205
if (cluster_needs_new_alloc(bs, l2_entry) != new_alloc) {
206
break;
207
}
208
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
209
return ret;
210
}
211
212
- l2_entry = be64_to_cpu(l2_slice[l2_index]);
213
+ l2_entry = get_l2_entry(s, l2_slice, l2_index);
214
cluster_offset = l2_entry & L2E_OFFSET_MASK;
215
216
if (!cluster_needs_new_alloc(bs, l2_entry)) {
217
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
218
for (i = 0; i < nb_clusters; i++) {
219
uint64_t old_l2_entry;
220
221
- old_l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
222
+ old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
223
224
/*
225
* If full_discard is false, make sure that a discarded area reads back
226
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
227
/* First remove L2 entries */
228
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
229
if (!full_discard && s->qcow_version >= 3) {
230
- l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
231
+ set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
232
} else {
233
- l2_slice[l2_index + i] = cpu_to_be64(0);
234
+ set_l2_entry(s, l2_slice, l2_index + i, 0);
235
}
236
237
/* Then decrease the refcount */
238
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
239
uint64_t old_offset;
240
QCow2ClusterType cluster_type;
241
242
- old_offset = be64_to_cpu(l2_slice[l2_index + i]);
243
+ old_offset = get_l2_entry(s, l2_slice, l2_index + i);
244
245
/*
246
* Minimize L2 changes if the cluster already reads back as
247
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
248
249
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
250
if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
251
- l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
252
+ set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
253
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
254
} else {
255
- l2_slice[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
256
+ uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
257
+ set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO);
258
}
259
}
260
261
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
262
}
263
264
for (j = 0; j < s->l2_slice_size; j++) {
265
- uint64_t l2_entry = be64_to_cpu(l2_slice[j]);
266
+ uint64_t l2_entry = get_l2_entry(s, l2_slice, j);
267
int64_t offset = l2_entry & L2E_OFFSET_MASK;
268
QCow2ClusterType cluster_type =
269
qcow2_get_cluster_type(bs, l2_entry);
270
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
271
if (!bs->backing) {
272
/* not backed; therefore we can simply deallocate the
273
* cluster */
274
- l2_slice[j] = 0;
275
+ set_l2_entry(s, l2_slice, j, 0);
276
l2_dirty = true;
277
continue;
278
}
279
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
280
}
281
282
if (l2_refcount == 1) {
283
- l2_slice[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
284
+ set_l2_entry(s, l2_slice, j, offset | QCOW_OFLAG_COPIED);
285
} else {
286
- l2_slice[j] = cpu_to_be64(offset);
287
+ set_l2_entry(s, l2_slice, j, offset);
288
}
289
l2_dirty = true;
290
}
291
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
292
index XXXXXXX..XXXXXXX 100644
293
--- a/block/qcow2-refcount.c
294
+++ b/block/qcow2-refcount.c
295
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
296
uint64_t cluster_index;
297
uint64_t offset;
298
299
- entry = be64_to_cpu(l2_slice[j]);
300
+ entry = get_l2_entry(s, l2_slice, j);
301
old_entry = entry;
302
entry &= ~QCOW_OFLAG_COPIED;
303
offset = entry & L2E_OFFSET_MASK;
304
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
305
qcow2_cache_set_dependency(bs, s->l2_table_cache,
306
s->refcount_block_cache);
307
}
308
- l2_slice[j] = cpu_to_be64(entry);
309
+ set_l2_entry(s, l2_slice, j, entry);
310
qcow2_cache_entry_mark_dirty(s->l2_table_cache,
311
l2_slice);
312
}
313
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
314
315
/* Do the actual checks */
316
for(i = 0; i < s->l2_size; i++) {
317
- l2_entry = be64_to_cpu(l2_table[i]);
318
+ l2_entry = get_l2_entry(s, l2_table, i);
319
320
switch (qcow2_get_cluster_type(bs, l2_entry)) {
321
case QCOW2_CLUSTER_COMPRESSED:
322
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
323
QCOW2_OL_INACTIVE_L2;
324
325
l2_entry = QCOW_OFLAG_ZERO;
326
- l2_table[i] = cpu_to_be64(l2_entry);
327
+ set_l2_entry(s, l2_table, i, l2_entry);
328
ret = qcow2_pre_write_overlap_check(bs, ign,
329
l2e_offset, sizeof(uint64_t), false);
330
if (ret < 0) {
331
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
332
}
333
334
for (j = 0; j < s->l2_size; j++) {
335
- uint64_t l2_entry = be64_to_cpu(l2_table[j]);
336
+ uint64_t l2_entry = get_l2_entry(s, l2_table, j);
337
uint64_t data_offset = l2_entry & L2E_OFFSET_MASK;
338
QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry);
339
340
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
341
"l2_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
342
repair ? "Repairing" : "ERROR", l2_entry, refcount);
343
if (repair) {
344
- l2_table[j] = cpu_to_be64(refcount == 1
345
- ? l2_entry | QCOW_OFLAG_COPIED
346
- : l2_entry & ~QCOW_OFLAG_COPIED);
347
+ set_l2_entry(s, l2_table, j,
348
+ refcount == 1 ?
349
+ l2_entry | QCOW_OFLAG_COPIED :
350
+ l2_entry & ~QCOW_OFLAG_COPIED);
351
l2_dirty++;
352
}
353
}
354
--
355
2.26.2
356
357
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Since configurable features for virtio-blk are growing, this patch
3
Subcluster allocation in qcow2 is implemented by extending the
4
adds host_features field in the struct VirtIOBlock. (as in virtio-net)
4
existing L2 table entries and adding additional information to
5
In this way, we can avoid to add new fields for new properties and
5
indicate the allocation status of each subcluster.
6
we can directly set VIRTIO_BLK_F* flags in the host_features.
7
6
8
We update "config-wce" and "scsi" property definition to use the new
7
This patch documents the changes to the qcow2 format and how they
9
host_features field without change the behaviour.
8
affect the calculation of the L2 cache size.
10
9
11
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
13
Message-Id: <5199f2e1c717bcaa58b48142c9062b803145ff7f.1594396418.git.berto@igalia.com>
15
Message-id: 20190221103314.58500-3-sgarzare@redhat.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Message-Id: <20190221103314.58500-3-sgarzare@redhat.com>
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
15
---
19
include/hw/virtio/virtio-blk.h | 3 +--
16
docs/interop/qcow2.txt | 68 ++++++++++++++++++++++++++++++++++++++++--
20
hw/block/virtio-blk.c | 16 +++++++++-------
17
docs/qcow2-cache.txt | 19 +++++++++++-
21
2 files changed, 10 insertions(+), 9 deletions(-)
18
2 files changed, 83 insertions(+), 4 deletions(-)
22
19
23
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
20
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
24
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/virtio/virtio-blk.h
22
--- a/docs/interop/qcow2.txt
26
+++ b/include/hw/virtio/virtio-blk.h
23
+++ b/docs/interop/qcow2.txt
27
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
24
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
28
BlockConf conf;
25
as the maximum cluster size and won't be able to open images
29
IOThread *iothread;
26
with larger cluster sizes.
30
char *serial;
27
31
- uint32_t scsi;
28
+ Note: if the image has Extended L2 Entries then cluster_bits
32
- uint32_t config_wce;
29
+ must be at least 14 (i.e. 16384 byte clusters).
33
uint32_t request_merging;
30
+
34
uint16_t num_queues;
31
24 - 31: size
35
uint16_t queue_size;
32
Virtual disk size in bytes.
36
@@ -XXX,XX +XXX,XX @@ typedef struct VirtIOBlock {
33
37
bool dataplane_disabled;
34
@@ -XXX,XX +XXX,XX @@ the next fields through header_length.
38
bool dataplane_started;
35
clusters. The compression_type field must be
39
struct VirtIOBlockDataPlane *dataplane;
36
present and not zero.
40
+ uint64_t host_features;
37
41
} VirtIOBlock;
38
- Bits 4-63: Reserved (set to 0)
42
39
+ Bit 4: Extended L2 Entries. If this bit is set then
43
typedef struct VirtIOBlockReq {
40
+ L2 table entries use an extended format that
44
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
41
+ allows subcluster-based allocation. See the
42
+ Extended L2 Entries section for more details.
43
+
44
+ Bits 5-63: Reserved (set to 0)
45
46
80 - 87: compatible_features
47
Bitmask of compatible features. An implementation can
48
@@ -XXX,XX +XXX,XX @@ cannot be relaxed without an incompatible layout change).
49
Given an offset into the virtual disk, the offset into the image file can be
50
obtained as follows:
51
52
- l2_entries = (cluster_size / sizeof(uint64_t))
53
+ l2_entries = (cluster_size / sizeof(uint64_t)) [*]
54
55
l2_index = (offset / cluster_size) % l2_entries
56
l1_index = (offset / cluster_size) / l2_entries
57
@@ -XXX,XX +XXX,XX @@ obtained as follows:
58
59
return cluster_offset + (offset % cluster_size)
60
61
+ [*] this changes if Extended L2 Entries are enabled, see next section
62
+
63
L1 table entry:
64
65
Bit 0 - 8: Reserved (set to 0)
66
@@ -XXX,XX +XXX,XX @@ Standard Cluster Descriptor:
67
nor is data read from the backing file if the cluster is
68
unallocated.
69
70
- With version 2, this is always 0.
71
+ With version 2 or with extended L2 entries (see the next
72
+ section), this is always 0.
73
74
1 - 8: Reserved (set to 0)
75
76
@@ -XXX,XX +XXX,XX @@ file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
77
no backing file or the backing file is smaller than the image, they shall read
78
zeros for all parts that are not covered by the backing file.
79
80
+== Extended L2 Entries ==
81
+
82
+An image uses Extended L2 Entries if bit 4 is set on the incompatible_features
83
+field of the header.
84
+
85
+In these images standard data clusters are divided into 32 subclusters of the
86
+same size. They are contiguous and start from the beginning of the cluster.
87
+Subclusters can be allocated independently and the L2 entry contains information
88
+indicating the status of each one of them. Compressed data clusters don't have
89
+subclusters so they are treated the same as in images without this feature.
90
+
91
+The size of an extended L2 entry is 128 bits so the number of entries per table
92
+is calculated using this formula:
93
+
94
+ l2_entries = (cluster_size / (2 * sizeof(uint64_t)))
95
+
96
+The first 64 bits have the same format as the standard L2 table entry described
97
+in the previous section, with the exception of bit 0 of the standard cluster
98
+descriptor.
99
+
100
+The last 64 bits contain a subcluster allocation bitmap with this format:
101
+
102
+Subcluster Allocation Bitmap (for standard clusters):
103
+
104
+ Bit 0 - 31: Allocation status (one bit per subcluster)
105
+
106
+ 1: the subcluster is allocated. In this case the
107
+ host cluster offset field must contain a valid
108
+ offset.
109
+ 0: the subcluster is not allocated. In this case
110
+ read requests shall go to the backing file or
111
+ return zeros if there is no backing file data.
112
+
113
+ Bits are assigned starting from the least significant
114
+ one (i.e. bit x is used for subcluster x).
115
+
116
+ 32 - 63 Subcluster reads as zeros (one bit per subcluster)
117
+
118
+ 1: the subcluster reads as zeros. In this case the
119
+ allocation status bit must be unset. The host
120
+ cluster offset field may or may not be set.
121
+ 0: no effect.
122
+
123
+ Bits are assigned starting from the least significant
124
+ one (i.e. bit x is used for subcluster x - 32).
125
+
126
+Subcluster Allocation Bitmap (for compressed clusters):
127
+
128
+ Bit 0 - 63: Reserved (set to 0)
129
+ Compressed clusters don't have subclusters,
130
+ so this field is not used.
131
132
== Snapshots ==
133
134
diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt
45
index XXXXXXX..XXXXXXX 100644
135
index XXXXXXX..XXXXXXX 100644
46
--- a/hw/block/virtio-blk.c
136
--- a/docs/qcow2-cache.txt
47
+++ b/hw/block/virtio-blk.c
137
+++ b/docs/qcow2-cache.txt
48
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
138
@@ -XXX,XX +XXX,XX @@
49
*/
139
qcow2 L2/refcount cache configuration
50
scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base;
140
=====================================
51
141
-Copyright (C) 2015, 2018 Igalia, S.L.
52
- if (!blk->conf.scsi) {
142
+Copyright (C) 2015, 2018-2020 Igalia, S.L.
53
+ if (!virtio_has_feature(blk->host_features, VIRTIO_BLK_F_SCSI)) {
143
Author: Alberto Garcia <berto@igalia.com>
54
status = VIRTIO_BLK_S_UNSUPP;
144
55
goto fail;
145
This work is licensed under the terms of the GNU GPL, version 2 or
56
}
146
@@ -XXX,XX +XXX,XX @@ support this functionality, and is 0 (disabled) on other platforms.
57
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
147
This functionality currently relies on the MADV_DONTNEED argument for
58
{
148
madvise() to actually free the memory. This is a Linux-specific feature,
59
VirtIOBlock *s = VIRTIO_BLK(vdev);
149
so cache-clean-interval is not supported on other systems.
60
61
+ /* Firstly sync all virtio-blk possible supported features */
62
+ features |= s->host_features;
63
+
150
+
64
virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX);
151
+
65
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
152
+Extended L2 Entries
66
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
153
+-------------------
67
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
154
+All numbers shown in this document are valid for qcow2 images with normal
68
if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
155
+64-bit L2 entries.
69
- if (s->conf.scsi) {
156
+
70
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_SCSI)) {
157
+Images with extended L2 entries need twice as much L2 metadata, so the L2
71
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
158
+cache size must be twice as large for the same disk space.
72
return 0;
159
+
73
}
160
+ disk_size = l2_cache_size * cluster_size / 16
74
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
161
+
75
virtio_add_feature(&features, VIRTIO_BLK_F_SCSI);
162
+i.e.
76
}
163
+
77
164
+ l2_cache_size = disk_size * 16 / cluster_size
78
- if (s->conf.config_wce) {
165
+
79
- virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
166
+Refcount blocks are not affected by this.
80
- }
81
if (blk_enable_write_cache(s->blk)) {
82
virtio_add_feature(&features, VIRTIO_BLK_F_WCE);
83
}
84
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
85
DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf),
86
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
87
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
88
- DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
89
+ DEFINE_PROP_BIT64("config-wce", VirtIOBlock, host_features,
90
+ VIRTIO_BLK_F_CONFIG_WCE, true),
91
#ifdef __linux__
92
- DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false),
93
+ DEFINE_PROP_BIT64("scsi", VirtIOBlock, host_features,
94
+ VIRTIO_BLK_F_SCSI, false),
95
#endif
96
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
97
true),
98
--
167
--
99
2.20.1
168
2.26.2
100
169
101
170
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
@iov is used only to initialize @qiov. Let's use new
3
This function will be used by the qcow2 code to check if an image has
4
qemu_iovec_init_buf() instead, which simplifies the code.
4
subclusters or not.
5
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
At the moment this simply returns false. Once all patches needed for
7
subcluster support are ready then QEMU will be able to create and
8
read images with subclusters and this function will return the actual
9
value.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-18-vsementsov@virtuozzo.com
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-Id: <20190218140926.333779-18-vsementsov@virtuozzo.com>
15
Message-Id: <905526221083581a1b7057bca1585487661c5c13.1594396418.git.berto@igalia.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
17
---
13
include/hw/ide/internal.h | 1 -
18
block/qcow2.h | 6 ++++++
14
hw/ide/atapi.c | 5 ++---
19
1 file changed, 6 insertions(+)
15
2 files changed, 2 insertions(+), 4 deletions(-)
16
20
17
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
21
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/ide/internal.h
23
--- a/block/qcow2.h
20
+++ b/include/hw/ide/internal.h
24
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ struct IDEDMAOps {
25
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
22
26
23
struct IDEDMA {
27
#define INV_OFFSET (-1ULL)
24
const struct IDEDMAOps *ops;
28
25
- struct iovec iov;
29
+static inline bool has_subclusters(BDRVQcow2State *s)
26
QEMUIOVector qiov;
30
+{
27
BlockAIOCB *aiocb;
31
+ /* FIXME: Return false until this feature is complete */
28
};
32
+ return false;
29
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
33
+}
30
index XXXXXXX..XXXXXXX 100644
34
+
31
--- a/hw/ide/atapi.c
35
static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
32
+++ b/hw/ide/atapi.c
36
int idx)
33
@@ -XXX,XX +XXX,XX @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
37
{
34
data_offset = 0;
35
}
36
trace_ide_atapi_cmd_read_dma_cb_aio(s, s->lba, n);
37
- s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
38
- s->bus->dma->iov.iov_len = n * ATAPI_SECTOR_SIZE;
39
- qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
40
+ qemu_iovec_init_buf(&s->bus->dma->qiov, s->io_buffer + data_offset,
41
+ n * ATAPI_SECTOR_SIZE);
42
43
s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2,
44
&s->bus->dma->qiov, n * 4,
45
--
38
--
46
2.20.1
39
2.26.2
47
40
48
41
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
If the DISCARD feature is enabled, we try this command in the
3
This patch adds the following new fields to BDRVQcow2State:
4
test_basic(), checking only the status returned by the request.
5
4
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
- subclusters_per_cluster: Number of subclusters in a cluster
7
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
6
- subcluster_size: The size of each subcluster, in bytes
8
Message-id: 20190221103314.58500-11-sgarzare@redhat.com
7
- subcluster_bits: No. of bits so 1 << subcluster_bits = subcluster_size
9
Message-Id: <20190221103314.58500-11-sgarzare@redhat.com>
8
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Images without subclusters are treated as if they had exactly one
10
subcluster per cluster (i.e. subcluster_size = cluster_size).
11
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
Message-Id: <55bfeac86b092fa2c9d182a95cbeb479ff7eca4f.1594396418.git.berto@igalia.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
17
---
12
tests/virtio-blk-test.c | 27 +++++++++++++++++++++++++++
18
block/qcow2.h | 5 +++++
13
1 file changed, 27 insertions(+)
19
block/qcow2.c | 5 +++++
20
2 files changed, 10 insertions(+)
14
21
15
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
22
diff --git a/block/qcow2.h b/block/qcow2.h
16
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/virtio-blk-test.c
24
--- a/block/qcow2.h
18
+++ b/tests/virtio-blk-test.c
25
+++ b/block/qcow2.h
19
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
26
@@ -XXX,XX +XXX,XX @@
20
guest_free(alloc, req_addr);
27
/* The cluster reads as all zeros */
28
#define QCOW_OFLAG_ZERO (1ULL << 0)
29
30
+#define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32
31
+
32
#define MIN_CLUSTER_BITS 9
33
#define MAX_CLUSTER_BITS 21
34
35
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
36
int cluster_bits;
37
int cluster_size;
38
int l2_slice_size;
39
+ int subcluster_bits;
40
+ int subcluster_size;
41
+ int subclusters_per_cluster;
42
int l2_bits;
43
int l2_size;
44
int l1_size;
45
diff --git a/block/qcow2.c b/block/qcow2.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/qcow2.c
48
+++ b/block/qcow2.c
49
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
50
}
21
}
51
}
22
52
23
+ if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
53
+ s->subclusters_per_cluster =
24
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
54
+ has_subclusters(s) ? QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER : 1;
55
+ s->subcluster_size = s->cluster_size / s->subclusters_per_cluster;
56
+ s->subcluster_bits = ctz32(s->subcluster_size);
25
+
57
+
26
+ req.type = VIRTIO_BLK_T_DISCARD;
58
/* Check support for various header values */
27
+ req.data = (char *) &dwz_hdr;
59
if (header.refcount_order > 6) {
28
+ dwz_hdr.sector = 0;
60
error_setg(errp, "Reference count entry width too large; may not "
29
+ dwz_hdr.num_sectors = 1;
30
+ dwz_hdr.flags = 0;
31
+
32
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
33
+
34
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
35
+
36
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
37
+ qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true);
38
+ qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
39
+
40
+ qvirtqueue_kick(dev, vq, free_head);
41
+
42
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
43
+ QVIRTIO_BLK_TIMEOUT_US);
44
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
45
+ g_assert_cmpint(status, ==, 0);
46
+
47
+ guest_free(alloc, req_addr);
48
+ }
49
+
50
if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
51
/* Write and read with 2 descriptor layout */
52
/* Write request */
53
--
61
--
54
2.20.1
62
2.26.2
55
63
56
64
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
@iov is used only to initialize @qiov. Let's use new
3
For a given offset, return the subcluster number within its cluster
4
qemu_iovec_init_buf() instead, which simplifies the code.
4
(i.e. with 32 subclusters per cluster it returns a number between 0
5
and 31).
5
6
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Message-id: 20190218140926.333779-17-vsementsov@virtuozzo.com
10
Message-Id: <56e3e4ac0d827c6a2f5f259106c5ddb7c4ca2653.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-17-vsementsov@virtuozzo.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
12
---
13
include/hw/ide/internal.h | 1 -
13
block/qcow2.h | 5 +++++
14
hw/ide/core.c | 11 ++++++-----
14
1 file changed, 5 insertions(+)
15
2 files changed, 6 insertions(+), 6 deletions(-)
16
15
17
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
16
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/ide/internal.h
18
--- a/block/qcow2.h
20
+++ b/include/hw/ide/internal.h
19
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ extern const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT];
20
@@ -XXX,XX +XXX,XX @@ static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
22
21
return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
23
typedef struct IDEBufferedRequest {
24
QLIST_ENTRY(IDEBufferedRequest) list;
25
- struct iovec iov;
26
QEMUIOVector qiov;
27
QEMUIOVector *original_qiov;
28
BlockCompletionFunc *original_cb;
29
diff --git a/hw/ide/core.c b/hw/ide/core.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/hw/ide/core.c
32
+++ b/hw/ide/core.c
33
@@ -XXX,XX +XXX,XX @@ static void ide_buffered_readv_cb(void *opaque, int ret)
34
IDEBufferedRequest *req = opaque;
35
if (!req->orphaned) {
36
if (!ret) {
37
- qemu_iovec_from_buf(req->original_qiov, 0, req->iov.iov_base,
38
+ assert(req->qiov.size == req->original_qiov->size);
39
+ qemu_iovec_from_buf(req->original_qiov, 0,
40
+ req->qiov.local_iov.iov_base,
41
req->original_qiov->size);
42
}
43
req->original_cb(req->original_opaque, ret);
44
}
45
QLIST_REMOVE(req, list);
46
- qemu_vfree(req->iov.iov_base);
47
+ qemu_vfree(qemu_iovec_buf(&req->qiov));
48
g_free(req);
49
}
22
}
50
23
51
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
24
+static inline int offset_to_sc_index(BDRVQcow2State *s, int64_t offset)
52
req->original_qiov = iov;
25
+{
53
req->original_cb = cb;
26
+ return (offset >> s->subcluster_bits) & (s->subclusters_per_cluster - 1);
54
req->original_opaque = opaque;
27
+}
55
- req->iov.iov_base = qemu_blockalign(blk_bs(s->blk), iov->size);
28
+
56
- req->iov.iov_len = iov->size;
29
static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
57
- qemu_iovec_init_external(&req->qiov, &req->iov, 1);
30
{
58
+ qemu_iovec_init_buf(&req->qiov, blk_blockalign(s->blk, iov->size),
31
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
59
+ iov->size);
60
61
aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS,
62
&req->qiov, 0, ide_buffered_readv_cb, req);
63
--
32
--
64
2.20.1
33
2.26.2
65
34
66
35
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new QEMU_IOVEC_INIT_BUF() instead of
3
Like offset_into_cluster() and size_to_clusters(), but for
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
subclusters.
5
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-15-vsementsov@virtuozzo.com
9
Message-Id: <3cc2390dcdef3d234d47c741b708bd8734490862.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-15-vsementsov@virtuozzo.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
11
---
13
tests/test-bdrv-drain.c | 29 ++++-------------------------
12
block/qcow2.h | 10 ++++++++++
14
1 file changed, 4 insertions(+), 25 deletions(-)
13
1 file changed, 10 insertions(+)
15
14
16
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
15
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/test-bdrv-drain.c
17
--- a/block/qcow2.h
19
+++ b/tests/test-bdrv-drain.c
18
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
19
@@ -XXX,XX +XXX,XX @@ static inline int64_t offset_into_cluster(BDRVQcow2State *s, int64_t offset)
21
BlockAIOCB *acb;
20
return offset & (s->cluster_size - 1);
22
int aio_ret;
21
}
23
22
24
- QEMUIOVector qiov;
23
+static inline int64_t offset_into_subcluster(BDRVQcow2State *s, int64_t offset)
25
- struct iovec iov = {
24
+{
26
- .iov_base = NULL,
25
+ return offset & (s->subcluster_size - 1);
27
- .iov_len = 0,
26
+}
28
- };
27
+
29
- qemu_iovec_init_external(&qiov, &iov, 1);
28
static inline uint64_t size_to_clusters(BDRVQcow2State *s, uint64_t size)
30
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
29
{
31
30
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
32
blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
31
}
33
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
32
34
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
33
+static inline uint64_t size_to_subclusters(BDRVQcow2State *s, uint64_t size)
35
AioContext *ctx_a = iothread_get_aio_context(a);
34
+{
36
AioContext *ctx_b = iothread_get_aio_context(b);
35
+ return (size + (s->subcluster_size - 1)) >> s->subcluster_bits;
37
36
+}
38
- QEMUIOVector qiov;
37
+
39
- struct iovec iov = {
38
static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
40
- .iov_base = NULL,
39
{
41
- .iov_len = 0,
40
int shift = s->cluster_bits + s->l2_bits;
42
- };
43
- qemu_iovec_init_external(&qiov, &iov, 1);
44
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
45
46
/* bdrv_drain_all() may only be called from the main loop thread */
47
if (drain_type == BDRV_DRAIN_ALL && drain_thread != 0) {
48
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
49
BlockDriverState *bs = blk_bs(blk);
50
BDRVTestTopState *tts = bs->opaque;
51
void *buffer = g_malloc(65536);
52
- QEMUIOVector qiov;
53
- struct iovec iov = {
54
- .iov_base = buffer,
55
- .iov_len = 65536,
56
- };
57
-
58
- qemu_iovec_init_external(&qiov, &iov, 1);
59
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buffer, 65536);
60
61
/* Pretend some internal write operation from parent to child.
62
* Important: We have to read from the child, not from the parent!
63
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
64
BdrvChild *child_a, *child_b;
65
BlockAIOCB *acb;
66
67
- QEMUIOVector qiov;
68
- struct iovec iov = {
69
- .iov_base = NULL,
70
- .iov_len = 0,
71
- };
72
- qemu_iovec_init_external(&qiov, &iov, 1);
73
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
74
75
if (!by_parent_cb) {
76
detach_by_driver_cb_role = child_file;
77
--
41
--
78
2.20.1
42
2.26.2
79
43
80
44
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
qcow2 images with subclusters have 128-bit L2 entries. The first 64
4
bits contain the same information as traditional images and the last
5
64 bits form a bitmap with the status of each individual subcluster.
6
7
Because of that we cannot assume that L2 entries are sizeof(uint64_t)
8
anymore. This function returns the proper value for the image.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <d34d578bd0380e739e2dde3e8dd6187d3d249fa9.1594396418.git.berto@igalia.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/qcow2.h | 9 +++++++++
16
block/qcow2-cluster.c | 12 ++++++------
17
block/qcow2-refcount.c | 14 ++++++++------
18
block/qcow2.c | 8 ++++----
19
4 files changed, 27 insertions(+), 16 deletions(-)
20
21
diff --git a/block/qcow2.h b/block/qcow2.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2.h
24
+++ b/block/qcow2.h
25
@@ -XXX,XX +XXX,XX @@
26
27
#define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32
28
29
+/* Size of normal and extended L2 entries */
30
+#define L2E_SIZE_NORMAL (sizeof(uint64_t))
31
+#define L2E_SIZE_EXTENDED (sizeof(uint64_t) * 2)
32
+
33
#define MIN_CLUSTER_BITS 9
34
#define MAX_CLUSTER_BITS 21
35
36
@@ -XXX,XX +XXX,XX @@ static inline bool has_subclusters(BDRVQcow2State *s)
37
return false;
38
}
39
40
+static inline size_t l2_entry_size(BDRVQcow2State *s)
41
+{
42
+ return has_subclusters(s) ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
43
+}
44
+
45
static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
46
int idx)
47
{
48
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/qcow2-cluster.c
51
+++ b/block/qcow2-cluster.c
52
@@ -XXX,XX +XXX,XX @@ static int l2_load(BlockDriverState *bs, uint64_t offset,
53
uint64_t l2_offset, uint64_t **l2_slice)
54
{
55
BDRVQcow2State *s = bs->opaque;
56
- int start_of_slice = sizeof(uint64_t) *
57
+ int start_of_slice = l2_entry_size(s) *
58
(offset_to_l2_index(s, offset) - offset_to_l2_slice_index(s, offset));
59
60
return qcow2_cache_get(bs, s->l2_table_cache, l2_offset + start_of_slice,
61
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index)
62
63
/* allocate a new l2 entry */
64
65
- l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
66
+ l2_offset = qcow2_alloc_clusters(bs, s->l2_size * l2_entry_size(s));
67
if (l2_offset < 0) {
68
ret = l2_offset;
69
goto fail;
70
@@ -XXX,XX +XXX,XX @@ static int l2_allocate(BlockDriverState *bs, int l1_index)
71
72
/* allocate a new entry in the l2 cache */
73
74
- slice_size2 = s->l2_slice_size * sizeof(uint64_t);
75
+ slice_size2 = s->l2_slice_size * l2_entry_size(s);
76
n_slices = s->cluster_size / slice_size2;
77
78
trace_qcow2_l2_allocate_get_empty(bs, l1_index);
79
@@ -XXX,XX +XXX,XX @@ fail:
80
}
81
s->l1_table[l1_index] = old_l2_offset;
82
if (l2_offset > 0) {
83
- qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
84
+ qcow2_free_clusters(bs, l2_offset, s->l2_size * l2_entry_size(s),
85
QCOW2_DISCARD_ALWAYS);
86
}
87
return ret;
88
@@ -XXX,XX +XXX,XX @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
89
90
/* Then decrease the refcount of the old table */
91
if (l2_offset) {
92
- qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
93
+ qcow2_free_clusters(bs, l2_offset, s->l2_size * l2_entry_size(s),
94
QCOW2_DISCARD_OTHER);
95
}
96
97
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
98
int ret;
99
int i, j;
100
101
- slice_size2 = s->l2_slice_size * sizeof(uint64_t);
102
+ slice_size2 = s->l2_slice_size * l2_entry_size(s);
103
n_slices = s->cluster_size / slice_size2;
104
105
if (!is_active_l1) {
106
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/qcow2-refcount.c
109
+++ b/block/qcow2-refcount.c
110
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
111
l2_slice = NULL;
112
l1_table = NULL;
113
l1_size2 = l1_size * sizeof(uint64_t);
114
- slice_size2 = s->l2_slice_size * sizeof(uint64_t);
115
+ slice_size2 = s->l2_slice_size * l2_entry_size(s);
116
n_slices = s->cluster_size / slice_size2;
117
118
s->cache_discards = true;
119
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
120
int i, l2_size, nb_csectors, ret;
121
122
/* Read L2 table from disk */
123
- l2_size = s->l2_size * sizeof(uint64_t);
124
+ l2_size = s->l2_size * l2_entry_size(s);
125
l2_table = g_malloc(l2_size);
126
127
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
128
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
129
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
130
offset);
131
if (fix & BDRV_FIX_ERRORS) {
132
+ int idx = i * (l2_entry_size(s) / sizeof(uint64_t));
133
uint64_t l2e_offset =
134
- l2_offset + (uint64_t)i * sizeof(uint64_t);
135
+ l2_offset + (uint64_t)i * l2_entry_size(s);
136
int ign = active ? QCOW2_OL_ACTIVE_L2 :
137
QCOW2_OL_INACTIVE_L2;
138
139
l2_entry = QCOW_OFLAG_ZERO;
140
set_l2_entry(s, l2_table, i, l2_entry);
141
ret = qcow2_pre_write_overlap_check(bs, ign,
142
- l2e_offset, sizeof(uint64_t), false);
143
+ l2e_offset, l2_entry_size(s), false);
144
if (ret < 0) {
145
fprintf(stderr, "ERROR: Overlap check failed\n");
146
res->check_errors++;
147
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
148
}
149
150
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
151
- &l2_table[i], sizeof(uint64_t));
152
+ &l2_table[idx],
153
+ l2_entry_size(s));
154
if (ret < 0) {
155
fprintf(stderr, "ERROR: Failed to overwrite L2 "
156
"table entry: %s\n", strerror(-ret));
157
@@ -XXX,XX +XXX,XX @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
158
}
159
160
ret = bdrv_pread(bs->file, l2_offset, l2_table,
161
- s->l2_size * sizeof(uint64_t));
162
+ s->l2_size * l2_entry_size(s));
163
if (ret < 0) {
164
fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
165
strerror(-ret));
166
diff --git a/block/qcow2.c b/block/qcow2.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/block/qcow2.c
169
+++ b/block/qcow2.c
170
@@ -XXX,XX +XXX,XX @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
171
uint64_t max_l2_entries = DIV_ROUND_UP(virtual_disk_size, s->cluster_size);
172
/* An L2 table is always one cluster in size so the max cache size
173
* should be a multiple of the cluster size. */
174
- uint64_t max_l2_cache = ROUND_UP(max_l2_entries * sizeof(uint64_t),
175
+ uint64_t max_l2_cache = ROUND_UP(max_l2_entries * l2_entry_size(s),
176
s->cluster_size);
177
178
combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
179
@@ -XXX,XX +XXX,XX @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
180
}
181
}
182
183
- r->l2_slice_size = l2_cache_entry_size / sizeof(uint64_t);
184
+ r->l2_slice_size = l2_cache_entry_size / l2_entry_size(s);
185
r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size,
186
l2_cache_entry_size);
187
r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size,
188
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
189
bs->encrypted = true;
190
}
191
192
- s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
193
+ s->l2_bits = s->cluster_bits - ctz32(l2_entry_size(s));
194
s->l2_size = 1 << s->l2_bits;
195
/* 2^(s->refcount_order - 3) is the refcount width in bytes */
196
s->refcount_block_bits = s->cluster_bits - (s->refcount_order - 3);
197
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
198
* preallocation. All that matters is that we will not have to allocate
199
* new refcount structures for them.) */
200
nb_new_l2_tables = DIV_ROUND_UP(nb_new_data_clusters,
201
- s->cluster_size / sizeof(uint64_t));
202
+ s->cluster_size / l2_entry_size(s));
203
/* The cluster range may not be aligned to L2 boundaries, so add one L2
204
* table for a potential head/tail */
205
nb_new_l2_tables++;
206
--
207
2.26.2
208
209
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
Extended L2 entries are 128-bit wide: 64 bits for the entry itself and
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
64 bits for the subcluster allocation bitmap.
5
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
In order to support them correctly get/set_l2_entry() need to be
7
updated so they take the entry width into account in order to
8
calculate the correct offset.
9
10
This patch also adds the get/set_l2_bitmap() functions that are
11
used to access the bitmaps. For convenience we allow calling
12
get_l2_bitmap() on images without subclusters. In this case the
13
returned value is always 0 and has no meaning.
14
15
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-14-vsementsov@virtuozzo.com
18
Message-Id: <6ee0f81ae3329c991de125618b3675e1e46acdbb.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-14-vsementsov@virtuozzo.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
20
---
13
migration/block.c | 10 +++-------
21
block/qcow2.h | 21 +++++++++++++++++++++
14
1 file changed, 3 insertions(+), 7 deletions(-)
22
1 file changed, 21 insertions(+)
15
23
16
diff --git a/migration/block.c b/migration/block.c
24
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
18
--- a/migration/block.c
26
--- a/block/qcow2.h
19
+++ b/migration/block.c
27
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ typedef struct BlkMigBlock {
28
@@ -XXX,XX +XXX,XX @@ static inline size_t l2_entry_size(BDRVQcow2State *s)
21
BlkMigDevState *bmds;
29
static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
22
int64_t sector;
30
int idx)
23
int nr_sectors;
31
{
24
- struct iovec iov;
32
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
25
QEMUIOVector qiov;
33
return be64_to_cpu(l2_slice[idx]);
26
BlockAIOCB *aiocb;
34
}
27
35
28
@@ -XXX,XX +XXX,XX @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
36
+static inline uint64_t get_l2_bitmap(BDRVQcow2State *s, uint64_t *l2_slice,
29
blk->sector = cur_sector;
37
+ int idx)
30
blk->nr_sectors = nr_sectors;
38
+{
31
39
+ if (has_subclusters(s)) {
32
- blk->iov.iov_base = blk->buf;
40
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
33
- blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
41
+ return be64_to_cpu(l2_slice[idx + 1]);
34
- qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
42
+ } else {
35
+ qemu_iovec_init_buf(&blk->qiov, blk->buf, nr_sectors * BDRV_SECTOR_SIZE);
43
+ return 0; /* For convenience only; this value has no meaning. */
36
44
+ }
37
blk_mig_lock();
45
+}
38
block_mig_state.submitted++;
46
+
39
@@ -XXX,XX +XXX,XX @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
47
static inline void set_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
40
blk->nr_sectors = nr_sectors;
48
int idx, uint64_t entry)
41
49
{
42
if (is_async) {
50
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
43
- blk->iov.iov_base = blk->buf;
51
l2_slice[idx] = cpu_to_be64(entry);
44
- blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
52
}
45
- qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
53
46
+ qemu_iovec_init_buf(&blk->qiov, blk->buf,
54
+static inline void set_l2_bitmap(BDRVQcow2State *s, uint64_t *l2_slice,
47
+ nr_sectors * BDRV_SECTOR_SIZE);
55
+ int idx, uint64_t bitmap)
48
56
+{
49
blk->aiocb = blk_aio_preadv(bmds->blk,
57
+ assert(has_subclusters(s));
50
sector * BDRV_SECTOR_SIZE,
58
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
59
+ l2_slice[idx + 1] = cpu_to_be64(bitmap);
60
+}
61
+
62
static inline bool has_data_file(BlockDriverState *bs)
63
{
64
BDRVQcow2State *s = bs->opaque;
51
--
65
--
52
2.20.1
66
2.26.2
53
67
54
68
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Add a possibility of embedded iovec, for cases when we need only one
3
This patch adds QCow2SubclusterType, which is the subcluster-level
4
local iov.
4
version of QCow2ClusterType. All QCOW2_SUBCLUSTER_* values have the
5
5
the same meaning as their QCOW2_CLUSTER_* equivalents (when they
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
exist). See below for details and caveats.
7
8
In images without extended L2 entries clusters are treated as having
9
exactly one subcluster so it is possible to replace one data type with
10
the other while keeping the exact same semantics.
11
12
With extended L2 entries there are new possible values, and every
13
subcluster in the same cluster can obviously have a different
14
QCow2SubclusterType so functions need to be adapted to work on the
15
subcluster level.
16
17
There are several things that have to be taken into account:
18
19
a) QCOW2_SUBCLUSTER_COMPRESSED means that the whole cluster is
20
compressed. We do not support compression at the subcluster
21
level.
22
23
b) There are two different values for unallocated subclusters:
24
QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN which means that the whole
25
cluster is unallocated, and QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC
26
which means that the cluster is allocated but the subcluster is
27
not. The latter can only happen in images with extended L2
28
entries.
29
30
c) QCOW2_SUBCLUSTER_INVALID is used to detect the cases where an L2
31
entry has a value that violates the specification. The caller is
32
responsible for handling these situations.
33
34
To prevent compatibility problems with images that have invalid
35
values but are currently being read by QEMU without causing side
36
effects, QCOW2_SUBCLUSTER_INVALID is only returned for images
37
with extended L2 entries.
38
39
qcow2_cluster_to_subcluster_type() is added as a separate function
40
from qcow2_get_subcluster_type(), but this is only temporary and both
41
will be merged in a subsequent patch.
42
43
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
44
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Message-id: 20190218140926.333779-2-vsementsov@virtuozzo.com
45
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20190218140926.333779-2-vsementsov@virtuozzo.com>
46
Message-Id: <26ef38e270f25851c98b51278852b4c4a7f97e69.1594396418.git.berto@igalia.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
47
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
48
---
12
include/qemu/iov.h | 64 ++++++++++++++++++++++++++++++++++++++++++++--
49
block/qcow2.h | 126 +++++++++++++++++++++++++++++++++++++++++++++++++-
13
1 file changed, 62 insertions(+), 2 deletions(-)
50
1 file changed, 125 insertions(+), 1 deletion(-)
14
51
15
diff --git a/include/qemu/iov.h b/include/qemu/iov.h
52
diff --git a/block/qcow2.h b/block/qcow2.h
16
index XXXXXXX..XXXXXXX 100644
53
index XXXXXXX..XXXXXXX 100644
17
--- a/include/qemu/iov.h
54
--- a/block/qcow2.h
18
+++ b/include/qemu/iov.h
55
+++ b/block/qcow2.h
19
@@ -XXX,XX +XXX,XX @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt,
56
@@ -XXX,XX +XXX,XX @@
20
typedef struct QEMUIOVector {
57
21
struct iovec *iov;
58
#define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32
22
int niov;
59
23
- int nalloc;
60
+/* The subcluster X [0..31] is allocated */
24
- size_t size;
61
+#define QCOW_OFLAG_SUB_ALLOC(X) (1ULL << (X))
25
+
62
+/* The subcluster X [0..31] reads as zeroes */
26
+ /*
63
+#define QCOW_OFLAG_SUB_ZERO(X) (QCOW_OFLAG_SUB_ALLOC(X) << 32)
27
+ * For external @iov (qemu_iovec_init_external()) or allocated @iov
64
+/* Subclusters [X, Y) (0 <= X <= Y <= 32) are allocated */
28
+ * (qemu_iovec_init()), @size is the cumulative size of iovecs and
65
+#define QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) \
29
+ * @local_iov is invalid and unused.
66
+ (QCOW_OFLAG_SUB_ALLOC(Y) - QCOW_OFLAG_SUB_ALLOC(X))
30
+ *
67
+/* Subclusters [X, Y) (0 <= X <= Y <= 32) read as zeroes */
31
+ * For embedded @iov (QEMU_IOVEC_INIT_BUF() or qemu_iovec_init_buf()),
68
+#define QCOW_OFLAG_SUB_ZERO_RANGE(X, Y) \
32
+ * @iov is equal to &@local_iov, and @size is valid, as it has same
69
+ (QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) << 32)
33
+ * offset and type as @local_iov.iov_len, which is guaranteed by
70
+/* L2 entry bitmap with all allocation bits set */
34
+ * static assertion below.
71
+#define QCOW_L2_BITMAP_ALL_ALLOC (QCOW_OFLAG_SUB_ALLOC_RANGE(0, 32))
35
+ *
72
+/* L2 entry bitmap with all "read as zeroes" bits set */
36
+ * @nalloc is always valid and is -1 both for embedded and external
73
+#define QCOW_L2_BITMAP_ALL_ZEROES (QCOW_OFLAG_SUB_ZERO_RANGE(0, 32))
37
+ * cases. It is included in the union only to ensure the padding prior
74
+
38
+ * to the @size field will not result in a 0-length array.
75
/* Size of normal and extended L2 entries */
39
+ */
76
#define L2E_SIZE_NORMAL (sizeof(uint64_t))
40
+ union {
77
#define L2E_SIZE_EXTENDED (sizeof(uint64_t) * 2)
41
+ struct {
78
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
42
+ int nalloc;
79
QLIST_ENTRY(QCowL2Meta) next_in_flight;
43
+ struct iovec local_iov;
80
} QCowL2Meta;
44
+ };
81
45
+ struct {
82
+/*
46
+ char __pad[sizeof(int) + offsetof(struct iovec, iov_len)];
83
+ * In images with standard L2 entries all clusters are treated as if
47
+ size_t size;
84
+ * they had one subcluster so QCow2ClusterType and QCow2SubclusterType
48
+ };
85
+ * can be mapped to each other and have the exact same meaning
49
+ };
86
+ * (QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC cannot happen in these images).
50
} QEMUIOVector;
87
+ *
51
88
+ * In images with extended L2 entries QCow2ClusterType refers to the
52
+QEMU_BUILD_BUG_ON(offsetof(QEMUIOVector, size) !=
89
+ * complete cluster and QCow2SubclusterType to each of the individual
53
+ offsetof(QEMUIOVector, local_iov.iov_len));
90
+ * subclusters, so there are several possible combinations:
54
+
91
+ *
55
+#define QEMU_IOVEC_INIT_BUF(self, buf, len) \
92
+ * |--------------+---------------------------|
56
+{ \
93
+ * | Cluster type | Possible subcluster types |
57
+ .iov = &(self).local_iov, \
94
+ * |--------------+---------------------------|
58
+ .niov = 1, \
95
+ * | UNALLOCATED | UNALLOCATED_PLAIN |
59
+ .nalloc = -1, \
96
+ * | | ZERO_PLAIN |
60
+ .local_iov = { \
97
+ * |--------------+---------------------------|
61
+ .iov_base = (void *)(buf), /* cast away const */ \
98
+ * | NORMAL | UNALLOCATED_ALLOC |
62
+ .iov_len = (len), \
99
+ * | | ZERO_ALLOC |
63
+ }, \
100
+ * | | NORMAL |
101
+ * |--------------+---------------------------|
102
+ * | COMPRESSED | COMPRESSED |
103
+ * |--------------+---------------------------|
104
+ *
105
+ * QCOW2_SUBCLUSTER_INVALID means that the L2 entry is incorrect and
106
+ * the image should be marked corrupt.
107
+ */
108
+
109
typedef enum QCow2ClusterType {
110
QCOW2_CLUSTER_UNALLOCATED,
111
QCOW2_CLUSTER_ZERO_PLAIN,
112
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2ClusterType {
113
QCOW2_CLUSTER_COMPRESSED,
114
} QCow2ClusterType;
115
116
+typedef enum QCow2SubclusterType {
117
+ QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN,
118
+ QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC,
119
+ QCOW2_SUBCLUSTER_ZERO_PLAIN,
120
+ QCOW2_SUBCLUSTER_ZERO_ALLOC,
121
+ QCOW2_SUBCLUSTER_NORMAL,
122
+ QCOW2_SUBCLUSTER_COMPRESSED,
123
+ QCOW2_SUBCLUSTER_INVALID,
124
+} QCow2SubclusterType;
125
+
126
typedef enum QCow2MetadataOverlap {
127
QCOW2_OL_MAIN_HEADER_BITNR = 0,
128
QCOW2_OL_ACTIVE_L1_BITNR = 1,
129
@@ -XXX,XX +XXX,XX @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
130
static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
131
uint64_t l2_entry)
132
{
133
+ BDRVQcow2State *s = bs->opaque;
134
+
135
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
136
return QCOW2_CLUSTER_COMPRESSED;
137
- } else if (l2_entry & QCOW_OFLAG_ZERO) {
138
+ } else if ((l2_entry & QCOW_OFLAG_ZERO) && !has_subclusters(s)) {
139
if (l2_entry & L2E_OFFSET_MASK) {
140
return QCOW2_CLUSTER_ZERO_ALLOC;
141
}
142
@@ -XXX,XX +XXX,XX @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
143
}
144
}
145
146
+/*
147
+ * For an image without extended L2 entries, return the
148
+ * QCow2SubclusterType equivalent of a given QCow2ClusterType.
149
+ */
150
+static inline
151
+QCow2SubclusterType qcow2_cluster_to_subcluster_type(QCow2ClusterType type)
152
+{
153
+ switch (type) {
154
+ case QCOW2_CLUSTER_COMPRESSED:
155
+ return QCOW2_SUBCLUSTER_COMPRESSED;
156
+ case QCOW2_CLUSTER_ZERO_PLAIN:
157
+ return QCOW2_SUBCLUSTER_ZERO_PLAIN;
158
+ case QCOW2_CLUSTER_ZERO_ALLOC:
159
+ return QCOW2_SUBCLUSTER_ZERO_ALLOC;
160
+ case QCOW2_CLUSTER_NORMAL:
161
+ return QCOW2_SUBCLUSTER_NORMAL;
162
+ case QCOW2_CLUSTER_UNALLOCATED:
163
+ return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
164
+ default:
165
+ g_assert_not_reached();
166
+ }
64
+}
167
+}
65
+
168
+
66
+/*
169
+/*
67
+ * qemu_iovec_init_buf
170
+ * In an image without subsclusters @l2_bitmap is ignored and
68
+ *
171
+ * @sc_index must be 0.
69
+ * Initialize embedded QEMUIOVector.
172
+ * Return QCOW2_SUBCLUSTER_INVALID if an invalid l2 entry is detected
70
+ *
173
+ * (this checks the whole entry and bitmap, not only the bits related
71
+ * Note: "const" is used over @buf pointer to make it simple to pass
174
+ * to subcluster @sc_index).
72
+ * const pointers, appearing in read functions. Then this "const" is
73
+ * cast away by QEMU_IOVEC_INIT_BUF().
74
+ */
175
+ */
75
+static inline void qemu_iovec_init_buf(QEMUIOVector *qiov,
176
+static inline
76
+ const void *buf, size_t len)
177
+QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
178
+ uint64_t l2_entry,
179
+ uint64_t l2_bitmap,
180
+ unsigned sc_index)
77
+{
181
+{
78
+ *qiov = (QEMUIOVector) QEMU_IOVEC_INIT_BUF(*qiov, buf, len);
182
+ BDRVQcow2State *s = bs->opaque;
183
+ QCow2ClusterType type = qcow2_get_cluster_type(bs, l2_entry);
184
+ assert(sc_index < s->subclusters_per_cluster);
185
+
186
+ if (has_subclusters(s)) {
187
+ switch (type) {
188
+ case QCOW2_CLUSTER_COMPRESSED:
189
+ return QCOW2_SUBCLUSTER_COMPRESSED;
190
+ case QCOW2_CLUSTER_NORMAL:
191
+ if ((l2_bitmap >> 32) & l2_bitmap) {
192
+ return QCOW2_SUBCLUSTER_INVALID;
193
+ } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) {
194
+ return QCOW2_SUBCLUSTER_ZERO_ALLOC;
195
+ } else if (l2_bitmap & QCOW_OFLAG_SUB_ALLOC(sc_index)) {
196
+ return QCOW2_SUBCLUSTER_NORMAL;
197
+ } else {
198
+ return QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC;
199
+ }
200
+ case QCOW2_CLUSTER_UNALLOCATED:
201
+ if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) {
202
+ return QCOW2_SUBCLUSTER_INVALID;
203
+ } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) {
204
+ return QCOW2_SUBCLUSTER_ZERO_PLAIN;
205
+ } else {
206
+ return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
207
+ }
208
+ default:
209
+ g_assert_not_reached();
210
+ }
211
+ } else {
212
+ return qcow2_cluster_to_subcluster_type(type);
213
+ }
79
+}
214
+}
80
+
215
+
81
+static inline void *qemu_iovec_buf(QEMUIOVector *qiov)
216
/* Check whether refcounts are eager or lazy */
82
+{
217
static inline bool qcow2_need_accurate_refcounts(BDRVQcow2State *s)
83
+ /* Only supports embedded iov */
218
{
84
+ assert(qiov->nalloc == -1 && qiov->iov == &qiov->local_iov);
85
+
86
+ return qiov->local_iov.iov_base;
87
+}
88
+
89
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
90
void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
91
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
92
--
219
--
93
2.20.1
220
2.26.2
94
221
95
222
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
In order to use VirtIOFeature also in other virtio devices, we move
3
There are situations in which we want to know how many contiguous
4
its declaration and the endof() macro (renamed in virtio_endof())
4
subclusters of the same type there are in a given cluster. This can be
5
in virtio.h.
5
done by simply iterating over the subclusters and repeatedly calling
6
We add virtio_feature_get_config_size() function to iterate the array
6
qcow2_get_subcluster_type() for each one of them.
7
of VirtIOFeature and to return the config size depending on the
8
features enabled. (as virtio_net_set_config_size() did)
9
7
10
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
8
However once we determined the type of a subcluster we can check the
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
rest efficiently by counting the number of adjacent ones (or zeroes)
12
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
10
in the bitmap. This is what this function does.
13
Message-id: 20190221103314.58500-5-sgarzare@redhat.com
11
14
Message-Id: <20190221103314.58500-5-sgarzare@redhat.com>
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Message-Id: <db917263d568ec6ffb4a41cac3c9100f96bf6c18.1594396418.git.berto@igalia.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
---
17
include/hw/virtio/virtio.h | 15 +++++++++++++++
18
block/qcow2-cluster.c | 51 +++++++++++++++++++++++++++++++++++++++++++
18
hw/net/virtio-net.c | 31 +++++++------------------------
19
1 file changed, 51 insertions(+)
19
hw/virtio/virtio.c | 15 +++++++++++++++
20
3 files changed, 37 insertions(+), 24 deletions(-)
21
20
22
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
23
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
24
--- a/include/hw/virtio/virtio.h
23
--- a/block/qcow2-cluster.c
25
+++ b/include/hw/virtio/virtio.h
24
+++ b/block/qcow2-cluster.c
26
@@ -XXX,XX +XXX,XX @@ static inline hwaddr vring_align(hwaddr addr,
25
@@ -XXX,XX +XXX,XX @@ fail:
27
return QEMU_ALIGN_UP(addr, align);
28
}
29
30
+/*
31
+ * Calculate the number of bytes up to and including the given 'field' of
32
+ * 'container'.
33
+ */
34
+#define virtio_endof(container, field) \
35
+ (offsetof(container, field) + sizeof_field(container, field))
36
+
37
+typedef struct VirtIOFeature {
38
+ uint64_t flags;
39
+ size_t end;
40
+} VirtIOFeature;
41
+
42
+size_t virtio_feature_get_config_size(VirtIOFeature *features,
43
+ uint64_t host_features);
44
+
45
typedef struct VirtQueue VirtQueue;
46
47
#define VIRTQUEUE_MAX_SIZE 1024
48
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/net/virtio-net.c
51
+++ b/hw/net/virtio-net.c
52
@@ -XXX,XX +XXX,XX @@ static inline __virtio16 *virtio_net_rsc_ext_num_dupacks(
53
54
#endif
55
56
-/*
57
- * Calculate the number of bytes up to and including the given 'field' of
58
- * 'container'.
59
- */
60
-#define endof(container, field) \
61
- (offsetof(container, field) + sizeof_field(container, field))
62
-
63
-typedef struct VirtIOFeature {
64
- uint64_t flags;
65
- size_t end;
66
-} VirtIOFeature;
67
-
68
static VirtIOFeature feature_sizes[] = {
69
{.flags = 1ULL << VIRTIO_NET_F_MAC,
70
- .end = endof(struct virtio_net_config, mac)},
71
+ .end = virtio_endof(struct virtio_net_config, mac)},
72
{.flags = 1ULL << VIRTIO_NET_F_STATUS,
73
- .end = endof(struct virtio_net_config, status)},
74
+ .end = virtio_endof(struct virtio_net_config, status)},
75
{.flags = 1ULL << VIRTIO_NET_F_MQ,
76
- .end = endof(struct virtio_net_config, max_virtqueue_pairs)},
77
+ .end = virtio_endof(struct virtio_net_config, max_virtqueue_pairs)},
78
{.flags = 1ULL << VIRTIO_NET_F_MTU,
79
- .end = endof(struct virtio_net_config, mtu)},
80
+ .end = virtio_endof(struct virtio_net_config, mtu)},
81
{.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX,
82
- .end = endof(struct virtio_net_config, duplex)},
83
+ .end = virtio_endof(struct virtio_net_config, duplex)},
84
{}
85
};
86
87
@@ -XXX,XX +XXX,XX @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
88
89
static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
90
{
91
- int i, config_size = 0;
92
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
93
94
- for (i = 0; feature_sizes[i].flags != 0; i++) {
95
- if (host_features & feature_sizes[i].flags) {
96
- config_size = MAX(feature_sizes[i].end, config_size);
97
- }
98
- }
99
- n->config_size = config_size;
100
+ n->config_size = virtio_feature_get_config_size(feature_sizes,
101
+ host_features);
102
}
103
104
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
105
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
106
index XXXXXXX..XXXXXXX 100644
107
--- a/hw/virtio/virtio.c
108
+++ b/hw/virtio/virtio.c
109
@@ -XXX,XX +XXX,XX @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val)
110
return ret;
26
return ret;
111
}
27
}
112
28
113
+size_t virtio_feature_get_config_size(VirtIOFeature *feature_sizes,
29
+/*
114
+ uint64_t host_features)
30
+ * For a given L2 entry, count the number of contiguous subclusters of
31
+ * the same type starting from @sc_from. Compressed clusters are
32
+ * treated as if they were divided into subclusters of size
33
+ * s->subcluster_size.
34
+ *
35
+ * Return the number of contiguous subclusters and set @type to the
36
+ * subcluster type.
37
+ *
38
+ * If the L2 entry is invalid return -errno and set @type to
39
+ * QCOW2_SUBCLUSTER_INVALID.
40
+ */
41
+G_GNUC_UNUSED
42
+static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
43
+ uint64_t l2_entry,
44
+ uint64_t l2_bitmap,
45
+ unsigned sc_from,
46
+ QCow2SubclusterType *type)
115
+{
47
+{
116
+ size_t config_size = 0;
48
+ BDRVQcow2State *s = bs->opaque;
117
+ int i;
49
+ uint32_t val;
118
+
50
+
119
+ for (i = 0; feature_sizes[i].flags != 0; i++) {
51
+ *type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_from);
120
+ if (host_features & feature_sizes[i].flags) {
52
+
121
+ config_size = MAX(feature_sizes[i].end, config_size);
53
+ if (*type == QCOW2_SUBCLUSTER_INVALID) {
122
+ }
54
+ return -EINVAL;
55
+ } else if (!has_subclusters(s) || *type == QCOW2_SUBCLUSTER_COMPRESSED) {
56
+ return s->subclusters_per_cluster - sc_from;
123
+ }
57
+ }
124
+
58
+
125
+ return config_size;
59
+ switch (*type) {
60
+ case QCOW2_SUBCLUSTER_NORMAL:
61
+ val = l2_bitmap | QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
62
+ return cto32(val) - sc_from;
63
+
64
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
65
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
66
+ val = (l2_bitmap | QCOW_OFLAG_SUB_ZERO_RANGE(0, sc_from)) >> 32;
67
+ return cto32(val) - sc_from;
68
+
69
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
70
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
71
+ val = ((l2_bitmap >> 32) | l2_bitmap)
72
+ & ~QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
73
+ return ctz32(val) - sc_from;
74
+
75
+ default:
76
+ g_assert_not_reached();
77
+ }
126
+}
78
+}
127
+
79
+
128
int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
80
/*
129
{
81
* Checks how many clusters in a given L2 slice are contiguous in the image
130
int i, ret;
82
* file. As soon as one of the flags in the bitmask stop_flags changes compared
131
--
83
--
132
2.20.1
84
2.26.2
133
85
134
86
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
This function is useful to fix the endianness of struct
3
This helper function tells us if a cluster is allocated (that is,
4
virtio_blk_discard_write_zeroes headers.
4
there is an associated host offset for it).
5
5
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Message-id: 20190221103314.58500-9-sgarzare@redhat.com
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20190221103314.58500-9-sgarzare@redhat.com>
9
Message-Id: <6d8771c5c79cbdc6c519875a5078e1cc85856d63.1594396418.git.berto@igalia.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
11
---
12
tests/virtio-blk-test.c | 23 +++++++++++++++++------
12
block/qcow2.h | 6 ++++++
13
1 file changed, 17 insertions(+), 6 deletions(-)
13
1 file changed, 6 insertions(+)
14
14
15
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
15
diff --git a/block/qcow2.h b/block/qcow2.h
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/virtio-blk-test.c
17
--- a/block/qcow2.h
18
+++ b/tests/virtio-blk-test.c
18
+++ b/block/qcow2.h
19
@@ -XXX,XX +XXX,XX @@ typedef struct QVirtioBlkReq {
19
@@ -XXX,XX +XXX,XX @@ QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
20
uint8_t status;
21
} QVirtioBlkReq;
22
23
+#ifdef HOST_WORDS_BIGENDIAN
24
+const bool host_is_big_endian = true;
25
+#else
26
+const bool host_is_big_endian; /* false */
27
+#endif
28
+
29
static char *drive_create(void)
30
{
31
int fd, ret;
32
@@ -XXX,XX +XXX,XX @@ static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
33
34
static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
35
{
36
-#ifdef HOST_WORDS_BIGENDIAN
37
- const bool host_is_big_endian = true;
38
-#else
39
- const bool host_is_big_endian = false;
40
-#endif
41
-
42
if (qvirtio_is_big_endian(d) != host_is_big_endian) {
43
req->type = bswap32(req->type);
44
req->ioprio = bswap32(req->ioprio);
45
@@ -XXX,XX +XXX,XX @@ static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
46
}
20
}
47
}
21
}
48
22
49
+
23
+static inline bool qcow2_cluster_is_allocated(QCow2ClusterType type)
50
+static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
51
+ struct virtio_blk_discard_write_zeroes *dwz_hdr)
52
+{
24
+{
53
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
25
+ return (type == QCOW2_CLUSTER_COMPRESSED || type == QCOW2_CLUSTER_NORMAL ||
54
+ dwz_hdr->sector = bswap64(dwz_hdr->sector);
26
+ type == QCOW2_CLUSTER_ZERO_ALLOC);
55
+ dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
56
+ dwz_hdr->flags = bswap32(dwz_hdr->flags);
57
+ }
58
+}
27
+}
59
+
28
+
60
static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
29
/* Check whether refcounts are eager or lazy */
61
QVirtioBlkReq *req, uint64_t data_size)
30
static inline bool qcow2_need_accurate_refcounts(BDRVQcow2State *s)
62
{
31
{
63
--
32
--
64
2.20.1
33
2.26.2
65
34
66
35
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
This function returns an integer that can be either an error code or a
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
cluster type (a value from the QCow2ClusterType enum).
5
5
6
While being here, use qemu_try_blockalign0 as well.
6
We are going to start using subcluster types instead of cluster types
7
in some functions so it's better to use the exact data types instead
8
of integers for clarity and in order to detect errors more easily.
7
9
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
This patch makes qcow2_get_host_offset() return 0 on success and
9
Reviewed-by: Eric Blake <eblake@redhat.com>
11
puts the returned cluster type in a separate parameter. There are no
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
semantic changes.
11
Message-id: 20190218140926.333779-3-vsementsov@virtuozzo.com
13
12
Message-Id: <20190218140926.333779-3-vsementsov@virtuozzo.com>
14
Signed-off-by: Alberto Garcia <berto@igalia.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Message-Id: <396b6eab1859a271551dcd7dcba77f8934aa3c3f.1594396418.git.berto@igalia.com>
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
19
---
15
block/io.c | 89 ++++++++++++------------------------------------------
20
block/qcow2.h | 3 ++-
16
1 file changed, 20 insertions(+), 69 deletions(-)
21
block/qcow2-cluster.c | 11 +++++++----
22
block/qcow2.c | 37 ++++++++++++++++++++++---------------
23
3 files changed, 31 insertions(+), 20 deletions(-)
17
24
18
diff --git a/block/io.c b/block/io.c
25
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
20
--- a/block/io.c
27
--- a/block/qcow2.h
21
+++ b/block/io.c
28
+++ b/block/qcow2.h
22
@@ -XXX,XX +XXX,XX @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
29
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
23
static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf,
30
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
24
int nb_sectors, bool is_write, BdrvRequestFlags flags)
31
32
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
33
- unsigned int *bytes, uint64_t *host_offset);
34
+ unsigned int *bytes, uint64_t *host_offset,
35
+ QCow2ClusterType *cluster_type);
36
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
37
unsigned int *bytes, uint64_t *host_offset,
38
QCowL2Meta **m);
39
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/qcow2-cluster.c
42
+++ b/block/qcow2-cluster.c
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
44
*
45
* On exit, *bytes is the number of bytes starting at offset that have the same
46
* cluster type and (if applicable) are stored contiguously in the image file.
47
+ * The cluster type is stored in *cluster_type.
48
* Compressed clusters are always returned one by one.
49
*
50
- * Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
51
- * cases.
52
+ * Returns 0 on success, -errno in error cases.
53
*/
54
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
55
- unsigned int *bytes, uint64_t *host_offset)
56
+ unsigned int *bytes, uint64_t *host_offset,
57
+ QCow2ClusterType *cluster_type)
25
{
58
{
26
- QEMUIOVector qiov;
59
BDRVQcow2State *s = bs->opaque;
27
- struct iovec iov = {
60
unsigned int l2_index;
28
- .iov_base = (void *)buf,
61
@@ -XXX,XX +XXX,XX @@ out:
29
- .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
62
assert(bytes_available - offset_in_cluster <= UINT_MAX);
30
- };
63
*bytes = bytes_available - offset_in_cluster;
31
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf,
64
32
+ nb_sectors * BDRV_SECTOR_SIZE);
65
- return type;
33
66
+ *cluster_type = type;
34
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
67
+
35
return -EINVAL;
68
+ return 0;
69
70
fail:
71
qcow2_cache_put(s->l2_table_cache, (void **)&l2_slice);
72
diff --git a/block/qcow2.c b/block/qcow2.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/qcow2.c
75
+++ b/block/qcow2.c
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
77
BDRVQcow2State *s = bs->opaque;
78
uint64_t host_offset;
79
unsigned int bytes;
80
+ QCow2ClusterType type;
81
int ret, status = 0;
82
83
qemu_co_mutex_lock(&s->lock);
84
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
36
}
85
}
37
86
38
- qemu_iovec_init_external(&qiov, &iov, 1);
87
bytes = MIN(INT_MAX, count);
39
return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS,
88
- ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset);
40
&qiov, is_write, flags);
89
+ ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset, &type);
41
}
90
qemu_co_mutex_unlock(&s->lock);
42
@@ -XXX,XX +XXX,XX @@ int bdrv_write(BdrvChild *child, int64_t sector_num,
43
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
44
int bytes, BdrvRequestFlags flags)
45
{
46
- QEMUIOVector qiov;
47
- struct iovec iov = {
48
- .iov_base = NULL,
49
- .iov_len = bytes,
50
- };
51
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
52
53
- qemu_iovec_init_external(&qiov, &iov, 1);
54
return bdrv_prwv_co(child, offset, &qiov, true,
55
BDRV_REQ_ZERO_WRITE | flags);
56
}
57
@@ -XXX,XX +XXX,XX @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
58
59
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
60
{
61
- QEMUIOVector qiov;
62
- struct iovec iov = {
63
- .iov_base = (void *)buf,
64
- .iov_len = bytes,
65
- };
66
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
67
68
if (bytes < 0) {
69
return -EINVAL;
70
}
71
72
- qemu_iovec_init_external(&qiov, &iov, 1);
73
return bdrv_preadv(child, offset, &qiov);
74
}
75
76
@@ -XXX,XX +XXX,XX @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
77
78
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
79
{
80
- QEMUIOVector qiov;
81
- struct iovec iov = {
82
- .iov_base = (void *) buf,
83
- .iov_len = bytes,
84
- };
85
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
86
87
if (bytes < 0) {
88
return -EINVAL;
89
}
90
91
- qemu_iovec_init_external(&qiov, &iov, 1);
92
return bdrv_pwritev(child, offset, &qiov);
93
}
94
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
96
void *bounce_buffer;
97
98
BlockDriver *drv = bs->drv;
99
- struct iovec iov;
100
QEMUIOVector local_qiov;
101
int64_t cluster_offset;
102
int64_t cluster_bytes;
103
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
104
105
if (ret <= 0) {
106
/* Must copy-on-read; use the bounce buffer */
107
- iov.iov_base = bounce_buffer;
108
- iov.iov_len = pnum = MIN(pnum, MAX_BOUNCE_BUFFER);
109
- qemu_iovec_init_external(&local_qiov, &iov, 1);
110
+ pnum = MIN(pnum, MAX_BOUNCE_BUFFER);
111
+ qemu_iovec_init_buf(&local_qiov, bounce_buffer, pnum);
112
113
ret = bdrv_driver_preadv(bs, cluster_offset, pnum,
114
&local_qiov, 0);
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
116
{
117
BlockDriver *drv = bs->drv;
118
QEMUIOVector qiov;
119
- struct iovec iov = {0};
120
+ void *buf = NULL;
121
int ret = 0;
122
bool need_flush = false;
123
int head = 0;
124
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
125
need_flush = true;
126
}
127
num = MIN(num, max_transfer);
128
- iov.iov_len = num;
129
- if (iov.iov_base == NULL) {
130
- iov.iov_base = qemu_try_blockalign(bs, num);
131
- if (iov.iov_base == NULL) {
132
+ if (buf == NULL) {
133
+ buf = qemu_try_blockalign0(bs, num);
134
+ if (buf == NULL) {
135
ret = -ENOMEM;
136
goto fail;
137
}
138
- memset(iov.iov_base, 0, num);
139
}
140
- qemu_iovec_init_external(&qiov, &iov, 1);
141
+ qemu_iovec_init_buf(&qiov, buf, num);
142
143
ret = bdrv_driver_pwritev(bs, offset, num, &qiov, write_flags);
144
145
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
146
* all future requests.
147
*/
148
if (num < max_transfer) {
149
- qemu_vfree(iov.iov_base);
150
- iov.iov_base = NULL;
151
+ qemu_vfree(buf);
152
+ buf = NULL;
153
}
154
}
155
156
@@ -XXX,XX +XXX,XX @@ fail:
157
if (ret == 0 && need_flush) {
158
ret = bdrv_co_flush(bs);
159
}
160
- qemu_vfree(iov.iov_base);
161
+ qemu_vfree(buf);
162
return ret;
163
}
164
165
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
166
BlockDriverState *bs = child->bs;
167
uint8_t *buf = NULL;
168
QEMUIOVector local_qiov;
169
- struct iovec iov;
170
uint64_t align = bs->bl.request_alignment;
171
unsigned int head_padding_bytes, tail_padding_bytes;
172
int ret = 0;
173
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
174
assert(flags & BDRV_REQ_ZERO_WRITE);
175
if (head_padding_bytes || tail_padding_bytes) {
176
buf = qemu_blockalign(bs, align);
177
- iov = (struct iovec) {
178
- .iov_base = buf,
179
- .iov_len = align,
180
- };
181
- qemu_iovec_init_external(&local_qiov, &iov, 1);
182
+ qemu_iovec_init_buf(&local_qiov, buf, align);
183
}
184
if (head_padding_bytes) {
185
uint64_t zero_bytes = MIN(bytes, align - head_padding_bytes);
186
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
187
188
if (offset & (align - 1)) {
189
QEMUIOVector head_qiov;
190
- struct iovec head_iov;
191
192
mark_request_serialising(&req, align);
193
wait_serialising_requests(&req);
194
195
head_buf = qemu_blockalign(bs, align);
196
- head_iov = (struct iovec) {
197
- .iov_base = head_buf,
198
- .iov_len = align,
199
- };
200
- qemu_iovec_init_external(&head_qiov, &head_iov, 1);
201
+ qemu_iovec_init_buf(&head_qiov, head_buf, align);
202
203
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
204
ret = bdrv_aligned_preadv(child, &req, offset & ~(align - 1), align,
205
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
206
207
if ((offset + bytes) & (align - 1)) {
208
QEMUIOVector tail_qiov;
209
- struct iovec tail_iov;
210
size_t tail_bytes;
211
bool waited;
212
213
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
214
assert(!waited || !use_local_qiov);
215
216
tail_buf = qemu_blockalign(bs, align);
217
- tail_iov = (struct iovec) {
218
- .iov_base = tail_buf,
219
- .iov_len = align,
220
- };
221
- qemu_iovec_init_external(&tail_qiov, &tail_iov, 1);
222
+ qemu_iovec_init_buf(&tail_qiov, tail_buf, align);
223
224
bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
225
ret = bdrv_aligned_preadv(child, &req, (offset + bytes) & ~(align - 1),
226
@@ -XXX,XX +XXX,XX @@ bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
227
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
228
int64_t pos, int size)
229
{
230
- QEMUIOVector qiov;
231
- struct iovec iov = {
232
- .iov_base = (void *) buf,
233
- .iov_len = size,
234
- };
235
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size);
236
int ret;
237
238
- qemu_iovec_init_external(&qiov, &iov, 1);
239
-
240
ret = bdrv_writev_vmstate(bs, &qiov, pos);
241
if (ret < 0) {
91
if (ret < 0) {
242
return ret;
92
return ret;
243
@@ -XXX,XX +XXX,XX @@ int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
244
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
94
245
int64_t pos, int size)
95
*pnum = bytes;
246
{
96
247
- QEMUIOVector qiov;
97
- if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
248
- struct iovec iov = {
98
+ if ((type == QCOW2_CLUSTER_NORMAL || type == QCOW2_CLUSTER_ZERO_ALLOC) &&
249
- .iov_base = buf,
99
!s->crypto) {
250
- .iov_len = size,
100
*map = host_offset;
251
- };
101
*file = s->data_file->bs;
252
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, size);
102
status |= BDRV_BLOCK_OFFSET_VALID;
253
int ret;
103
}
254
104
- if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) {
255
- qemu_iovec_init_external(&qiov, &iov, 1);
105
+ if (type == QCOW2_CLUSTER_ZERO_PLAIN || type == QCOW2_CLUSTER_ZERO_ALLOC) {
256
ret = bdrv_readv_vmstate(bs, &qiov, pos);
106
status |= BDRV_BLOCK_ZERO;
257
if (ret < 0) {
107
- } else if (ret != QCOW2_CLUSTER_UNALLOCATED) {
258
return ret;
108
+ } else if (type != QCOW2_CLUSTER_UNALLOCATED) {
109
status |= BDRV_BLOCK_DATA;
110
}
111
if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
112
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
113
int ret = 0;
114
unsigned int cur_bytes; /* number of bytes in current iteration */
115
uint64_t host_offset = 0;
116
+ QCow2ClusterType type;
117
AioTaskPool *aio = NULL;
118
119
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
120
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
121
}
122
123
qemu_co_mutex_lock(&s->lock);
124
- ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset);
125
+ ret = qcow2_get_host_offset(bs, offset, &cur_bytes,
126
+ &host_offset, &type);
127
qemu_co_mutex_unlock(&s->lock);
128
if (ret < 0) {
129
goto out;
130
}
131
132
- if (ret == QCOW2_CLUSTER_ZERO_PLAIN ||
133
- ret == QCOW2_CLUSTER_ZERO_ALLOC ||
134
- (ret == QCOW2_CLUSTER_UNALLOCATED && !bs->backing))
135
+ if (type == QCOW2_CLUSTER_ZERO_PLAIN ||
136
+ type == QCOW2_CLUSTER_ZERO_ALLOC ||
137
+ (type == QCOW2_CLUSTER_UNALLOCATED && !bs->backing))
138
{
139
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
140
} else {
141
if (!aio && cur_bytes != bytes) {
142
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
143
}
144
- ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, ret,
145
+ ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, type,
146
host_offset, offset, cur_bytes,
147
qiov, qiov_offset, NULL);
148
if (ret < 0) {
149
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
150
if (head || tail) {
151
uint64_t off;
152
unsigned int nr;
153
+ QCow2ClusterType type;
154
155
assert(head + bytes <= s->cluster_size);
156
157
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
158
offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
159
bytes = s->cluster_size;
160
nr = s->cluster_size;
161
- ret = qcow2_get_host_offset(bs, offset, &nr, &off);
162
- if (ret != QCOW2_CLUSTER_UNALLOCATED &&
163
- ret != QCOW2_CLUSTER_ZERO_PLAIN &&
164
- ret != QCOW2_CLUSTER_ZERO_ALLOC) {
165
+ ret = qcow2_get_host_offset(bs, offset, &nr, &off, &type);
166
+ if (ret < 0 ||
167
+ (type != QCOW2_CLUSTER_UNALLOCATED &&
168
+ type != QCOW2_CLUSTER_ZERO_PLAIN &&
169
+ type != QCOW2_CLUSTER_ZERO_ALLOC)) {
170
qemu_co_mutex_unlock(&s->lock);
171
return -ENOTSUP;
172
}
173
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
174
175
while (bytes != 0) {
176
uint64_t copy_offset = 0;
177
+ QCow2ClusterType type;
178
/* prepare next request */
179
cur_bytes = MIN(bytes, INT_MAX);
180
cur_write_flags = write_flags;
181
182
- ret = qcow2_get_host_offset(bs, src_offset, &cur_bytes, &copy_offset);
183
+ ret = qcow2_get_host_offset(bs, src_offset, &cur_bytes,
184
+ &copy_offset, &type);
185
if (ret < 0) {
186
goto out;
187
}
188
189
- switch (ret) {
190
+ switch (type) {
191
case QCOW2_CLUSTER_UNALLOCATED:
192
if (bs->backing && bs->backing->bs) {
193
int64_t backing_length = bdrv_getlength(bs->backing->bs);
259
--
194
--
260
2.20.1
195
2.26.2
261
196
262
197
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
In order to support extended L2 entries some functions of the qcow2
4
driver need to start dealing with subclusters instead of clusters.
5
6
qcow2_get_host_offset() is modified to return the subcluster type
7
instead of the cluster type, and all callers are updated to replace
8
all values of QCow2ClusterType with their QCow2SubclusterType
9
equivalents.
10
11
This patch only changes the data types, there are no semantic changes.
12
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-Id: <f6c29737c295f32cbee74c903c30b01820363b34.1594396418.git.berto@igalia.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
block/qcow2.h | 2 +-
20
block/qcow2-cluster.c | 10 +++----
21
block/qcow2.c | 70 ++++++++++++++++++++++---------------------
22
3 files changed, 42 insertions(+), 40 deletions(-)
23
24
diff --git a/block/qcow2.h b/block/qcow2.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2.h
27
+++ b/block/qcow2.h
28
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
29
30
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
31
unsigned int *bytes, uint64_t *host_offset,
32
- QCow2ClusterType *cluster_type);
33
+ QCow2SubclusterType *subcluster_type);
34
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
35
unsigned int *bytes, uint64_t *host_offset,
36
QCowL2Meta **m);
37
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/block/qcow2-cluster.c
40
+++ b/block/qcow2-cluster.c
41
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
42
* offset that we are interested in.
43
*
44
* On exit, *bytes is the number of bytes starting at offset that have the same
45
- * cluster type and (if applicable) are stored contiguously in the image file.
46
- * The cluster type is stored in *cluster_type.
47
- * Compressed clusters are always returned one by one.
48
+ * subcluster type and (if applicable) are stored contiguously in the image
49
+ * file. The subcluster type is stored in *subcluster_type.
50
+ * Compressed clusters are always processed one by one.
51
*
52
* Returns 0 on success, -errno in error cases.
53
*/
54
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
55
unsigned int *bytes, uint64_t *host_offset,
56
- QCow2ClusterType *cluster_type)
57
+ QCow2SubclusterType *subcluster_type)
58
{
59
BDRVQcow2State *s = bs->opaque;
60
unsigned int l2_index;
61
@@ -XXX,XX +XXX,XX @@ out:
62
assert(bytes_available - offset_in_cluster <= UINT_MAX);
63
*bytes = bytes_available - offset_in_cluster;
64
65
- *cluster_type = type;
66
+ *subcluster_type = qcow2_cluster_to_subcluster_type(type);
67
68
return 0;
69
70
diff --git a/block/qcow2.c b/block/qcow2.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/qcow2.c
73
+++ b/block/qcow2.c
74
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
75
BDRVQcow2State *s = bs->opaque;
76
uint64_t host_offset;
77
unsigned int bytes;
78
- QCow2ClusterType type;
79
+ QCow2SubclusterType type;
80
int ret, status = 0;
81
82
qemu_co_mutex_lock(&s->lock);
83
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
84
85
*pnum = bytes;
86
87
- if ((type == QCOW2_CLUSTER_NORMAL || type == QCOW2_CLUSTER_ZERO_ALLOC) &&
88
- !s->crypto) {
89
+ if ((type == QCOW2_SUBCLUSTER_NORMAL ||
90
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC) && !s->crypto) {
91
*map = host_offset;
92
*file = s->data_file->bs;
93
status |= BDRV_BLOCK_OFFSET_VALID;
94
}
95
- if (type == QCOW2_CLUSTER_ZERO_PLAIN || type == QCOW2_CLUSTER_ZERO_ALLOC) {
96
+ if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
97
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC) {
98
status |= BDRV_BLOCK_ZERO;
99
- } else if (type != QCOW2_CLUSTER_UNALLOCATED) {
100
+ } else if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN) {
101
status |= BDRV_BLOCK_DATA;
102
}
103
if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
104
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2AioTask {
105
AioTask task;
106
107
BlockDriverState *bs;
108
- QCow2ClusterType cluster_type; /* only for read */
109
+ QCow2SubclusterType subcluster_type; /* only for read */
110
uint64_t host_offset; /* or full descriptor in compressed clusters */
111
uint64_t offset;
112
uint64_t bytes;
113
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task);
114
static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
115
AioTaskPool *pool,
116
AioTaskFunc func,
117
- QCow2ClusterType cluster_type,
118
+ QCow2SubclusterType subcluster_type,
119
uint64_t host_offset,
120
uint64_t offset,
121
uint64_t bytes,
122
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
123
*task = (Qcow2AioTask) {
124
.task.func = func,
125
.bs = bs,
126
- .cluster_type = cluster_type,
127
+ .subcluster_type = subcluster_type,
128
.qiov = qiov,
129
.host_offset = host_offset,
130
.offset = offset,
131
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
132
133
trace_qcow2_add_task(qemu_coroutine_self(), bs, pool,
134
func == qcow2_co_preadv_task_entry ? "read" : "write",
135
- cluster_type, host_offset, offset, bytes,
136
+ subcluster_type, host_offset, offset, bytes,
137
qiov, qiov_offset);
138
139
if (!pool) {
140
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
141
}
142
143
static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
144
- QCow2ClusterType cluster_type,
145
+ QCow2SubclusterType subc_type,
146
uint64_t host_offset,
147
uint64_t offset, uint64_t bytes,
148
QEMUIOVector *qiov,
149
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
150
{
151
BDRVQcow2State *s = bs->opaque;
152
153
- switch (cluster_type) {
154
- case QCOW2_CLUSTER_ZERO_PLAIN:
155
- case QCOW2_CLUSTER_ZERO_ALLOC:
156
+ switch (subc_type) {
157
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
158
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
159
/* Both zero types are handled in qcow2_co_preadv_part */
160
g_assert_not_reached();
161
162
- case QCOW2_CLUSTER_UNALLOCATED:
163
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
164
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
165
166
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
167
return bdrv_co_preadv_part(bs->backing, offset, bytes,
168
qiov, qiov_offset, 0);
169
170
- case QCOW2_CLUSTER_COMPRESSED:
171
+ case QCOW2_SUBCLUSTER_COMPRESSED:
172
return qcow2_co_preadv_compressed(bs, host_offset,
173
offset, bytes, qiov, qiov_offset);
174
175
- case QCOW2_CLUSTER_NORMAL:
176
+ case QCOW2_SUBCLUSTER_NORMAL:
177
if (bs->encrypted) {
178
return qcow2_co_preadv_encrypted(bs, host_offset,
179
offset, bytes, qiov, qiov_offset);
180
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
181
182
assert(!t->l2meta);
183
184
- return qcow2_co_preadv_task(t->bs, t->cluster_type, t->host_offset,
185
- t->offset, t->bytes, t->qiov, t->qiov_offset);
186
+ return qcow2_co_preadv_task(t->bs, t->subcluster_type,
187
+ t->host_offset, t->offset, t->bytes,
188
+ t->qiov, t->qiov_offset);
189
}
190
191
static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
192
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
193
int ret = 0;
194
unsigned int cur_bytes; /* number of bytes in current iteration */
195
uint64_t host_offset = 0;
196
- QCow2ClusterType type;
197
+ QCow2SubclusterType type;
198
AioTaskPool *aio = NULL;
199
200
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
201
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
202
goto out;
203
}
204
205
- if (type == QCOW2_CLUSTER_ZERO_PLAIN ||
206
- type == QCOW2_CLUSTER_ZERO_ALLOC ||
207
- (type == QCOW2_CLUSTER_UNALLOCATED && !bs->backing))
208
+ if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
209
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
210
+ (type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing))
211
{
212
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
213
} else {
214
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task)
215
{
216
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
217
218
- assert(!t->cluster_type);
219
+ assert(!t->subcluster_type);
220
221
return qcow2_co_pwritev_task(t->bs, t->host_offset,
222
t->offset, t->bytes, t->qiov, t->qiov_offset,
223
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
224
if (head || tail) {
225
uint64_t off;
226
unsigned int nr;
227
- QCow2ClusterType type;
228
+ QCow2SubclusterType type;
229
230
assert(head + bytes <= s->cluster_size);
231
232
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
233
nr = s->cluster_size;
234
ret = qcow2_get_host_offset(bs, offset, &nr, &off, &type);
235
if (ret < 0 ||
236
- (type != QCOW2_CLUSTER_UNALLOCATED &&
237
- type != QCOW2_CLUSTER_ZERO_PLAIN &&
238
- type != QCOW2_CLUSTER_ZERO_ALLOC)) {
239
+ (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
240
+ type != QCOW2_SUBCLUSTER_ZERO_PLAIN &&
241
+ type != QCOW2_SUBCLUSTER_ZERO_ALLOC)) {
242
qemu_co_mutex_unlock(&s->lock);
243
return -ENOTSUP;
244
}
245
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
246
247
while (bytes != 0) {
248
uint64_t copy_offset = 0;
249
- QCow2ClusterType type;
250
+ QCow2SubclusterType type;
251
/* prepare next request */
252
cur_bytes = MIN(bytes, INT_MAX);
253
cur_write_flags = write_flags;
254
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
255
}
256
257
switch (type) {
258
- case QCOW2_CLUSTER_UNALLOCATED:
259
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
260
if (bs->backing && bs->backing->bs) {
261
int64_t backing_length = bdrv_getlength(bs->backing->bs);
262
if (src_offset >= backing_length) {
263
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
264
}
265
break;
266
267
- case QCOW2_CLUSTER_ZERO_PLAIN:
268
- case QCOW2_CLUSTER_ZERO_ALLOC:
269
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
270
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
271
cur_write_flags |= BDRV_REQ_ZERO_WRITE;
272
break;
273
274
- case QCOW2_CLUSTER_COMPRESSED:
275
+ case QCOW2_SUBCLUSTER_COMPRESSED:
276
ret = -ENOTSUP;
277
goto out;
278
279
- case QCOW2_CLUSTER_NORMAL:
280
+ case QCOW2_SUBCLUSTER_NORMAL:
281
child = s->data_file;
282
break;
283
284
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
285
{
286
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
287
288
- assert(!t->cluster_type && !t->l2meta);
289
+ assert(!t->subcluster_type && !t->l2meta);
290
291
return qcow2_co_pwritev_compressed_task(t->bs, t->offset, t->bytes, t->qiov,
292
t->qiov_offset);
293
--
294
2.26.2
295
296
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
When dealing with subcluster types there is a new value called
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC that has no equivalent in
5
QCow2ClusterType.
5
6
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
This patch handles that value in all places where subcluster types
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
are processed.
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
9
Message-id: 20190218140926.333779-13-vsementsov@virtuozzo.com
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Message-Id: <20190218140926.333779-13-vsementsov@virtuozzo.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-Id: <bf09e2e2439a468a901bb96ace411eed9ee50295.1594396418.git.berto@igalia.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
15
---
13
qemu-img.c | 10 ++--------
16
block/qcow2.c | 12 +++++++++---
14
1 file changed, 2 insertions(+), 8 deletions(-)
17
1 file changed, 9 insertions(+), 3 deletions(-)
15
18
16
diff --git a/qemu-img.c b/qemu-img.c
19
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-img.c
21
--- a/block/qcow2.c
19
+++ b/qemu-img.c
22
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
23
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
21
{
24
*pnum = bytes;
22
int n, ret;
25
23
QEMUIOVector qiov;
26
if ((type == QCOW2_SUBCLUSTER_NORMAL ||
24
- struct iovec iov;
27
- type == QCOW2_SUBCLUSTER_ZERO_ALLOC) && !s->crypto) {
25
28
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
26
assert(nb_sectors <= s->buf_sectors);
29
+ type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC) && !s->crypto) {
27
while (nb_sectors > 0) {
30
*map = host_offset;
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
31
*file = s->data_file->bs;
29
bs_sectors = s->src_sectors[src_cur];
32
status |= BDRV_BLOCK_OFFSET_VALID;
30
33
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
31
n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
34
if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
32
- iov.iov_base = buf;
35
type == QCOW2_SUBCLUSTER_ZERO_ALLOC) {
33
- iov.iov_len = n << BDRV_SECTOR_BITS;
36
status |= BDRV_BLOCK_ZERO;
34
- qemu_iovec_init_external(&qiov, &iov, 1);
37
- } else if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN) {
35
+ qemu_iovec_init_buf(&qiov, buf, n << BDRV_SECTOR_BITS);
38
+ } else if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
36
39
+ type != QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC) {
37
ret = blk_co_preadv(
40
status |= BDRV_BLOCK_DATA;
38
blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS,
41
}
39
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
42
if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
40
{
43
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
41
int ret;
44
g_assert_not_reached();
42
QEMUIOVector qiov;
45
43
- struct iovec iov;
46
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
44
47
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
45
while (nb_sectors > 0) {
48
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
46
int n = nb_sectors;
49
47
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
50
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
48
(s->compressed &&
51
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
49
!buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)))
52
50
{
53
if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
51
- iov.iov_base = buf;
54
type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
52
- iov.iov_len = n << BDRV_SECTOR_BITS;
55
- (type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing))
53
- qemu_iovec_init_external(&qiov, &iov, 1);
56
+ (type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing) ||
54
+ qemu_iovec_init_buf(&qiov, buf, n << BDRV_SECTOR_BITS);
57
+ (type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC && !bs->backing))
55
58
{
56
ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS,
59
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
57
n << BDRV_SECTOR_BITS, &qiov, flags);
60
} else {
61
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
62
ret = qcow2_get_host_offset(bs, offset, &nr, &off, &type);
63
if (ret < 0 ||
64
(type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
65
+ type != QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC &&
66
type != QCOW2_SUBCLUSTER_ZERO_PLAIN &&
67
type != QCOW2_SUBCLUSTER_ZERO_ALLOC)) {
68
qemu_co_mutex_unlock(&s->lock);
69
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
70
71
switch (type) {
72
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
73
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
74
if (bs->backing && bs->backing->bs) {
75
int64_t backing_length = bdrv_getlength(bs->backing->bs);
76
if (src_offset >= backing_length) {
58
--
77
--
59
2.20.1
78
2.26.2
60
79
61
80
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
@iov is used only to initialize @qiov. Let's use new
3
If an image has subclusters then there are more copy-on-write
4
qemu_iovec_init_buf() instead, which simplifies the code.
4
scenarios that we need to consider. Let's say we have a write request
5
5
from the middle of subcluster #3 until the end of the cluster:
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
7
1) If we are writing to a newly allocated cluster then we need
8
copy-on-write. The previous contents of subclusters #0 to #3 must
9
be copied to the new cluster. We can optimize this process by
10
skipping all leading unallocated or zero subclusters (the status of
11
those skipped subclusters will be reflected in the new L2 bitmap).
12
13
2) If we are overwriting an existing cluster:
14
15
2.1) If subcluster #3 is unallocated or has the all-zeroes bit set
16
then we need copy-on-write (on subcluster #3 only).
17
18
2.2) If subcluster #3 was already allocated then there is no need
19
for any copy-on-write. However we still need to update the L2
20
bitmap to reflect possible changes in the allocation status of
21
subclusters #4 to #31. Because of this, this function checks
22
if all the overwritten subclusters are already allocated and
23
in this case it returns without creating a new QCowL2Meta
24
structure.
25
26
After all these changes l2meta_cow_start() and l2meta_cow_end()
27
are not necessarily cluster-aligned anymore. We need to update the
28
calculation of old_start and old_end in handle_dependencies() to
29
guarantee that no two requests try to write on the same cluster.
30
31
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
32
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-16-vsementsov@virtuozzo.com
34
Message-Id: <4292dd56e4446d386a2fe307311737a711c00708.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-16-vsementsov@virtuozzo.com>
35
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
36
---
13
include/hw/ide/internal.h | 1 -
37
block/qcow2-cluster.c | 167 +++++++++++++++++++++++++++++++++---------
14
hw/ide/atapi.c | 9 ++++-----
38
1 file changed, 133 insertions(+), 34 deletions(-)
15
hw/ide/core.c | 8 ++------
39
16
3 files changed, 6 insertions(+), 12 deletions(-)
40
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
18
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
19
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/ide/internal.h
42
--- a/block/qcow2-cluster.c
21
+++ b/include/hw/ide/internal.h
43
+++ b/block/qcow2-cluster.c
22
@@ -XXX,XX +XXX,XX @@ struct IDEState {
44
@@ -XXX,XX +XXX,XX @@ fail:
23
int atapi_dma; /* true if dma is requested for the packet cmd */
45
* If the L2 entry is invalid return -errno and set @type to
24
BlockAcctCookie acct;
46
* QCOW2_SUBCLUSTER_INVALID.
25
BlockAIOCB *pio_aiocb;
47
*/
26
- struct iovec iov;
48
-G_GNUC_UNUSED
27
QEMUIOVector qiov;
49
static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
28
QLIST_HEAD(, IDEBufferedRequest) buffered_requests;
50
uint64_t l2_entry,
29
/* ATA DMA state */
51
uint64_t l2_bitmap,
30
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
52
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
31
index XXXXXXX..XXXXXXX 100644
53
* If @keep_old is true it means that the clusters were already
32
--- a/hw/ide/atapi.c
54
* allocated and will be overwritten. If false then the clusters are
33
+++ b/hw/ide/atapi.c
55
* new and we have to decrease the reference count of the old ones.
34
@@ -XXX,XX +XXX,XX @@ static void cd_read_sector_cb(void *opaque, int ret)
56
+ *
35
57
+ * Returns 0 on success, -errno on failure.
36
static int cd_read_sector(IDEState *s)
58
*/
59
-static void calculate_l2_meta(BlockDriverState *bs,
60
- uint64_t host_cluster_offset,
61
- uint64_t guest_offset, unsigned bytes,
62
- uint64_t *l2_slice, QCowL2Meta **m, bool keep_old)
63
+static int calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
64
+ uint64_t guest_offset, unsigned bytes,
65
+ uint64_t *l2_slice, QCowL2Meta **m, bool keep_old)
37
{
66
{
38
+ void *buf;
67
BDRVQcow2State *s = bs->opaque;
39
+
68
- int l2_index = offset_to_l2_slice_index(s, guest_offset);
40
if (s->cd_sector_size != 2048 && s->cd_sector_size != 2352) {
69
- uint64_t l2_entry;
41
block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
70
+ int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset);
42
return -EINVAL;
71
+ uint64_t l2_entry, l2_bitmap;
72
unsigned cow_start_from, cow_end_to;
73
unsigned cow_start_to = offset_into_cluster(s, guest_offset);
74
unsigned cow_end_from = cow_start_to + bytes;
75
unsigned nb_clusters = size_to_clusters(s, cow_end_from);
76
QCowL2Meta *old_m = *m;
77
- QCow2ClusterType type;
78
+ QCow2SubclusterType type;
79
+ int i;
80
+ bool skip_cow = keep_old;
81
82
assert(nb_clusters <= s->l2_slice_size - l2_index);
83
84
- /* Return if there's no COW (all clusters are normal and we keep them) */
85
- if (keep_old) {
86
- int i;
87
- for (i = 0; i < nb_clusters; i++) {
88
- l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
89
- if (qcow2_get_cluster_type(bs, l2_entry) != QCOW2_CLUSTER_NORMAL) {
90
- break;
91
+ /* Check the type of all affected subclusters */
92
+ for (i = 0; i < nb_clusters; i++) {
93
+ l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
94
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
95
+ if (skip_cow) {
96
+ unsigned write_from = MAX(cow_start_to, i << s->cluster_bits);
97
+ unsigned write_to = MIN(cow_end_from, (i + 1) << s->cluster_bits);
98
+ int first_sc = offset_to_sc_index(s, write_from);
99
+ int last_sc = offset_to_sc_index(s, write_to - 1);
100
+ int cnt = qcow2_get_subcluster_range_type(bs, l2_entry, l2_bitmap,
101
+ first_sc, &type);
102
+ /* Is any of the subclusters of type != QCOW2_SUBCLUSTER_NORMAL ? */
103
+ if (type != QCOW2_SUBCLUSTER_NORMAL || first_sc + cnt <= last_sc) {
104
+ skip_cow = false;
105
}
106
+ } else {
107
+ /* If we can't skip the cow we can still look for invalid entries */
108
+ type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, 0);
109
}
110
- if (i == nb_clusters) {
111
- return;
112
+ if (type == QCOW2_SUBCLUSTER_INVALID) {
113
+ int l1_index = offset_to_l1_index(s, guest_offset);
114
+ uint64_t l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
115
+ qcow2_signal_corruption(bs, true, -1, -1, "Invalid cluster "
116
+ "entry found (L2 offset: %#" PRIx64
117
+ ", L2 index: %#x)",
118
+ l2_offset, l2_index + i);
119
+ return -EIO;
120
}
43
}
121
}
44
122
45
- s->iov.iov_base = (s->cd_sector_size == 2352) ?
123
+ if (skip_cow) {
46
- s->io_buffer + 16 : s->io_buffer;
124
+ return 0;
125
+ }
126
+
127
/* Get the L2 entry of the first cluster */
128
l2_entry = get_l2_entry(s, l2_slice, l2_index);
129
- type = qcow2_get_cluster_type(bs, l2_entry);
47
-
130
-
48
- s->iov.iov_len = ATAPI_SECTOR_SIZE;
131
- if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
49
- qemu_iovec_init_external(&s->qiov, &s->iov, 1);
132
- cow_start_from = cow_start_to;
50
+ buf = (s->cd_sector_size == 2352) ? s->io_buffer + 16 : s->io_buffer;
133
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
51
+ qemu_iovec_init_buf(&s->qiov, buf, ATAPI_SECTOR_SIZE);
134
+ sc_index = offset_to_sc_index(s, guest_offset);
52
135
+ type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);
53
trace_cd_read_sector(s->lba);
136
+
54
137
+ if (!keep_old) {
55
diff --git a/hw/ide/core.c b/hw/ide/core.c
138
+ switch (type) {
56
index XXXXXXX..XXXXXXX 100644
139
+ case QCOW2_SUBCLUSTER_COMPRESSED:
57
--- a/hw/ide/core.c
140
+ cow_start_from = 0;
58
+++ b/hw/ide/core.c
141
+ break;
59
@@ -XXX,XX +XXX,XX @@ static void ide_sector_read(IDEState *s)
142
+ case QCOW2_SUBCLUSTER_NORMAL:
60
return;
143
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
144
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
145
+ if (has_subclusters(s)) {
146
+ /* Skip all leading zero and unallocated subclusters */
147
+ uint32_t alloc_bitmap = l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC;
148
+ cow_start_from =
149
+ MIN(sc_index, ctz32(alloc_bitmap)) << s->subcluster_bits;
150
+ } else {
151
+ cow_start_from = 0;
152
+ }
153
+ break;
154
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
155
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
156
+ cow_start_from = sc_index << s->subcluster_bits;
157
+ break;
158
+ default:
159
+ g_assert_not_reached();
160
+ }
161
} else {
162
- cow_start_from = 0;
163
+ switch (type) {
164
+ case QCOW2_SUBCLUSTER_NORMAL:
165
+ cow_start_from = cow_start_to;
166
+ break;
167
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
168
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
169
+ cow_start_from = sc_index << s->subcluster_bits;
170
+ break;
171
+ default:
172
+ g_assert_not_reached();
173
+ }
61
}
174
}
62
175
63
- s->iov.iov_base = s->io_buffer;
176
/* Get the L2 entry of the last cluster */
64
- s->iov.iov_len = n * BDRV_SECTOR_SIZE;
177
- l2_entry = get_l2_entry(s, l2_slice, l2_index + nb_clusters - 1);
65
- qemu_iovec_init_external(&s->qiov, &s->iov, 1);
178
- type = qcow2_get_cluster_type(bs, l2_entry);
66
+ qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE);
179
-
67
180
- if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
68
block_acct_start(blk_get_stats(s->blk), &s->acct,
181
- cow_end_to = cow_end_from;
69
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
182
+ l2_index += nb_clusters - 1;
70
@@ -XXX,XX +XXX,XX @@ static void ide_sector_write(IDEState *s)
183
+ l2_entry = get_l2_entry(s, l2_slice, l2_index);
71
return;
184
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
185
+ sc_index = offset_to_sc_index(s, guest_offset + bytes - 1);
186
+ type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);
187
+
188
+ if (!keep_old) {
189
+ switch (type) {
190
+ case QCOW2_SUBCLUSTER_COMPRESSED:
191
+ cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
192
+ break;
193
+ case QCOW2_SUBCLUSTER_NORMAL:
194
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
195
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
196
+ cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
197
+ if (has_subclusters(s)) {
198
+ /* Skip all trailing zero and unallocated subclusters */
199
+ uint32_t alloc_bitmap = l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC;
200
+ cow_end_to -=
201
+ MIN(s->subclusters_per_cluster - sc_index - 1,
202
+ clz32(alloc_bitmap)) << s->subcluster_bits;
203
+ }
204
+ break;
205
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
206
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
207
+ cow_end_to = ROUND_UP(cow_end_from, s->subcluster_size);
208
+ break;
209
+ default:
210
+ g_assert_not_reached();
211
+ }
212
} else {
213
- cow_end_to = ROUND_UP(cow_end_from, s->cluster_size);
214
+ switch (type) {
215
+ case QCOW2_SUBCLUSTER_NORMAL:
216
+ cow_end_to = cow_end_from;
217
+ break;
218
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
219
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
220
+ cow_end_to = ROUND_UP(cow_end_from, s->subcluster_size);
221
+ break;
222
+ default:
223
+ g_assert_not_reached();
224
+ }
72
}
225
}
73
226
74
- s->iov.iov_base = s->io_buffer;
227
*m = g_malloc0(sizeof(**m));
75
- s->iov.iov_len = n * BDRV_SECTOR_SIZE;
228
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
76
- qemu_iovec_init_external(&s->qiov, &s->iov, 1);
229
77
+ qemu_iovec_init_buf(&s->qiov, s->io_buffer, n * BDRV_SECTOR_SIZE);
230
qemu_co_queue_init(&(*m)->dependent_requests);
78
231
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
79
block_acct_start(blk_get_stats(s->blk), &s->acct,
232
+
80
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
233
+ return 0;
234
}
235
236
/*
237
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
238
239
uint64_t start = guest_offset;
240
uint64_t end = start + bytes;
241
- uint64_t old_start = l2meta_cow_start(old_alloc);
242
- uint64_t old_end = l2meta_cow_end(old_alloc);
243
+ uint64_t old_start = start_of_cluster(s, l2meta_cow_start(old_alloc));
244
+ uint64_t old_end = ROUND_UP(l2meta_cow_end(old_alloc), s->cluster_size);
245
246
if (end <= old_start || start >= old_end) {
247
/* No intersection */
248
@@ -XXX,XX +XXX,XX @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
249
- offset_into_cluster(s, guest_offset));
250
assert(*bytes != 0);
251
252
- calculate_l2_meta(bs, cluster_offset, guest_offset,
253
- *bytes, l2_slice, m, true);
254
+ ret = calculate_l2_meta(bs, cluster_offset, guest_offset,
255
+ *bytes, l2_slice, m, true);
256
+ if (ret < 0) {
257
+ goto out;
258
+ }
259
260
ret = 1;
261
} else {
262
@@ -XXX,XX +XXX,XX @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
263
*bytes = MIN(*bytes, nb_bytes - offset_into_cluster(s, guest_offset));
264
assert(*bytes != 0);
265
266
- calculate_l2_meta(bs, alloc_cluster_offset, guest_offset, *bytes, l2_slice,
267
- m, false);
268
+ ret = calculate_l2_meta(bs, alloc_cluster_offset, guest_offset, *bytes,
269
+ l2_slice, m, false);
270
+ if (ret < 0) {
271
+ goto out;
272
+ }
273
274
ret = 1;
275
81
--
276
--
82
2.20.1
277
2.26.2
83
278
84
279
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
The logic of this function remains pretty much the same, except that
4
it uses count_contiguous_subclusters(), which combines the logic of
5
count_contiguous_clusters() / count_contiguous_clusters_unallocated()
6
and checks individual subclusters.
7
8
qcow2_cluster_to_subcluster_type() is not necessary as a separate
9
function anymore so it's inlined into its caller.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-Id: <d2193fd48653a350d80f0eca1c67b1d9053fb2f3.1594396418.git.berto@igalia.com>
14
[mreitz: Initialize expected_type to anything]
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/qcow2.h | 38 ++++-------
18
block/qcow2-cluster.c | 150 ++++++++++++++++++++++--------------------
19
2 files changed, 92 insertions(+), 96 deletions(-)
20
21
diff --git a/block/qcow2.h b/block/qcow2.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2.h
24
+++ b/block/qcow2.h
25
@@ -XXX,XX +XXX,XX @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
26
}
27
}
28
29
-/*
30
- * For an image without extended L2 entries, return the
31
- * QCow2SubclusterType equivalent of a given QCow2ClusterType.
32
- */
33
-static inline
34
-QCow2SubclusterType qcow2_cluster_to_subcluster_type(QCow2ClusterType type)
35
-{
36
- switch (type) {
37
- case QCOW2_CLUSTER_COMPRESSED:
38
- return QCOW2_SUBCLUSTER_COMPRESSED;
39
- case QCOW2_CLUSTER_ZERO_PLAIN:
40
- return QCOW2_SUBCLUSTER_ZERO_PLAIN;
41
- case QCOW2_CLUSTER_ZERO_ALLOC:
42
- return QCOW2_SUBCLUSTER_ZERO_ALLOC;
43
- case QCOW2_CLUSTER_NORMAL:
44
- return QCOW2_SUBCLUSTER_NORMAL;
45
- case QCOW2_CLUSTER_UNALLOCATED:
46
- return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
47
- default:
48
- g_assert_not_reached();
49
- }
50
-}
51
-
52
/*
53
* In an image without subsclusters @l2_bitmap is ignored and
54
* @sc_index must be 0.
55
@@ -XXX,XX +XXX,XX @@ QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
56
g_assert_not_reached();
57
}
58
} else {
59
- return qcow2_cluster_to_subcluster_type(type);
60
+ switch (type) {
61
+ case QCOW2_CLUSTER_COMPRESSED:
62
+ return QCOW2_SUBCLUSTER_COMPRESSED;
63
+ case QCOW2_CLUSTER_ZERO_PLAIN:
64
+ return QCOW2_SUBCLUSTER_ZERO_PLAIN;
65
+ case QCOW2_CLUSTER_ZERO_ALLOC:
66
+ return QCOW2_SUBCLUSTER_ZERO_ALLOC;
67
+ case QCOW2_CLUSTER_NORMAL:
68
+ return QCOW2_SUBCLUSTER_NORMAL;
69
+ case QCOW2_CLUSTER_UNALLOCATED:
70
+ return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
71
+ default:
72
+ g_assert_not_reached();
73
+ }
74
}
75
}
76
77
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/block/qcow2-cluster.c
80
+++ b/block/qcow2-cluster.c
81
@@ -XXX,XX +XXX,XX @@ static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
82
}
83
84
/*
85
- * Checks how many clusters in a given L2 slice are contiguous in the image
86
- * file. As soon as one of the flags in the bitmask stop_flags changes compared
87
- * to the first cluster, the search is stopped and the cluster is not counted
88
- * as contiguous. (This allows it, for example, to stop at the first compressed
89
- * cluster which may require a different handling)
90
+ * Return the number of contiguous subclusters of the exact same type
91
+ * in a given L2 slice, starting from cluster @l2_index, subcluster
92
+ * @sc_index. Allocated subclusters are required to be contiguous in
93
+ * the image file.
94
+ * At most @nb_clusters are checked (note that this means clusters,
95
+ * not subclusters).
96
+ * Compressed clusters are always processed one by one but for the
97
+ * purpose of this count they are treated as if they were divided into
98
+ * subclusters of size s->subcluster_size.
99
+ * On failure return -errno and update @l2_index to point to the
100
+ * invalid entry.
101
*/
102
-static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
103
- int cluster_size, uint64_t *l2_slice, int l2_index, uint64_t stop_flags)
104
+static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
105
+ unsigned sc_index, uint64_t *l2_slice,
106
+ unsigned *l2_index)
107
{
108
BDRVQcow2State *s = bs->opaque;
109
- int i;
110
- QCow2ClusterType first_cluster_type;
111
- uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;
112
- uint64_t first_entry = get_l2_entry(s, l2_slice, l2_index);
113
- uint64_t offset = first_entry & mask;
114
+ int i, count = 0;
115
+ bool check_offset = false;
116
+ uint64_t expected_offset = 0;
117
+ QCow2SubclusterType expected_type = QCOW2_SUBCLUSTER_NORMAL, type;
118
119
- first_cluster_type = qcow2_get_cluster_type(bs, first_entry);
120
- if (first_cluster_type == QCOW2_CLUSTER_UNALLOCATED) {
121
- return 0;
122
- }
123
-
124
- /* must be allocated */
125
- assert(first_cluster_type == QCOW2_CLUSTER_NORMAL ||
126
- first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
127
+ assert(*l2_index + nb_clusters <= s->l2_slice_size);
128
129
for (i = 0; i < nb_clusters; i++) {
130
- uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index + i) & mask;
131
- if (offset + (uint64_t) i * cluster_size != l2_entry) {
132
+ unsigned first_sc = (i == 0) ? sc_index : 0;
133
+ uint64_t l2_entry = get_l2_entry(s, l2_slice, *l2_index + i);
134
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, *l2_index + i);
135
+ int ret = qcow2_get_subcluster_range_type(bs, l2_entry, l2_bitmap,
136
+ first_sc, &type);
137
+ if (ret < 0) {
138
+ *l2_index += i; /* Point to the invalid entry */
139
+ return -EIO;
140
+ }
141
+ if (i == 0) {
142
+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
143
+ /* Compressed clusters are always processed one by one */
144
+ return ret;
145
+ }
146
+ expected_type = type;
147
+ expected_offset = l2_entry & L2E_OFFSET_MASK;
148
+ check_offset = (type == QCOW2_SUBCLUSTER_NORMAL ||
149
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
150
+ type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC);
151
+ } else if (type != expected_type) {
152
break;
153
+ } else if (check_offset) {
154
+ expected_offset += s->cluster_size;
155
+ if (expected_offset != (l2_entry & L2E_OFFSET_MASK)) {
156
+ break;
157
+ }
158
}
159
- }
160
-
161
- return i;
162
-}
163
-
164
-/*
165
- * Checks how many consecutive unallocated clusters in a given L2
166
- * slice have the same cluster type.
167
- */
168
-static int count_contiguous_clusters_unallocated(BlockDriverState *bs,
169
- int nb_clusters,
170
- uint64_t *l2_slice,
171
- int l2_index,
172
- QCow2ClusterType wanted_type)
173
-{
174
- BDRVQcow2State *s = bs->opaque;
175
- int i;
176
-
177
- assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||
178
- wanted_type == QCOW2_CLUSTER_UNALLOCATED);
179
- for (i = 0; i < nb_clusters; i++) {
180
- uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
181
- QCow2ClusterType type = qcow2_get_cluster_type(bs, entry);
182
-
183
- if (type != wanted_type) {
184
+ count += ret;
185
+ /* Stop if there are type changes before the end of the cluster */
186
+ if (first_sc + ret < s->subclusters_per_cluster) {
187
break;
188
}
189
}
190
191
- return i;
192
+ return count;
193
}
194
195
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
196
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
197
QCow2SubclusterType *subcluster_type)
198
{
199
BDRVQcow2State *s = bs->opaque;
200
- unsigned int l2_index;
201
- uint64_t l1_index, l2_offset, *l2_slice, l2_entry;
202
- int c;
203
+ unsigned int l2_index, sc_index;
204
+ uint64_t l1_index, l2_offset, *l2_slice, l2_entry, l2_bitmap;
205
+ int sc;
206
unsigned int offset_in_cluster;
207
uint64_t bytes_available, bytes_needed, nb_clusters;
208
- QCow2ClusterType type;
209
+ QCow2SubclusterType type;
210
int ret;
211
212
offset_in_cluster = offset_into_cluster(s, offset);
213
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
214
215
l1_index = offset_to_l1_index(s, offset);
216
if (l1_index >= s->l1_size) {
217
- type = QCOW2_CLUSTER_UNALLOCATED;
218
+ type = QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
219
goto out;
220
}
221
222
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
223
if (!l2_offset) {
224
- type = QCOW2_CLUSTER_UNALLOCATED;
225
+ type = QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
226
goto out;
227
}
228
229
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
230
/* find the cluster offset for the given disk offset */
231
232
l2_index = offset_to_l2_slice_index(s, offset);
233
+ sc_index = offset_to_sc_index(s, offset);
234
l2_entry = get_l2_entry(s, l2_slice, l2_index);
235
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
236
237
nb_clusters = size_to_clusters(s, bytes_needed);
238
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
239
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
240
* true */
241
assert(nb_clusters <= INT_MAX);
242
243
- type = qcow2_get_cluster_type(bs, l2_entry);
244
- if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||
245
- type == QCOW2_CLUSTER_ZERO_ALLOC)) {
246
+ type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);
247
+ if (s->qcow_version < 3 && (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
248
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC)) {
249
qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
250
" in pre-v3 image (L2 offset: %#" PRIx64
251
", L2 index: %#x)", l2_offset, l2_index);
252
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
253
goto fail;
254
}
255
switch (type) {
256
- case QCOW2_CLUSTER_COMPRESSED:
257
+ case QCOW2_SUBCLUSTER_INVALID:
258
+ break; /* This is handled by count_contiguous_subclusters() below */
259
+ case QCOW2_SUBCLUSTER_COMPRESSED:
260
if (has_data_file(bs)) {
261
qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster "
262
"entry found in image with external data "
263
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
264
ret = -EIO;
265
goto fail;
266
}
267
- /* Compressed clusters can only be processed one by one */
268
- c = 1;
269
*host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;
270
break;
271
- case QCOW2_CLUSTER_ZERO_PLAIN:
272
- case QCOW2_CLUSTER_UNALLOCATED:
273
- /* how many empty clusters ? */
274
- c = count_contiguous_clusters_unallocated(bs, nb_clusters,
275
- l2_slice, l2_index, type);
276
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
277
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
278
break;
279
- case QCOW2_CLUSTER_ZERO_ALLOC:
280
- case QCOW2_CLUSTER_NORMAL: {
281
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
282
+ case QCOW2_SUBCLUSTER_NORMAL:
283
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC: {
284
uint64_t host_cluster_offset = l2_entry & L2E_OFFSET_MASK;
285
*host_offset = host_cluster_offset + offset_in_cluster;
286
- /* how many allocated clusters ? */
287
- c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
288
- l2_slice, l2_index, QCOW_OFLAG_ZERO);
289
if (offset_into_cluster(s, host_cluster_offset)) {
290
qcow2_signal_corruption(bs, true, -1, -1,
291
"Cluster allocation offset %#"
292
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
293
abort();
294
}
295
296
+ sc = count_contiguous_subclusters(bs, nb_clusters, sc_index,
297
+ l2_slice, &l2_index);
298
+ if (sc < 0) {
299
+ qcow2_signal_corruption(bs, true, -1, -1, "Invalid cluster entry found "
300
+ " (L2 offset: %#" PRIx64 ", L2 index: %#x)",
301
+ l2_offset, l2_index);
302
+ ret = -EIO;
303
+ goto fail;
304
+ }
305
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
306
307
- bytes_available = (int64_t)c * s->cluster_size;
308
+ bytes_available = ((int64_t)sc + sc_index) << s->subcluster_bits;
309
310
out:
311
if (bytes_available > bytes_needed) {
312
@@ -XXX,XX +XXX,XX @@ out:
313
assert(bytes_available - offset_in_cluster <= UINT_MAX);
314
*bytes = bytes_available - offset_in_cluster;
315
316
- *subcluster_type = qcow2_cluster_to_subcluster_type(type);
317
+ *subcluster_type = type;
318
319
return 0;
320
321
--
322
2.26.2
323
324
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Starting from DISABLE and WRITE_ZEROES features, we use an array of
3
The QCOW_OFLAG_ZERO bit that indicates that a cluster reads as
4
VirtIOFeature (as virtio-net) to properly set the config size
4
zeroes is only used in standard L2 entries. Extended L2 entries use
5
depending on the features enabled.
5
individual 'all zeroes' bits for each subcluster.
6
6
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
This must be taken into account when updating the L2 entry and also
8
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
8
when deciding that an existing entry does not need to be updated.
9
Message-id: 20190221103314.58500-6-sgarzare@redhat.com
9
10
Message-Id: <20190221103314.58500-6-sgarzare@redhat.com>
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Message-Id: <b61d61606d8c9b367bd641ab37351ddb9172799a.1594396418.git.berto@igalia.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
15
---
13
include/hw/virtio/virtio-blk.h | 1 +
16
block/qcow2-cluster.c | 38 ++++++++++++++++++++------------------
14
hw/block/virtio-blk.c | 31 +++++++++++++++++++++++++------
17
1 file changed, 20 insertions(+), 18 deletions(-)
15
2 files changed, 26 insertions(+), 6 deletions(-)
16
18
17
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/virtio/virtio-blk.h
21
--- a/block/qcow2-cluster.c
20
+++ b/include/hw/virtio/virtio-blk.h
22
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ typedef struct VirtIOBlock {
23
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
22
bool dataplane_started;
24
int l2_index;
23
struct VirtIOBlockDataPlane *dataplane;
25
int ret;
24
uint64_t host_features;
26
int i;
25
+ size_t config_size;
27
- bool unmap = !!(flags & BDRV_REQ_MAY_UNMAP);
26
} VirtIOBlock;
28
27
29
ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
28
typedef struct VirtIOBlockReq {
30
if (ret < 0) {
29
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
31
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
30
index XXXXXXX..XXXXXXX 100644
32
assert(nb_clusters <= INT_MAX);
31
--- a/hw/block/virtio-blk.c
33
32
+++ b/hw/block/virtio-blk.c
34
for (i = 0; i < nb_clusters; i++) {
33
@@ -XXX,XX +XXX,XX @@
35
- uint64_t old_offset;
34
#include "hw/virtio/virtio-bus.h"
36
- QCow2ClusterType cluster_type;
35
#include "hw/virtio/virtio-access.h"
37
-
36
38
- old_offset = get_l2_entry(s, l2_slice, l2_index + i);
37
-/* We don't support discard yet, hide associated config fields. */
39
+ uint64_t old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
38
+/* Config size before the discard support (hide associated config fields) */
40
+ uint64_t old_l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
39
#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
41
+ QCow2ClusterType type = qcow2_get_cluster_type(bs, old_l2_entry);
40
max_discard_sectors)
42
+ bool unmap = (type == QCOW2_CLUSTER_COMPRESSED) ||
41
+/*
43
+ ((flags & BDRV_REQ_MAY_UNMAP) && qcow2_cluster_is_allocated(type));
42
+ * Starting from the discard feature, we can use this array to properly
44
+ uint64_t new_l2_entry = unmap ? 0 : old_l2_entry;
43
+ * set the config size depending on the features enabled.
45
+ uint64_t new_l2_bitmap = old_l2_bitmap;
44
+ */
45
+static VirtIOFeature feature_sizes[] = {
46
+ {.flags = 1ULL << VIRTIO_BLK_F_DISCARD,
47
+ .end = virtio_endof(struct virtio_blk_config, discard_sector_alignment)},
48
+ {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
49
+ .end = virtio_endof(struct virtio_blk_config, write_zeroes_may_unmap)},
50
+ {}
51
+};
52
+
46
+
53
+static void virtio_blk_set_config_size(VirtIOBlock *s, uint64_t host_features)
47
+ if (has_subclusters(s)) {
54
+{
48
+ new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES;
55
+ s->config_size = MAX(VIRTIO_BLK_CFG_SIZE,
49
+ } else {
56
+ virtio_feature_get_config_size(feature_sizes, host_features));
50
+ new_l2_entry |= QCOW_OFLAG_ZERO;
57
+
51
+ }
58
+ assert(s->config_size <= sizeof(struct virtio_blk_config));
52
59
+}
53
- /*
60
54
- * Minimize L2 changes if the cluster already reads back as
61
static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
55
- * zeroes with correct allocation.
62
VirtIOBlockReq *req)
56
- */
63
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
57
- cluster_type = qcow2_get_cluster_type(bs, old_offset);
64
blkcfg.alignment_offset = 0;
58
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN ||
65
blkcfg.wce = blk_enable_write_cache(s->blk);
59
- (cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) {
66
virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues);
60
+ if (old_l2_entry == new_l2_entry && old_l2_bitmap == new_l2_bitmap) {
67
- memcpy(config, &blkcfg, VIRTIO_BLK_CFG_SIZE);
61
continue;
68
- QEMU_BUILD_BUG_ON(VIRTIO_BLK_CFG_SIZE > sizeof(blkcfg));
62
}
69
+ memcpy(config, &blkcfg, s->config_size);
63
70
}
64
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
71
65
- if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
72
static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
66
- set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
73
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
67
- qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
74
VirtIOBlock *s = VIRTIO_BLK(vdev);
68
- } else {
75
struct virtio_blk_config blkcfg;
69
- uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
76
70
- set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO);
77
- memcpy(&blkcfg, config, VIRTIO_BLK_CFG_SIZE);
71
+ if (unmap) {
78
- QEMU_BUILD_BUG_ON(VIRTIO_BLK_CFG_SIZE > sizeof(blkcfg));
72
+ qcow2_free_any_clusters(bs, old_l2_entry, 1, QCOW2_DISCARD_REQUEST);
79
+ memcpy(&blkcfg, config, s->config_size);
73
+ }
80
74
+ set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry);
81
aio_context_acquire(blk_get_aio_context(s->blk));
75
+ if (has_subclusters(s)) {
82
blk_set_enable_write_cache(s->blk, blkcfg.wce != 0);
76
+ set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
83
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
77
}
84
return;
85
}
78
}
86
79
87
- virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, VIRTIO_BLK_CFG_SIZE);
88
+ virtio_blk_set_config_size(s, s->host_features);
89
+
90
+ virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size);
91
92
s->blk = conf->conf.blk;
93
s->rq = NULL;
94
--
80
--
95
2.20.1
81
2.26.2
96
82
97
83
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
Two things need to be taken into account here:
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
5
4
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
1) With full_discard == true the L2 entry must be cleared completely.
6
This also includes the L2 bitmap if the image has extended L2
7
entries.
8
9
2) With full_discard == false we have to make the discarded cluster
10
read back as zeroes. With normal L2 entries this is done with the
11
QCOW_OFLAG_ZERO bit, whereas with extended L2 entries this is done
12
with the individual 'all zeroes' bits for each subcluster.
13
14
Note however that QCOW_OFLAG_ZERO is not supported in v2 qcow2
15
images so, if there is a backing file, discard cannot guarantee
16
that the image will read back as zeroes. If this is important for
17
the caller it should forbid it as qcow2_co_pdiscard() does (see
18
80f5c01183 for more details).
19
20
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-9-vsementsov@virtuozzo.com
23
Message-Id: <5ef8274e628aa3ab559bfac467abf488534f2b76.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-9-vsementsov@virtuozzo.com>
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
25
---
13
block/qcow.c | 21 ++++-----------------
26
block/qcow2-cluster.c | 52 +++++++++++++++++++------------------------
14
1 file changed, 4 insertions(+), 17 deletions(-)
27
1 file changed, 23 insertions(+), 29 deletions(-)
15
28
16
diff --git a/block/qcow.c b/block/qcow.c
29
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow.c
31
--- a/block/qcow2-cluster.c
19
+++ b/block/qcow.c
32
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,
33
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
21
int offset_in_cluster;
34
assert(nb_clusters <= INT_MAX);
22
int ret = 0, n;
35
23
uint64_t cluster_offset;
36
for (i = 0; i < nb_clusters; i++) {
24
- struct iovec hd_iov;
37
- uint64_t old_l2_entry;
25
QEMUIOVector hd_qiov;
38
-
26
uint8_t *buf;
39
- old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
27
void *orig_buf;
40
+ uint64_t old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
28
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,
41
+ uint64_t old_l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
29
if (!cluster_offset) {
42
+ uint64_t new_l2_entry = old_l2_entry;
30
if (bs->backing) {
43
+ uint64_t new_l2_bitmap = old_l2_bitmap;
31
/* read from the base image */
44
+ QCow2ClusterType cluster_type =
32
- hd_iov.iov_base = (void *)buf;
45
+ qcow2_get_cluster_type(bs, old_l2_entry);
33
- hd_iov.iov_len = n;
46
34
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
47
/*
35
+ qemu_iovec_init_buf(&hd_qiov, buf, n);
48
+ * If full_discard is true, the cluster should not read back as zeroes,
36
qemu_co_mutex_unlock(&s->lock);
49
+ * but rather fall through to the backing file.
37
/* qcow2 emits this on bs->file instead of bs->backing */
50
+ *
38
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
51
* If full_discard is false, make sure that a discarded area reads back
39
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,
52
* as zeroes for v3 images (we cannot do it for v2 without actually
40
ret = -EIO;
53
* writing a zero-filled buffer). We can skip the operation if the
41
break;
54
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
55
*
56
* TODO We might want to use bdrv_block_status(bs) here, but we're
57
* holding s->lock, so that doesn't work today.
58
- *
59
- * If full_discard is true, the sector should not read back as zeroes,
60
- * but rather fall through to the backing file.
61
*/
62
- switch (qcow2_get_cluster_type(bs, old_l2_entry)) {
63
- case QCOW2_CLUSTER_UNALLOCATED:
64
- if (full_discard || !bs->backing) {
65
- continue;
66
- }
67
- break;
68
-
69
- case QCOW2_CLUSTER_ZERO_PLAIN:
70
- if (!full_discard) {
71
- continue;
72
+ if (full_discard) {
73
+ new_l2_entry = new_l2_bitmap = 0;
74
+ } else if (bs->backing || qcow2_cluster_is_allocated(cluster_type)) {
75
+ if (has_subclusters(s)) {
76
+ new_l2_entry = 0;
77
+ new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES;
78
+ } else {
79
+ new_l2_entry = s->qcow_version >= 3 ? QCOW_OFLAG_ZERO : 0;
42
}
80
}
43
- hd_iov.iov_base = (void *)buf;
81
- break;
44
- hd_iov.iov_len = n;
82
-
45
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
83
- case QCOW2_CLUSTER_ZERO_ALLOC:
46
+ qemu_iovec_init_buf(&hd_qiov, buf, n);
84
- case QCOW2_CLUSTER_NORMAL:
47
qemu_co_mutex_unlock(&s->lock);
85
- case QCOW2_CLUSTER_COMPRESSED:
48
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
86
- break;
49
ret = bdrv_co_preadv(bs->file, cluster_offset + offset_in_cluster,
87
+ }
50
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset,
88
51
int offset_in_cluster;
89
- default:
52
uint64_t cluster_offset;
90
- abort();
53
int ret = 0, n;
91
+ if (old_l2_entry == new_l2_entry && old_l2_bitmap == new_l2_bitmap) {
54
- struct iovec hd_iov;
92
+ continue;
55
QEMUIOVector hd_qiov;
56
uint8_t *buf;
57
void *orig_buf;
58
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset,
59
}
60
}
93
}
61
94
62
- hd_iov.iov_base = (void *)buf;
95
/* First remove L2 entries */
63
- hd_iov.iov_len = n;
96
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
64
- qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
97
- if (!full_discard && s->qcow_version >= 3) {
65
+ qemu_iovec_init_buf(&hd_qiov, buf, n);
98
- set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
66
qemu_co_mutex_unlock(&s->lock);
99
- } else {
67
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
100
- set_l2_entry(s, l2_slice, l2_index + i, 0);
68
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
101
+ set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry);
69
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
102
+ if (has_subclusters(s)) {
70
{
103
+ set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
71
BDRVQcowState *s = bs->opaque;
104
}
72
QEMUIOVector hd_qiov;
105
-
73
- struct iovec iov;
106
/* Then decrease the refcount */
74
z_stream strm;
107
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
75
int ret, out_len;
76
uint8_t *buf, *out_buf;
77
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
78
}
108
}
79
cluster_offset &= s->cluster_offset_mask;
80
81
- iov = (struct iovec) {
82
- .iov_base = out_buf,
83
- .iov_len = out_len,
84
- };
85
- qemu_iovec_init_external(&hd_qiov, &iov, 1);
86
+ qemu_iovec_init_buf(&hd_qiov, out_buf, out_len);
87
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
88
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
89
if (ret < 0) {
90
--
109
--
91
2.20.1
110
2.26.2
92
111
93
112
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
The offset field of an uncompressed cluster's L2 entry must be aligned
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
to the cluster size, otherwise it is invalid. If the cluster has no
5
data then it means that the offset points to a preallocation, so we
6
can clear the offset field without affecting the guest-visible data.
7
This is what 'qemu-img check' does when run in repair mode.
5
8
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
On traditional qcow2 images this can only happen when QCOW_OFLAG_ZERO
7
Reviewed-by: Eric Blake <eblake@redhat.com>
10
is set, and repairing such entries turns the clusters from ZERO_ALLOC
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
into ZERO_PLAIN.
9
Message-id: 20190218140926.333779-12-vsementsov@virtuozzo.com
12
10
Message-Id: <20190218140926.333779-12-vsementsov@virtuozzo.com>
13
Extended L2 entries have no ZERO_ALLOC clusters and no QCOW_OFLAG_ZERO
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
but the idea is the same: if none of the subclusters are allocated
15
then we can clear the offset field and leave the bitmap untouched.
16
17
Signed-off-by: Alberto Garcia <berto@igalia.com>
18
Reviewed-by: Max Reitz <mreitz@redhat.com>
19
Message-Id: <9f4ed1d0a34b0a545b032c31ecd8c14734065342.1594396418.git.berto@igalia.com>
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
21
---
13
block/vmdk.c | 7 +------
22
block/qcow2-refcount.c | 16 +++++++++++-----
14
1 file changed, 1 insertion(+), 6 deletions(-)
23
tests/qemu-iotests/060.out | 2 +-
24
2 files changed, 12 insertions(+), 6 deletions(-)
15
25
16
diff --git a/block/vmdk.c b/block/vmdk.c
26
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
17
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
18
--- a/block/vmdk.c
28
--- a/block/qcow2-refcount.c
19
+++ b/block/vmdk.c
29
+++ b/block/qcow2-refcount.c
20
@@ -XXX,XX +XXX,XX @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
30
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
21
VmdkGrainMarker *data = NULL;
31
22
uLongf buf_len;
32
/* Correct offsets are cluster aligned */
23
QEMUIOVector local_qiov;
33
if (offset_into_cluster(s, offset)) {
24
- struct iovec iov;
34
+ bool contains_data;
25
int64_t write_offset;
35
res->corruptions++;
26
int64_t write_end_sector;
36
27
37
- if (qcow2_get_cluster_type(bs, l2_entry) ==
28
@@ -XXX,XX +XXX,XX @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
38
- QCOW2_CLUSTER_ZERO_ALLOC)
29
data->size = cpu_to_le32(buf_len);
39
- {
30
40
- fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
31
n_bytes = buf_len + sizeof(VmdkGrainMarker);
41
+ if (has_subclusters(s)) {
32
- iov = (struct iovec) {
42
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i);
33
- .iov_base = data,
43
+ contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC);
34
- .iov_len = n_bytes,
44
+ } else {
35
- };
45
+ contains_data = !(l2_entry & QCOW_OFLAG_ZERO);
36
- qemu_iovec_init_external(&local_qiov, &iov, 1);
46
+ }
37
+ qemu_iovec_init_buf(&local_qiov, data, n_bytes);
47
+
38
48
+ if (!contains_data) {
39
BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
49
+ fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated "
40
} else {
50
"cluster is not properly aligned; L2 entry "
51
"corrupted.\n",
52
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
53
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
54
int ign = active ? QCOW2_OL_ACTIVE_L2 :
55
QCOW2_OL_INACTIVE_L2;
56
57
- l2_entry = QCOW_OFLAG_ZERO;
58
+ l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
59
set_l2_entry(s, l2_table, i, l2_entry);
60
ret = qcow2_pre_write_overlap_check(bs, ign,
61
l2e_offset, l2_entry_size(s), false);
62
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
63
index XXXXXXX..XXXXXXX 100644
64
--- a/tests/qemu-iotests/060.out
65
+++ b/tests/qemu-iotests/060.out
66
@@ -XXX,XX +XXX,XX @@ discard 65536/65536 bytes at offset 0
67
qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 unaligned (guest offset: 0); further corruption events will be suppressed
68
write failed: Input/output error
69
--- Repairing ---
70
-Repairing offset=2a00: Preallocated zero cluster is not properly aligned; L2 entry corrupted.
71
+Repairing offset=2a00: Preallocated cluster is not properly aligned; L2 entry corrupted.
72
The following inconsistencies were found and repaired:
73
74
0 leaked clusters
41
--
75
--
42
2.20.1
76
2.26.2
43
77
44
78
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new QEMU_IOVEC_INIT_BUF() instead of
3
The L2 bitmap needs to be updated after each write to indicate what
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
new subclusters are now allocated. This needs to happen even if the
5
cluster was already allocated and the L2 entry was otherwise valid.
5
6
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
In some cases however a write operation doesn't need change the L2
8
bitmap (because all affected subclusters were already allocated). This
9
is detected in calculate_l2_meta(), and qcow2_alloc_cluster_link_l2()
10
is never called in those cases.
11
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-7-vsementsov@virtuozzo.com
15
Message-Id: <0875620d49f44320334b6a91c73b3f301f975f38.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-7-vsementsov@virtuozzo.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
17
---
13
block/stream.c | 7 +------
18
block/qcow2-cluster.c | 18 ++++++++++++++++++
14
1 file changed, 1 insertion(+), 6 deletions(-)
19
1 file changed, 18 insertions(+)
15
20
16
diff --git a/block/stream.c b/block/stream.c
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
18
--- a/block/stream.c
23
--- a/block/qcow2-cluster.c
19
+++ b/block/stream.c
24
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_populate(BlockBackend *blk,
25
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
21
int64_t offset, uint64_t bytes,
26
assert((offset & L2E_OFFSET_MASK) == offset);
22
void *buf)
27
23
{
28
set_l2_entry(s, l2_slice, l2_index + i, offset | QCOW_OFLAG_COPIED);
24
- struct iovec iov = {
29
+
25
- .iov_base = buf,
30
+ /* Update bitmap with the subclusters that were just written */
26
- .iov_len = bytes,
31
+ if (has_subclusters(s)) {
27
- };
32
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
28
- QEMUIOVector qiov;
33
+ unsigned written_from = m->cow_start.offset;
29
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
34
+ unsigned written_to = m->cow_end.offset + m->cow_end.nb_bytes ?:
30
35
+ m->nb_clusters << s->cluster_bits;
31
assert(bytes < SIZE_MAX);
36
+ int first_sc, last_sc;
32
- qemu_iovec_init_external(&qiov, &iov, 1);
37
+ /* Narrow written_from and written_to down to the current cluster */
33
38
+ written_from = MAX(written_from, i << s->cluster_bits);
34
/* Copy-on-read the unallocated clusters */
39
+ written_to = MIN(written_to, (i + 1) << s->cluster_bits);
35
return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ);
40
+ assert(written_from < written_to);
41
+ first_sc = offset_to_sc_index(s, written_from);
42
+ last_sc = offset_to_sc_index(s, written_to - 1);
43
+ l2_bitmap |= QCOW_OFLAG_SUB_ALLOC_RANGE(first_sc, last_sc + 1);
44
+ l2_bitmap &= ~QCOW_OFLAG_SUB_ZERO_RANGE(first_sc, last_sc + 1);
45
+ set_l2_bitmap(s, l2_slice, l2_index + i, l2_bitmap);
46
+ }
47
}
48
49
36
--
50
--
37
2.20.1
51
2.26.2
38
52
39
53
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new QEMU_IOVEC_INIT_BUF() instead of
3
Compressed clusters always have the bitmap part of the extended L2
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
entry set to 0.
5
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <04455b3de5dfeb9d1cfe1fc7b02d7060a6e09710.1594396418.git.berto@igalia.com>
9
Message-id: 20190218140926.333779-6-vsementsov@virtuozzo.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <20190218140926.333779-6-vsementsov@virtuozzo.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
10
---
13
block/commit.c | 7 +------
11
block/qcow2-cluster.c | 3 +++
14
1 file changed, 1 insertion(+), 6 deletions(-)
12
1 file changed, 3 insertions(+)
15
13
16
diff --git a/block/commit.c b/block/commit.c
14
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/block/commit.c
16
--- a/block/qcow2-cluster.c
19
+++ b/block/commit.c
17
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
18
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
21
void *buf)
19
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
22
{
20
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
23
int ret = 0;
21
set_l2_entry(s, l2_slice, l2_index, cluster_offset);
24
- QEMUIOVector qiov;
22
+ if (has_subclusters(s)) {
25
- struct iovec iov = {
23
+ set_l2_bitmap(s, l2_slice, l2_index, 0);
26
- .iov_base = buf,
24
+ }
27
- .iov_len = bytes,
25
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
28
- };
26
29
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
27
*host_offset = cluster_offset & s->cluster_offset_mask;
30
31
assert(bytes < SIZE_MAX);
32
- qemu_iovec_init_external(&qiov, &iov, 1);
33
34
ret = blk_co_preadv(bs, offset, qiov.size, &qiov, 0);
35
if (ret < 0) {
36
--
28
--
37
2.20.1
29
2.26.2
38
30
39
31
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new QEMU_IOVEC_INIT_BUF() instead of
3
The bdrv_co_pwrite_zeroes() call here fills complete clusters with
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
zeroes, but it can happen that some subclusters are not part of the
5
write request or the copy-on-write. This patch makes sure that only
6
the affected subclusters are overwritten.
5
7
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
A potential improvement would be to also fill with zeroes the other
7
Reviewed-by: Eric Blake <eblake@redhat.com>
9
subclusters if we can guarantee that we are not overwriting existing
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
data. However this would waste more disk space, so we should first
9
Message-id: 20190218140926.333779-8-vsementsov@virtuozzo.com
11
evaluate if it's really worth doing.
10
Message-Id: <20190218140926.333779-8-vsementsov@virtuozzo.com>
12
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-Id: <b3dc97e8e2240ddb5191a4f930e8fc9653f94621.1594396418.git.berto@igalia.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
18
---
13
block/parallels.c | 13 +++++--------
19
block/qcow2.c | 9 +++++----
14
1 file changed, 5 insertions(+), 8 deletions(-)
20
1 file changed, 5 insertions(+), 4 deletions(-)
15
21
16
diff --git a/block/parallels.c b/block/parallels.c
22
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
18
--- a/block/parallels.c
24
--- a/block/qcow2.c
19
+++ b/block/parallels.c
25
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
26
@@ -XXX,XX +XXX,XX @@ static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
21
if (bs->backing) {
27
22
int64_t nb_cow_sectors = to_allocate * s->tracks;
28
for (m = l2meta; m != NULL; m = m->next) {
23
int64_t nb_cow_bytes = nb_cow_sectors << BDRV_SECTOR_BITS;
29
int ret;
24
- QEMUIOVector qiov;
30
+ uint64_t start_offset = m->alloc_offset + m->cow_start.offset;
25
- struct iovec iov = {
31
+ unsigned nb_bytes = m->cow_end.offset + m->cow_end.nb_bytes -
26
- .iov_len = nb_cow_bytes,
32
+ m->cow_start.offset;
27
- .iov_base = qemu_blockalign(bs, nb_cow_bytes)
33
28
- };
34
if (!m->cow_start.nb_bytes && !m->cow_end.nb_bytes) {
29
- qemu_iovec_init_external(&qiov, &iov, 1);
35
continue;
30
+ QEMUIOVector qiov =
36
@@ -XXX,XX +XXX,XX @@ static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
31
+ QEMU_IOVEC_INIT_BUF(qiov, qemu_blockalign(bs, nb_cow_bytes),
37
* efficiently zero out the whole clusters
32
+ nb_cow_bytes);
38
*/
33
39
34
ret = bdrv_co_preadv(bs->backing, idx * s->tracks * BDRV_SECTOR_SIZE,
40
- ret = qcow2_pre_write_overlap_check(bs, 0, m->alloc_offset,
35
nb_cow_bytes, &qiov, 0);
41
- m->nb_clusters * s->cluster_size,
36
if (ret < 0) {
42
+ ret = qcow2_pre_write_overlap_check(bs, 0, start_offset, nb_bytes,
37
- qemu_vfree(iov.iov_base);
43
true);
38
+ qemu_vfree(qemu_iovec_buf(&qiov));
39
return ret;
40
}
41
42
ret = bdrv_co_pwritev(bs->file, s->data_end * BDRV_SECTOR_SIZE,
43
nb_cow_bytes, &qiov, 0);
44
- qemu_vfree(iov.iov_base);
45
+ qemu_vfree(qemu_iovec_buf(&qiov));
46
if (ret < 0) {
44
if (ret < 0) {
47
return ret;
45
return ret;
48
}
46
}
47
48
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
49
- ret = bdrv_co_pwrite_zeroes(s->data_file, m->alloc_offset,
50
- m->nb_clusters * s->cluster_size,
51
+ ret = bdrv_co_pwrite_zeroes(s->data_file, start_offset, nb_bytes,
52
BDRV_REQ_NO_FALLBACK);
53
if (ret < 0) {
54
if (ret != -ENOTSUP && ret != -EAGAIN) {
49
--
55
--
50
2.20.1
56
2.26.2
51
57
52
58
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
This works now at the subcluster level and pwrite_zeroes_alignment is
4
updated accordingly.
5
6
qcow2_cluster_zeroize() is turned into qcow2_subcluster_zeroize() with
7
the following changes:
8
9
- The request can now be subcluster-aligned.
10
11
- The cluster-aligned body of the request is still zeroized using
12
zero_in_l2_slice() as before.
13
14
- The subcluster-aligned head and tail of the request are zeroized
15
with the new zero_l2_subclusters() function.
16
17
There is just one thing to take into account for a possible future
18
improvement: compressed clusters cannot be partially zeroized so
19
zero_l2_subclusters() on the head or the tail can return -ENOTSUP.
20
This makes the caller repeat the *complete* request and write actual
21
zeroes to disk. This is sub-optimal because
22
23
1) if the head area was compressed we would still be able to use
24
the fast path for the body and possibly the tail.
25
26
2) if the tail area was compressed we are writing zeroes to the
27
head and the body areas, which are already zeroized.
28
29
Signed-off-by: Alberto Garcia <berto@igalia.com>
30
Reviewed-by: Max Reitz <mreitz@redhat.com>
31
Message-Id: <17e05e2ee7e12f10dcf012da81e83ebe27eb3bef.1594396418.git.berto@igalia.com>
32
Signed-off-by: Max Reitz <mreitz@redhat.com>
33
---
34
block/qcow2.h | 4 +--
35
block/qcow2-cluster.c | 81 +++++++++++++++++++++++++++++++++++++++----
36
block/qcow2.c | 33 +++++++++---------
37
3 files changed, 94 insertions(+), 24 deletions(-)
38
39
diff --git a/block/qcow2.h b/block/qcow2.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/qcow2.h
42
+++ b/block/qcow2.h
43
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
44
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
45
uint64_t bytes, enum qcow2_discard_type type,
46
bool full_discard);
47
-int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
48
- uint64_t bytes, int flags);
49
+int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,
50
+ uint64_t bytes, int flags);
51
52
int qcow2_expand_zero_clusters(BlockDriverState *bs,
53
BlockDriverAmendStatusCB *status_cb,
54
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/qcow2-cluster.c
57
+++ b/block/qcow2-cluster.c
58
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
59
return nb_clusters;
60
}
61
62
-int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
63
- uint64_t bytes, int flags)
64
+static int zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
65
+ unsigned nb_subclusters)
66
+{
67
+ BDRVQcow2State *s = bs->opaque;
68
+ uint64_t *l2_slice;
69
+ uint64_t old_l2_bitmap, l2_bitmap;
70
+ int l2_index, ret, sc = offset_to_sc_index(s, offset);
71
+
72
+ /* For full clusters use zero_in_l2_slice() instead */
73
+ assert(nb_subclusters > 0 && nb_subclusters < s->subclusters_per_cluster);
74
+ assert(sc + nb_subclusters <= s->subclusters_per_cluster);
75
+ assert(offset_into_subcluster(s, offset) == 0);
76
+
77
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
78
+ if (ret < 0) {
79
+ return ret;
80
+ }
81
+
82
+ switch (qcow2_get_cluster_type(bs, get_l2_entry(s, l2_slice, l2_index))) {
83
+ case QCOW2_CLUSTER_COMPRESSED:
84
+ ret = -ENOTSUP; /* We cannot partially zeroize compressed clusters */
85
+ goto out;
86
+ case QCOW2_CLUSTER_NORMAL:
87
+ case QCOW2_CLUSTER_UNALLOCATED:
88
+ break;
89
+ default:
90
+ g_assert_not_reached();
91
+ }
92
+
93
+ old_l2_bitmap = l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
94
+
95
+ l2_bitmap |= QCOW_OFLAG_SUB_ZERO_RANGE(sc, sc + nb_subclusters);
96
+ l2_bitmap &= ~QCOW_OFLAG_SUB_ALLOC_RANGE(sc, sc + nb_subclusters);
97
+
98
+ if (old_l2_bitmap != l2_bitmap) {
99
+ set_l2_bitmap(s, l2_slice, l2_index, l2_bitmap);
100
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
101
+ }
102
+
103
+ ret = 0;
104
+out:
105
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
106
+
107
+ return ret;
108
+}
109
+
110
+int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,
111
+ uint64_t bytes, int flags)
112
{
113
BDRVQcow2State *s = bs->opaque;
114
uint64_t end_offset = offset + bytes;
115
uint64_t nb_clusters;
116
+ unsigned head, tail;
117
int64_t cleared;
118
int ret;
119
120
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
121
}
122
123
/* Caller must pass aligned values, except at image end */
124
- assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
125
- assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
126
+ assert(offset_into_subcluster(s, offset) == 0);
127
+ assert(offset_into_subcluster(s, end_offset) == 0 ||
128
end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
129
130
/*
131
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
132
return -ENOTSUP;
133
}
134
135
- /* Each L2 slice is handled by its own loop iteration */
136
- nb_clusters = size_to_clusters(s, bytes);
137
+ head = MIN(end_offset, ROUND_UP(offset, s->cluster_size)) - offset;
138
+ offset += head;
139
+
140
+ tail = (end_offset >= bs->total_sectors << BDRV_SECTOR_BITS) ? 0 :
141
+ end_offset - MAX(offset, start_of_cluster(s, end_offset));
142
+ end_offset -= tail;
143
144
s->cache_discards = true;
145
146
+ if (head) {
147
+ ret = zero_l2_subclusters(bs, offset - head,
148
+ size_to_subclusters(s, head));
149
+ if (ret < 0) {
150
+ goto fail;
151
+ }
152
+ }
153
+
154
+ /* Each L2 slice is handled by its own loop iteration */
155
+ nb_clusters = size_to_clusters(s, end_offset - offset);
156
+
157
while (nb_clusters > 0) {
158
cleared = zero_in_l2_slice(bs, offset, nb_clusters, flags);
159
if (cleared < 0) {
160
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
161
offset += (cleared * s->cluster_size);
162
}
163
164
+ if (tail) {
165
+ ret = zero_l2_subclusters(bs, end_offset, size_to_subclusters(s, tail));
166
+ if (ret < 0) {
167
+ goto fail;
168
+ }
169
+ }
170
+
171
ret = 0;
172
fail:
173
s->cache_discards = false;
174
diff --git a/block/qcow2.c b/block/qcow2.c
175
index XXXXXXX..XXXXXXX 100644
176
--- a/block/qcow2.c
177
+++ b/block/qcow2.c
178
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
179
/* Encryption works on a sector granularity */
180
bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto);
181
}
182
- bs->bl.pwrite_zeroes_alignment = s->cluster_size;
183
+ bs->bl.pwrite_zeroes_alignment = s->subcluster_size;
184
bs->bl.pdiscard_alignment = s->cluster_size;
185
}
186
187
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
188
int ret;
189
BDRVQcow2State *s = bs->opaque;
190
191
- uint32_t head = offset % s->cluster_size;
192
- uint32_t tail = (offset + bytes) % s->cluster_size;
193
+ uint32_t head = offset_into_subcluster(s, offset);
194
+ uint32_t tail = ROUND_UP(offset + bytes, s->subcluster_size) -
195
+ (offset + bytes);
196
197
trace_qcow2_pwrite_zeroes_start_req(qemu_coroutine_self(), offset, bytes);
198
if (offset + bytes == bs->total_sectors * BDRV_SECTOR_SIZE) {
199
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
200
unsigned int nr;
201
QCow2SubclusterType type;
202
203
- assert(head + bytes <= s->cluster_size);
204
+ assert(head + bytes + tail <= s->subcluster_size);
205
206
/* check whether remainder of cluster already reads as zero */
207
if (!(is_zero(bs, offset - head, head) &&
208
- is_zero(bs, offset + bytes,
209
- tail ? s->cluster_size - tail : 0))) {
210
+ is_zero(bs, offset + bytes, tail))) {
211
return -ENOTSUP;
212
}
213
214
qemu_co_mutex_lock(&s->lock);
215
/* We can have new write after previous check */
216
- offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
217
- bytes = s->cluster_size;
218
- nr = s->cluster_size;
219
+ offset -= head;
220
+ bytes = s->subcluster_size;
221
+ nr = s->subcluster_size;
222
ret = qcow2_get_host_offset(bs, offset, &nr, &off, &type);
223
if (ret < 0 ||
224
(type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
225
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
226
227
trace_qcow2_pwrite_zeroes(qemu_coroutine_self(), offset, bytes);
228
229
- /* Whatever is left can use real zero clusters */
230
- ret = qcow2_cluster_zeroize(bs, offset, bytes, flags);
231
+ /* Whatever is left can use real zero subclusters */
232
+ ret = qcow2_subcluster_zeroize(bs, offset, bytes, flags);
233
qemu_co_mutex_unlock(&s->lock);
234
235
return ret;
236
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
237
}
238
239
if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
240
- uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
241
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->subcluster_size);
242
243
/*
244
- * Use zero clusters as much as we can. qcow2_cluster_zeroize()
245
- * requires a cluster-aligned start. The end may be unaligned if it is
246
- * at the end of the image (which it is here).
247
+ * Use zero clusters as much as we can. qcow2_subcluster_zeroize()
248
+ * requires a subcluster-aligned start. The end may be unaligned if
249
+ * it is at the end of the image (which it is here).
250
*/
251
if (offset > zero_start) {
252
- ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
253
+ ret = qcow2_subcluster_zeroize(bs, zero_start, offset - zero_start,
254
+ 0);
255
if (ret < 0) {
256
error_setg_errno(errp, -ret, "Failed to zero out new clusters");
257
goto fail;
258
--
259
2.26.2
260
261
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
Extended L2 entries are bigger than normal L2 entries so this has an
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
impact on the amount of metadata needed for a qcow2 file.
5
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <7efae2efd5e36b42d2570743a12576d68ce53685.1594396418.git.berto@igalia.com>
9
Message-id: 20190218140926.333779-11-vsementsov@virtuozzo.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <20190218140926.333779-11-vsementsov@virtuozzo.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
10
---
13
block/qed-table.c | 16 +++-------------
11
block/qcow2.c | 20 +++++++++++++-------
14
block/qed.c | 31 +++++++++----------------------
12
1 file changed, 13 insertions(+), 7 deletions(-)
15
2 files changed, 12 insertions(+), 35 deletions(-)
16
13
17
diff --git a/block/qed-table.c b/block/qed-table.c
14
diff --git a/block/qcow2.c b/block/qcow2.c
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qed-table.c
16
--- a/block/qcow2.c
20
+++ b/block/qed-table.c
17
+++ b/block/qcow2.c
21
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
22
/* Called with table_lock held. */
19
* @total_size: virtual disk size in bytes
23
static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
20
* @cluster_size: cluster size in bytes
21
* @refcount_order: refcount bits power-of-2 exponent
22
+ * @extended_l2: true if the image has extended L2 entries
23
*
24
* Returns: Total number of bytes required for the fully allocated image
25
* (including metadata).
26
*/
27
static int64_t qcow2_calc_prealloc_size(int64_t total_size,
28
size_t cluster_size,
29
- int refcount_order)
30
+ int refcount_order,
31
+ bool extended_l2)
24
{
32
{
25
- QEMUIOVector qiov;
33
int64_t meta_size = 0;
26
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(
34
uint64_t nl1e, nl2e;
27
+ qiov, table->offsets, s->header.cluster_size * s->header.table_size);
35
int64_t aligned_total_size = ROUND_UP(total_size, cluster_size);
28
int noffsets;
36
+ size_t l2e_size = extended_l2 ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
29
int i, ret;
37
30
38
/* header: 1 cluster */
31
- struct iovec iov = {
39
meta_size += cluster_size;
32
- .iov_base = table->offsets,
40
33
- .iov_len = s->header.cluster_size * s->header.table_size,
41
/* total size of L2 tables */
34
- };
42
nl2e = aligned_total_size / cluster_size;
35
- qemu_iovec_init_external(&qiov, &iov, 1);
43
- nl2e = ROUND_UP(nl2e, cluster_size / sizeof(uint64_t));
36
-
44
- meta_size += nl2e * sizeof(uint64_t);
37
trace_qed_read_table(s, offset, table);
45
+ nl2e = ROUND_UP(nl2e, cluster_size / l2e_size);
38
46
+ meta_size += nl2e * l2e_size;
39
qemu_co_mutex_unlock(&s->table_lock);
47
40
@@ -XXX,XX +XXX,XX @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
48
/* total size of L1 tables */
41
unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
49
- nl1e = nl2e * sizeof(uint64_t) / cluster_size;
42
unsigned int start, end, i;
50
+ nl1e = nl2e * l2e_size / cluster_size;
43
QEDTable *new_table;
51
nl1e = ROUND_UP(nl1e, cluster_size / sizeof(uint64_t));
44
- struct iovec iov;
52
meta_size += nl1e * sizeof(uint64_t);
45
QEMUIOVector qiov;
53
46
size_t len_bytes;
54
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
47
int ret;
55
PreallocMode prealloc;
48
@@ -XXX,XX +XXX,XX @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
56
bool has_backing_file;
49
len_bytes = (end - start) * sizeof(uint64_t);
57
bool has_luks;
50
58
+ bool extended_l2 = false; /* Set to false until the option is added */
51
new_table = qemu_blockalign(s->bs, len_bytes);
59
+ size_t l2e_size;
52
- iov = (struct iovec) {
60
53
- .iov_base = new_table->offsets,
61
/* Parse image creation options */
54
- .iov_len = len_bytes,
62
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
55
- };
63
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
56
- qemu_iovec_init_external(&qiov, &iov, 1);
64
virtual_size = ROUND_UP(virtual_size, cluster_size);
57
+ qemu_iovec_init_buf(&qiov, new_table->offsets, len_bytes);
65
58
66
/* Check that virtual disk size is valid */
59
/* Byteswap table */
67
+ l2e_size = extended_l2 ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
60
for (i = start; i < end; i++) {
68
l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,
61
diff --git a/block/qed.c b/block/qed.c
69
- cluster_size / sizeof(uint64_t));
62
index XXXXXXX..XXXXXXX 100644
70
+ cluster_size / l2e_size);
63
--- a/block/qed.c
71
if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {
64
+++ b/block/qed.c
72
error_setg(&local_err, "The image size is too large "
65
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_write_header(BDRVQEDState *s)
73
"(try using a larger cluster size)");
66
int nsectors = DIV_ROUND_UP(sizeof(QEDHeader), BDRV_SECTOR_SIZE);
74
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
67
size_t len = nsectors * BDRV_SECTOR_SIZE;
68
uint8_t *buf;
69
- struct iovec iov;
70
QEMUIOVector qiov;
71
int ret;
72
73
assert(s->allocating_acb || s->allocating_write_reqs_plugged);
74
75
buf = qemu_blockalign(s->bs, len);
76
- iov = (struct iovec) {
77
- .iov_base = buf,
78
- .iov_len = len,
79
- };
80
- qemu_iovec_init_external(&qiov, &iov, 1);
81
+ qemu_iovec_init_buf(&qiov, buf, len);
82
83
ret = bdrv_co_preadv(s->bs->file, 0, qiov.size, &qiov, 0);
84
if (ret < 0) {
85
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
86
{
87
QEMUIOVector qiov;
88
QEMUIOVector *backing_qiov = NULL;
89
- struct iovec iov;
90
int ret;
91
92
/* Skip copy entirely if there is no work to do */
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
94
return 0;
95
}
75
}
96
76
97
- iov = (struct iovec) {
77
info = g_new0(BlockMeasureInfo, 1);
98
- .iov_base = qemu_blockalign(s->bs, len),
78
- info->fully_allocated =
99
- .iov_len = len,
79
+ info->fully_allocated = luks_payload_size +
100
- };
80
qcow2_calc_prealloc_size(virtual_size, cluster_size,
101
- qemu_iovec_init_external(&qiov, &iov, 1);
81
- ctz32(refcount_bits)) + luks_payload_size;
102
+ qemu_iovec_init_buf(&qiov, qemu_blockalign(s->bs, len), len);
82
+ ctz32(refcount_bits), extended_l2);
103
83
104
ret = qed_read_backing_file(s, pos, &qiov, &backing_qiov);
84
/*
105
85
* Remove data clusters that are not required. This overestimates the
106
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
107
}
108
ret = 0;
109
out:
110
- qemu_vfree(iov.iov_base);
111
+ qemu_vfree(qemu_iovec_buf(&qiov));
112
return ret;
113
}
114
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
116
BdrvRequestFlags flags)
117
{
118
BDRVQEDState *s = bs->opaque;
119
- QEMUIOVector qiov;
120
- struct iovec iov;
121
+
122
+ /*
123
+ * Zero writes start without an I/O buffer. If a buffer becomes necessary
124
+ * then it will be allocated during request processing.
125
+ */
126
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
127
128
/* Fall back if the request is not aligned */
129
if (qed_offset_into_cluster(s, offset) ||
130
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
131
return -ENOTSUP;
132
}
133
134
- /* Zero writes start without an I/O buffer. If a buffer becomes necessary
135
- * then it will be allocated during request processing.
136
- */
137
- iov.iov_base = NULL;
138
- iov.iov_len = bytes;
139
-
140
- qemu_iovec_init_external(&qiov, &iov, 1);
141
return qed_co_request(bs, offset >> BDRV_SECTOR_BITS, &qiov,
142
bytes >> BDRV_SECTOR_BITS,
143
QED_AIOCB_WRITE | QED_AIOCB_ZERO);
144
--
86
--
145
2.20.1
87
2.26.2
146
88
147
89
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
In order to avoid migration issues, we enable DISCARD and
3
This field allows us to indicate that the L2 metadata update does not
4
WRITE_ZEROES features only for machine type >= 4.0
4
come from a write request with actual data but from a preallocation
5
request.
5
6
6
As discussed with Michael S. Tsirkin and Stefan Hajnoczi on the
7
For traditional images this does not make any difference, but for
7
list [1], DISCARD operation should not have security implications
8
images with extended L2 entries this means that the clusters are
8
(eg. page cache attacks), so we can enable it by default.
9
allocated normally in the L2 table but individual subclusters are
10
marked as unallocated.
9
11
10
[1] https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg00504.html
12
This will allow preallocating images that have a backing file.
11
13
12
Suggested-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
14
There is one special case: when we resize an existing image we can
13
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
15
also request that the new clusters are preallocated. If the image
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
already had a backing file then we have to hide any possible stale
15
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
17
data and zero out the new clusters (see commit 955c7d6687 for more
16
Message-id: 20190221103314.58500-4-sgarzare@redhat.com
18
details).
17
Message-Id: <20190221103314.58500-4-sgarzare@redhat.com>
19
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
In this case the subclusters cannot be left as unallocated so the L2
21
bitmap must be updated.
22
23
Signed-off-by: Alberto Garcia <berto@igalia.com>
24
Reviewed-by: Eric Blake <eblake@redhat.com>
25
Reviewed-by: Max Reitz <mreitz@redhat.com>
26
Message-Id: <960d4c444a4f5a870e2b47e5da322a73cd9a2f5a.1594396418.git.berto@igalia.com>
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
28
---
20
hw/block/virtio-blk.c | 4 ++++
29
block/qcow2.h | 8 ++++++++
21
hw/core/machine.c | 2 ++
30
block/qcow2-cluster.c | 2 +-
22
2 files changed, 6 insertions(+)
31
block/qcow2.c | 6 ++++++
32
3 files changed, 15 insertions(+), 1 deletion(-)
23
33
24
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
34
diff --git a/block/qcow2.h b/block/qcow2.h
25
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/block/virtio-blk.c
36
--- a/block/qcow2.h
27
+++ b/hw/block/virtio-blk.c
37
+++ b/block/qcow2.h
28
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
38
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
29
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
39
*/
30
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
40
bool skip_cow;
31
IOThread *),
41
32
+ DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
42
+ /**
33
+ VIRTIO_BLK_F_DISCARD, true),
43
+ * Indicates that this is not a normal write request but a preallocation.
34
+ DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
44
+ * If the image has extended L2 entries this means that no new individual
35
+ VIRTIO_BLK_F_WRITE_ZEROES, true),
45
+ * subclusters will be marked as allocated in the L2 bitmap (but any
36
DEFINE_PROP_END_OF_LIST(),
46
+ * existing contents of that bitmap will be kept).
37
};
47
+ */
38
48
+ bool prealloc;
39
diff --git a/hw/core/machine.c b/hw/core/machine.c
49
+
50
/**
51
* The I/O vector with the data from the actual guest write request.
52
* If non-NULL, this is meant to be merged together with the data
53
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
40
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
41
--- a/hw/core/machine.c
55
--- a/block/qcow2-cluster.c
42
+++ b/hw/core/machine.c
56
+++ b/block/qcow2-cluster.c
43
@@ -XXX,XX +XXX,XX @@ GlobalProperty hw_compat_3_1[] = {
57
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
44
{ "usb-kbd", "serial", "42" },
58
set_l2_entry(s, l2_slice, l2_index + i, offset | QCOW_OFLAG_COPIED);
45
{ "usb-mouse", "serial", "42" },
59
46
{ "usb-kbd", "serial", "42" },
60
/* Update bitmap with the subclusters that were just written */
47
+ { "virtio-blk-device", "discard", "false" },
61
- if (has_subclusters(s)) {
48
+ { "virtio-blk-device", "write-zeroes", "false" },
62
+ if (has_subclusters(s) && !m->prealloc) {
49
};
63
uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
50
const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
64
unsigned written_from = m->cow_start.offset;
65
unsigned written_to = m->cow_end.offset + m->cow_end.nb_bytes ?:
66
diff --git a/block/qcow2.c b/block/qcow2.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block/qcow2.c
69
+++ b/block/qcow2.c
70
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
71
QCowL2Meta *next;
72
73
if (link_l2) {
74
+ assert(!l2meta->prealloc);
75
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
76
if (ret) {
77
goto out;
78
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
79
80
while (meta) {
81
QCowL2Meta *next = meta->next;
82
+ meta->prealloc = true;
83
84
ret = qcow2_alloc_cluster_link_l2(bs, meta);
85
if (ret < 0) {
86
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
87
int64_t clusters_allocated;
88
int64_t old_file_size, last_cluster, new_file_size;
89
uint64_t nb_new_data_clusters, nb_new_l2_tables;
90
+ bool subclusters_need_allocation = false;
91
92
/* With a data file, preallocation means just allocating the metadata
93
* and forwarding the truncate request to the data file */
94
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
95
BDRV_REQ_ZERO_WRITE, NULL);
96
if (ret >= 0) {
97
flags &= ~BDRV_REQ_ZERO_WRITE;
98
+ /* Ensure that we read zeroes and not backing file data */
99
+ subclusters_need_allocation = true;
100
}
101
} else {
102
ret = -1;
103
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
104
.offset = nb_clusters << s->cluster_bits,
105
.nb_bytes = 0,
106
},
107
+ .prealloc = !subclusters_need_allocation,
108
};
109
qemu_co_queue_init(&allocation.dependent_requests);
51
110
52
--
111
--
53
2.20.1
112
2.26.2
54
113
55
114
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
This patch adds the support of DISCARD and WRITE_ZEROES commands,
3
Now that the implementation of subclusters is complete we can finally
4
that have been introduced in the virtio-blk protocol to have
4
add the necessary options to create and read images with this feature,
5
better performance when using SSD backend.
5
which we call "extended L2 entries".
6
6
7
We support only one segment per request since multiple segments
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
are not widely used and there are no userspace APIs that allow
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
applications to submit multiple segments in a single call.
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-Id: <6476caaa73216bd05b7bb2d504a20415e1665176.1594396418.git.berto@igalia.com>
11
[mreitz: %s/5\.1/5.2/; fixed 302's and 303's reference output]
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
qapi/block-core.json | 7 +++
15
block/qcow2.h | 8 ++-
16
include/block/block_int.h | 1 +
17
block/qcow2.c | 66 ++++++++++++++++++--
18
tests/qemu-iotests/031.out | 8 +--
19
tests/qemu-iotests/036.out | 4 +-
20
tests/qemu-iotests/049.out | 102 +++++++++++++++----------------
21
tests/qemu-iotests/060.out | 1 +
22
tests/qemu-iotests/061.out | 20 +++---
23
tests/qemu-iotests/065 | 12 ++--
24
tests/qemu-iotests/082.out | 39 +++++++++---
25
tests/qemu-iotests/085.out | 38 ++++++------
26
tests/qemu-iotests/144.out | 4 +-
27
tests/qemu-iotests/182.out | 2 +-
28
tests/qemu-iotests/185.out | 8 +--
29
tests/qemu-iotests/198 | 2 +
30
tests/qemu-iotests/206.out | 4 ++
31
tests/qemu-iotests/242.out | 5 ++
32
tests/qemu-iotests/255.out | 8 +--
33
tests/qemu-iotests/274.out | 49 ++++++++-------
34
tests/qemu-iotests/280.out | 2 +-
35
tests/qemu-iotests/291.out | 2 +
36
tests/qemu-iotests/302.out | 1 +
37
tests/qemu-iotests/303.out | 4 +-
38
tests/qemu-iotests/common.filter | 1 +
39
25 files changed, 256 insertions(+), 142 deletions(-)
10
40
11
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
41
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
42
index XXXXXXX..XXXXXXX 100644
13
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
43
--- a/qapi/block-core.json
14
Message-id: 20190221103314.58500-7-sgarzare@redhat.com
44
+++ b/qapi/block-core.json
15
Message-Id: <20190221103314.58500-7-sgarzare@redhat.com>
45
@@ -XXX,XX +XXX,XX @@
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
46
# standalone (read-only) raw image without looking at qcow2
17
---
47
# metadata (since: 4.0)
18
include/hw/virtio/virtio-blk.h | 2 +
48
#
19
hw/block/virtio-blk.c | 184 +++++++++++++++++++++++++++++++++
49
+# @extended-l2: true if the image has extended L2 entries; only valid for
20
2 files changed, 186 insertions(+)
50
+# compat >= 1.1 (since 5.2)
21
51
+#
22
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
52
# @lazy-refcounts: on or off; only valid for compat >= 1.1
23
index XXXXXXX..XXXXXXX 100644
53
#
24
--- a/include/hw/virtio/virtio-blk.h
54
# @corrupt: true if the image has been marked corrupt; only valid for
25
+++ b/include/hw/virtio/virtio-blk.h
55
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
56
'compat': 'str',
27
uint32_t request_merging;
57
'*data-file': 'str',
28
uint16_t num_queues;
58
'*data-file-raw': 'bool',
29
uint16_t queue_size;
59
+ '*extended-l2': 'bool',
30
+ uint32_t max_discard_sectors;
60
'*lazy-refcounts': 'bool',
31
+ uint32_t max_write_zeroes_sectors;
61
'*corrupt': 'bool',
62
'refcount-bits': 'int',
63
@@ -XXX,XX +XXX,XX @@
64
# @data-file-raw: True if the external data file must stay valid as a
65
# standalone (read-only) raw image without looking at qcow2
66
# metadata (default: false; since: 4.0)
67
+# @extended-l2 True to make the image have extended L2 entries
68
+# (default: false; since 5.2)
69
# @size: Size of the virtual disk in bytes
70
# @version: Compatibility level (default: v3)
71
# @backing-file: File name of the backing file if a backing file
72
@@ -XXX,XX +XXX,XX @@
73
'data': { 'file': 'BlockdevRef',
74
'*data-file': 'BlockdevRef',
75
'*data-file-raw': 'bool',
76
+ '*extended-l2': 'bool',
77
'size': 'size',
78
'*version': 'BlockdevQcow2Version',
79
'*backing-file': 'str',
80
diff --git a/block/qcow2.h b/block/qcow2.h
81
index XXXXXXX..XXXXXXX 100644
82
--- a/block/qcow2.h
83
+++ b/block/qcow2.h
84
@@ -XXX,XX +XXX,XX @@ enum {
85
QCOW2_INCOMPAT_CORRUPT_BITNR = 1,
86
QCOW2_INCOMPAT_DATA_FILE_BITNR = 2,
87
QCOW2_INCOMPAT_COMPRESSION_BITNR = 3,
88
+ QCOW2_INCOMPAT_EXTL2_BITNR = 4,
89
QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
90
QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR,
91
QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR,
92
QCOW2_INCOMPAT_COMPRESSION = 1 << QCOW2_INCOMPAT_COMPRESSION_BITNR,
93
+ QCOW2_INCOMPAT_EXTL2 = 1 << QCOW2_INCOMPAT_EXTL2_BITNR,
94
95
QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY
96
| QCOW2_INCOMPAT_CORRUPT
97
| QCOW2_INCOMPAT_DATA_FILE
98
- | QCOW2_INCOMPAT_COMPRESSION,
99
+ | QCOW2_INCOMPAT_COMPRESSION
100
+ | QCOW2_INCOMPAT_EXTL2,
32
};
101
};
33
102
34
struct VirtIOBlockDataPlane;
103
/* Compatible feature bits */
35
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
104
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
36
index XXXXXXX..XXXXXXX 100644
105
37
--- a/hw/block/virtio-blk.c
106
static inline bool has_subclusters(BDRVQcow2State *s)
38
+++ b/hw/block/virtio-blk.c
107
{
39
@@ -XXX,XX +XXX,XX @@ out:
108
- /* FIXME: Return false until this feature is complete */
40
aio_context_release(blk_get_aio_context(s->conf.conf.blk));
109
- return false;
110
+ return s->incompatible_features & QCOW2_INCOMPAT_EXTL2;
41
}
111
}
42
112
43
+static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
113
static inline size_t l2_entry_size(BDRVQcow2State *s)
44
+{
114
diff --git a/include/block/block_int.h b/include/block/block_int.h
45
+ VirtIOBlockReq *req = opaque;
115
index XXXXXXX..XXXXXXX 100644
46
+ VirtIOBlock *s = req->dev;
116
--- a/include/block/block_int.h
47
+ bool is_write_zeroes = (virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type) &
117
+++ b/include/block/block_int.h
48
+ ~VIRTIO_BLK_T_BARRIER) == VIRTIO_BLK_T_WRITE_ZEROES;
118
@@ -XXX,XX +XXX,XX @@
119
#define BLOCK_OPT_DATA_FILE "data_file"
120
#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw"
121
#define BLOCK_OPT_COMPRESSION_TYPE "compression_type"
122
+#define BLOCK_OPT_EXTL2 "extended_l2"
123
124
#define BLOCK_PROBE_BUF_SIZE 512
125
126
diff --git a/block/qcow2.c b/block/qcow2.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/block/qcow2.c
129
+++ b/block/qcow2.c
130
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
131
s->subcluster_size = s->cluster_size / s->subclusters_per_cluster;
132
s->subcluster_bits = ctz32(s->subcluster_size);
133
134
+ if (s->subcluster_size < (1 << MIN_CLUSTER_BITS)) {
135
+ error_setg(errp, "Unsupported subcluster size: %d", s->subcluster_size);
136
+ ret = -EINVAL;
137
+ goto fail;
138
+ }
49
+
139
+
50
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
140
/* Check support for various header values */
51
+ if (ret) {
141
if (header.refcount_order > 6) {
52
+ if (virtio_blk_handle_rw_error(req, -ret, false, is_write_zeroes)) {
142
error_setg(errp, "Reference count entry width too large; may not "
143
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
144
.bit = QCOW2_INCOMPAT_COMPRESSION_BITNR,
145
.name = "compression type",
146
},
147
+ {
148
+ .type = QCOW2_FEAT_TYPE_INCOMPATIBLE,
149
+ .bit = QCOW2_INCOMPAT_EXTL2_BITNR,
150
+ .name = "extended L2 entries",
151
+ },
152
{
153
.type = QCOW2_FEAT_TYPE_COMPATIBLE,
154
.bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
155
@@ -XXX,XX +XXX,XX @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
156
return meta_size + aligned_total_size;
157
}
158
159
-static bool validate_cluster_size(size_t cluster_size, Error **errp)
160
+static bool validate_cluster_size(size_t cluster_size, bool extended_l2,
161
+ Error **errp)
162
{
163
int cluster_bits = ctz32(cluster_size);
164
if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
165
@@ -XXX,XX +XXX,XX @@ static bool validate_cluster_size(size_t cluster_size, Error **errp)
166
"%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
167
return false;
168
}
169
+
170
+ if (extended_l2) {
171
+ unsigned min_cluster_size =
172
+ (1 << MIN_CLUSTER_BITS) * QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER;
173
+ if (cluster_size < min_cluster_size) {
174
+ error_setg(errp, "Extended L2 entries are only supported with "
175
+ "cluster sizes of at least %u bytes", min_cluster_size);
176
+ return false;
177
+ }
178
+ }
179
+
180
return true;
181
}
182
183
-static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
184
+static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, bool extended_l2,
185
+ Error **errp)
186
{
187
size_t cluster_size;
188
189
cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
190
DEFAULT_CLUSTER_SIZE);
191
- if (!validate_cluster_size(cluster_size, errp)) {
192
+ if (!validate_cluster_size(cluster_size, extended_l2, errp)) {
193
return 0;
194
}
195
return cluster_size;
196
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
197
cluster_size = DEFAULT_CLUSTER_SIZE;
198
}
199
200
- if (!validate_cluster_size(cluster_size, errp)) {
201
+ if (!qcow2_opts->has_extended_l2) {
202
+ qcow2_opts->extended_l2 = false;
203
+ }
204
+ if (qcow2_opts->extended_l2) {
205
+ if (version < 3) {
206
+ error_setg(errp, "Extended L2 entries are only supported with "
207
+ "compatibility level 1.1 and above (use version=v3 or "
208
+ "greater)");
209
+ ret = -EINVAL;
53
+ goto out;
210
+ goto out;
54
+ }
211
+ }
55
+ }
212
+ }
56
+
213
+
57
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
214
+ if (!validate_cluster_size(cluster_size, qcow2_opts->extended_l2, errp)) {
58
+ if (is_write_zeroes) {
215
ret = -EINVAL;
59
+ block_acct_done(blk_get_stats(s->blk), &req->acct);
216
goto out;
60
+ }
217
}
61
+ virtio_blk_free_request(req);
218
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
62
+
219
cpu_to_be64(QCOW2_INCOMPAT_COMPRESSION);
63
+out:
220
}
64
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
221
65
+}
222
+ if (qcow2_opts->extended_l2) {
66
+
223
+ header->incompatible_features |=
67
#ifdef __linux__
224
+ cpu_to_be64(QCOW2_INCOMPAT_EXTL2);
68
69
typedef struct {
70
@@ -XXX,XX +XXX,XX @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
71
return true;
72
}
73
74
+static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req,
75
+ struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes)
76
+{
77
+ VirtIOBlock *s = req->dev;
78
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
79
+ uint64_t sector;
80
+ uint32_t num_sectors, flags, max_sectors;
81
+ uint8_t err_status;
82
+ int bytes;
83
+
84
+ sector = virtio_ldq_p(vdev, &dwz_hdr->sector);
85
+ num_sectors = virtio_ldl_p(vdev, &dwz_hdr->num_sectors);
86
+ flags = virtio_ldl_p(vdev, &dwz_hdr->flags);
87
+ max_sectors = is_write_zeroes ? s->conf.max_write_zeroes_sectors :
88
+ s->conf.max_discard_sectors;
89
+
90
+ /*
91
+ * max_sectors is at most BDRV_REQUEST_MAX_SECTORS, this check
92
+ * make us sure that "num_sectors << BDRV_SECTOR_BITS" can fit in
93
+ * the integer variable.
94
+ */
95
+ if (unlikely(num_sectors > max_sectors)) {
96
+ err_status = VIRTIO_BLK_S_IOERR;
97
+ goto err;
98
+ }
225
+ }
99
+
226
+
100
+ bytes = num_sectors << BDRV_SECTOR_BITS;
227
ret = blk_pwrite(blk, 0, header, cluster_size, 0);
228
g_free(header);
229
if (ret < 0) {
230
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv,
231
{ BLOCK_OPT_BACKING_FMT, "backing-fmt" },
232
{ BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
233
{ BLOCK_OPT_LAZY_REFCOUNTS, "lazy-refcounts" },
234
+ { BLOCK_OPT_EXTL2, "extended-l2" },
235
{ BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" },
236
{ BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
237
{ BLOCK_OPT_COMPAT_LEVEL, "version" },
238
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
239
PreallocMode prealloc;
240
bool has_backing_file;
241
bool has_luks;
242
- bool extended_l2 = false; /* Set to false until the option is added */
243
+ bool extended_l2;
244
size_t l2e_size;
245
246
/* Parse image creation options */
247
- cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
248
+ extended_l2 = qemu_opt_get_bool_del(opts, BLOCK_OPT_EXTL2, false);
101
+
249
+
102
+ if (unlikely(!virtio_blk_sect_range_ok(s, sector, bytes))) {
250
+ cluster_size = qcow2_opt_get_cluster_size_del(opts, extended_l2,
103
+ err_status = VIRTIO_BLK_S_IOERR;
251
+ &local_err);
104
+ goto err;
252
if (local_err) {
105
+ }
253
goto err;
106
+
107
+ /*
108
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard
109
+ * and write zeroes commands if any unknown flag is set.
110
+ */
111
+ if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
112
+ err_status = VIRTIO_BLK_S_UNSUPP;
113
+ goto err;
114
+ }
115
+
116
+ if (is_write_zeroes) { /* VIRTIO_BLK_T_WRITE_ZEROES */
117
+ int blk_aio_flags = 0;
118
+
119
+ if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
120
+ blk_aio_flags |= BDRV_REQ_MAY_UNMAP;
121
+ }
122
+
123
+ block_acct_start(blk_get_stats(s->blk), &req->acct, bytes,
124
+ BLOCK_ACCT_WRITE);
125
+
126
+ blk_aio_pwrite_zeroes(s->blk, sector << BDRV_SECTOR_BITS,
127
+ bytes, blk_aio_flags,
128
+ virtio_blk_discard_write_zeroes_complete, req);
129
+ } else { /* VIRTIO_BLK_T_DISCARD */
130
+ /*
131
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for
132
+ * discard commands if the unmap flag is set.
133
+ */
134
+ if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
135
+ err_status = VIRTIO_BLK_S_UNSUPP;
136
+ goto err;
137
+ }
138
+
139
+ blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes,
140
+ virtio_blk_discard_write_zeroes_complete, req);
141
+ }
142
+
143
+ return VIRTIO_BLK_S_OK;
144
+
145
+err:
146
+ if (is_write_zeroes) {
147
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
148
+ }
149
+ return err_status;
150
+}
151
+
152
static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
153
{
154
uint32_t type;
155
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
156
virtio_blk_free_request(req);
157
break;
158
}
254
}
159
+ /*
255
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
160
+ * VIRTIO_BLK_T_DISCARD and VIRTIO_BLK_T_WRITE_ZEROES are defined with
256
.corrupt = s->incompatible_features &
161
+ * VIRTIO_BLK_T_OUT flag set. We masked this flag in the switch statement,
257
QCOW2_INCOMPAT_CORRUPT,
162
+ * so we must mask it for these requests, then we will check if it is set.
258
.has_corrupt = true,
163
+ */
259
+ .has_extended_l2 = true,
164
+ case VIRTIO_BLK_T_DISCARD & ~VIRTIO_BLK_T_OUT:
260
+ .extended_l2 = has_subclusters(s),
165
+ case VIRTIO_BLK_T_WRITE_ZEROES & ~VIRTIO_BLK_T_OUT:
261
.refcount_bits = s->refcount_bits,
166
+ {
262
.has_bitmaps = !!bitmaps,
167
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
263
.bitmaps = bitmaps,
168
+ size_t out_len = iov_size(out_iov, out_num);
264
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = {
169
+ bool is_write_zeroes = (type & ~VIRTIO_BLK_T_BARRIER) ==
265
.help = "qcow2 cluster size", \
170
+ VIRTIO_BLK_T_WRITE_ZEROES;
266
.def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \
171
+ uint8_t err_status;
267
}, \
172
+
268
+ { \
173
+ /*
269
+ .name = BLOCK_OPT_EXTL2, \
174
+ * Unsupported if VIRTIO_BLK_T_OUT is not set or the request contains
270
+ .type = QEMU_OPT_BOOL, \
175
+ * more than one segment.
271
+ .help = "Extended L2 tables", \
176
+ */
272
+ .def_value_str = "off" \
177
+ if (unlikely(!(type & VIRTIO_BLK_T_OUT) ||
273
+ }, \
178
+ out_len > sizeof(dwz_hdr))) {
274
{ \
179
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
275
.name = BLOCK_OPT_PREALLOC, \
180
+ virtio_blk_free_request(req);
276
.type = QEMU_OPT_STRING, \
181
+ return 0;
277
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
182
+ }
278
index XXXXXXX..XXXXXXX 100644
183
+
279
--- a/tests/qemu-iotests/031.out
184
+ if (unlikely(iov_to_buf(out_iov, out_num, 0, &dwz_hdr,
280
+++ b/tests/qemu-iotests/031.out
185
+ sizeof(dwz_hdr)) != sizeof(dwz_hdr))) {
281
@@ -XXX,XX +XXX,XX @@ header_length 112
186
+ virtio_error(vdev, "virtio-blk discard/write_zeroes header"
282
187
+ " too short");
283
Header extension:
188
+ return -1;
284
magic 0x6803f857 (Feature table)
189
+ }
285
-length 336
190
+
286
+length 384
191
+ err_status = virtio_blk_handle_discard_write_zeroes(req, &dwz_hdr,
287
data <binary>
192
+ is_write_zeroes);
288
193
+ if (err_status != VIRTIO_BLK_S_OK) {
289
Header extension:
194
+ virtio_blk_req_complete(req, err_status);
290
@@ -XXX,XX +XXX,XX @@ header_length 112
195
+ virtio_blk_free_request(req);
291
196
+ }
292
Header extension:
197
+
293
magic 0x6803f857 (Feature table)
198
+ break;
294
-length 336
199
+ }
295
+length 384
200
default:
296
data <binary>
201
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
297
202
virtio_blk_free_request(req);
298
Header extension:
203
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
299
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
204
blkcfg.alignment_offset = 0;
300
205
blkcfg.wce = blk_enable_write_cache(s->blk);
301
magic 0x514649fb
206
virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues);
302
version 3
207
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD)) {
303
-backing_file_offset 0x210
208
+ virtio_stl_p(vdev, &blkcfg.max_discard_sectors,
304
+backing_file_offset 0x240
209
+ s->conf.max_discard_sectors);
305
backing_file_size 0x17
210
+ virtio_stl_p(vdev, &blkcfg.discard_sector_alignment,
306
cluster_bits 16
211
+ blk_size >> BDRV_SECTOR_BITS);
307
size 67108864
212
+ /*
308
@@ -XXX,XX +XXX,XX @@ data 'host_device'
213
+ * We support only one segment per request since multiple segments
309
214
+ * are not widely used and there are no userspace APIs that allow
310
Header extension:
215
+ * applications to submit multiple segments in a single call.
311
magic 0x6803f857 (Feature table)
216
+ */
312
-length 336
217
+ virtio_stl_p(vdev, &blkcfg.max_discard_seg, 1);
313
+length 384
218
+ }
314
data <binary>
219
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES)) {
315
220
+ virtio_stl_p(vdev, &blkcfg.max_write_zeroes_sectors,
316
Header extension:
221
+ s->conf.max_write_zeroes_sectors);
317
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
222
+ blkcfg.write_zeroes_may_unmap = 1;
318
index XXXXXXX..XXXXXXX 100644
223
+ virtio_stl_p(vdev, &blkcfg.max_write_zeroes_seg, 1);
319
--- a/tests/qemu-iotests/036.out
224
+ }
320
+++ b/tests/qemu-iotests/036.out
225
memcpy(config, &blkcfg, s->config_size);
321
@@ -XXX,XX +XXX,XX @@ compatible_features []
226
}
322
autoclear_features [63]
227
323
Header extension:
228
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
324
magic 0x6803f857 (Feature table)
229
return;
325
-length 336
230
}
326
+length 384
231
327
data <binary>
232
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD) &&
328
233
+ (!conf->max_discard_sectors ||
329
234
+ conf->max_discard_sectors > BDRV_REQUEST_MAX_SECTORS)) {
330
@@ -XXX,XX +XXX,XX @@ compatible_features []
235
+ error_setg(errp, "invalid max-discard-sectors property (%" PRIu32 ")"
331
autoclear_features []
236
+ ", must be between 1 and %d",
332
Header extension:
237
+ conf->max_discard_sectors, (int)BDRV_REQUEST_MAX_SECTORS);
333
magic 0x6803f857 (Feature table)
238
+ return;
334
-length 336
239
+ }
335
+length 384
240
+
336
data <binary>
241
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES) &&
337
242
+ (!conf->max_write_zeroes_sectors ||
338
*** done
243
+ conf->max_write_zeroes_sectors > BDRV_REQUEST_MAX_SECTORS)) {
339
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
244
+ error_setg(errp, "invalid max-write-zeroes-sectors property (%" PRIu32
340
index XXXXXXX..XXXXXXX 100644
245
+ "), must be between 1 and %d",
341
--- a/tests/qemu-iotests/049.out
246
+ conf->max_write_zeroes_sectors,
342
+++ b/tests/qemu-iotests/049.out
247
+ (int)BDRV_REQUEST_MAX_SECTORS);
343
@@ -XXX,XX +XXX,XX @@ QA output created by 049
248
+ return;
344
== 1. Traditional size parameter ==
249
+ }
345
250
+
346
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
251
virtio_blk_set_config_size(s, s->host_features);
347
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
252
348
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
253
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size);
349
254
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
350
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
255
VIRTIO_BLK_F_DISCARD, true),
351
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
256
DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
352
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
257
VIRTIO_BLK_F_WRITE_ZEROES, true),
353
258
+ DEFINE_PROP_UINT32("max-discard-sectors", VirtIOBlock,
354
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
259
+ conf.max_discard_sectors, BDRV_REQUEST_MAX_SECTORS),
355
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
260
+ DEFINE_PROP_UINT32("max-write-zeroes-sectors", VirtIOBlock,
356
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
261
+ conf.max_write_zeroes_sectors, BDRV_REQUEST_MAX_SECTORS),
357
262
DEFINE_PROP_END_OF_LIST(),
358
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
263
};
359
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
264
360
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
361
362
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
363
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16
364
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16
365
366
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
367
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
368
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
369
370
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
371
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16
372
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16
373
374
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
375
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
376
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
377
378
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
379
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
380
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
381
382
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
383
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
384
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
385
386
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
387
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
388
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
389
390
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
391
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16
392
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16
393
394
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
395
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16
396
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16
397
398
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
399
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16
400
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16
401
402
== 2. Specifying size via -o ==
403
404
qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
405
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
406
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
407
408
qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
409
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
410
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
411
412
qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
413
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
414
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
415
416
qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
417
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
418
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
419
420
qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
421
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16
422
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 lazy_refcounts=off refcount_bits=16
423
424
qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
425
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
426
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
427
428
qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
429
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16
430
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1099511627776 lazy_refcounts=off refcount_bits=16
431
432
qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
433
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
434
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
435
436
qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
437
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
438
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
439
440
qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
441
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
442
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
443
444
qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
445
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
446
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1536 lazy_refcounts=off refcount_bits=16
447
448
qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
449
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16
450
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1572864 lazy_refcounts=off refcount_bits=16
451
452
qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
453
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16
454
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1610612736 lazy_refcounts=off refcount_bits=16
455
456
qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
457
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16
458
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1649267441664 lazy_refcounts=off refcount_bits=16
459
460
== 3. Invalid sizes ==
461
462
@@ -XXX,XX +XXX,XX @@ qemu-img: TEST_DIR/t.qcow2: The image size must be specified only once
463
== Check correct interpretation of suffixes for cluster size ==
464
465
qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
466
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
467
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
468
469
qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
470
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
471
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
472
473
qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
474
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
475
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
476
477
qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
478
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
479
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
480
481
qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
482
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1048576 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
483
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1048576 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
484
485
qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
486
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
487
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
488
489
qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
490
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
491
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=1024 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
492
493
qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
494
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
495
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
496
497
qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
498
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
499
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=512 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
500
501
qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
502
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=524288 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
503
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=524288 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
504
505
== Check compat level option ==
506
507
qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
508
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16
509
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16
510
511
qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
512
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16
513
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16
514
515
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
516
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16
517
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.42 lazy_refcounts=off refcount_bits=16
518
qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42'
519
520
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
521
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16
522
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=foobar lazy_refcounts=off refcount_bits=16
523
qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar'
524
525
== Check preallocation option ==
526
527
qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
528
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
529
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
530
531
qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
532
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
533
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
534
535
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
536
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
537
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=1234 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
538
qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234'
539
540
== Check encryption option ==
541
542
qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
543
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=off cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
544
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=off cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
545
546
qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,encrypt.key-secret=sec0 TEST_DIR/t.qcow2 64M
547
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=on encrypt.key-secret=sec0 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
548
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 encryption=on encrypt.key-secret=sec0 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
549
550
== Check lazy_refcounts option (only with v3) ==
551
552
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
553
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16
554
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=off refcount_bits=16
555
556
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
557
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=on refcount_bits=16
558
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=1.1 lazy_refcounts=on refcount_bits=16
559
560
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
561
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16
562
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=off refcount_bits=16
563
564
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
565
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16
566
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 compat=0.10 lazy_refcounts=on refcount_bits=16
567
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
568
569
*** done
570
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
571
index XXXXXXX..XXXXXXX 100644
572
--- a/tests/qemu-iotests/060.out
573
+++ b/tests/qemu-iotests/060.out
574
@@ -XXX,XX +XXX,XX @@ Format specific information:
575
lazy refcounts: false
576
refcount bits: 16
577
corrupt: true
578
+ extended l2: false
579
qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write
580
no file open, try 'help open'
581
read 512/512 bytes at offset 0
582
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
583
index XXXXXXX..XXXXXXX 100644
584
--- a/tests/qemu-iotests/061.out
585
+++ b/tests/qemu-iotests/061.out
586
@@ -XXX,XX +XXX,XX @@ header_length 112
587
588
Header extension:
589
magic 0x6803f857 (Feature table)
590
-length 336
591
+length 384
592
data <binary>
593
594
magic 0x514649fb
595
@@ -XXX,XX +XXX,XX @@ header_length 112
596
597
Header extension:
598
magic 0x6803f857 (Feature table)
599
-length 336
600
+length 384
601
data <binary>
602
603
magic 0x514649fb
604
@@ -XXX,XX +XXX,XX @@ header_length 112
605
606
Header extension:
607
magic 0x6803f857 (Feature table)
608
-length 336
609
+length 384
610
data <binary>
611
612
ERROR cluster 5 refcount=0 reference=1
613
@@ -XXX,XX +XXX,XX @@ header_length 112
614
615
Header extension:
616
magic 0x6803f857 (Feature table)
617
-length 336
618
+length 384
619
data <binary>
620
621
magic 0x514649fb
622
@@ -XXX,XX +XXX,XX @@ header_length 112
623
624
Header extension:
625
magic 0x6803f857 (Feature table)
626
-length 336
627
+length 384
628
data <binary>
629
630
read 65536/65536 bytes at offset 44040192
631
@@ -XXX,XX +XXX,XX @@ header_length 112
632
633
Header extension:
634
magic 0x6803f857 (Feature table)
635
-length 336
636
+length 384
637
data <binary>
638
639
ERROR cluster 5 refcount=0 reference=1
640
@@ -XXX,XX +XXX,XX @@ header_length 112
641
642
Header extension:
643
magic 0x6803f857 (Feature table)
644
-length 336
645
+length 384
646
data <binary>
647
648
read 131072/131072 bytes at offset 0
649
@@ -XXX,XX +XXX,XX @@ Format specific information:
650
data file: TEST_DIR/t.IMGFMT.data
651
data file raw: false
652
corrupt: false
653
+ extended l2: false
654
No errors were found on the image.
655
656
=== Try changing the external data file ===
657
@@ -XXX,XX +XXX,XX @@ Format specific information:
658
data file: foo
659
data file raw: false
660
corrupt: false
661
+ extended l2: false
662
663
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image
664
image: TEST_DIR/t.IMGFMT
665
@@ -XXX,XX +XXX,XX @@ Format specific information:
666
refcount bits: 16
667
data file raw: false
668
corrupt: false
669
+ extended l2: false
670
671
=== Clearing and setting data-file-raw ===
672
673
@@ -XXX,XX +XXX,XX @@ Format specific information:
674
data file: TEST_DIR/t.IMGFMT.data
675
data file raw: true
676
corrupt: false
677
+ extended l2: false
678
No errors were found on the image.
679
image: TEST_DIR/t.IMGFMT
680
file format: IMGFMT
681
@@ -XXX,XX +XXX,XX @@ Format specific information:
682
data file: TEST_DIR/t.IMGFMT.data
683
data file raw: false
684
corrupt: false
685
+ extended l2: false
686
No errors were found on the image.
687
qemu-img: data-file-raw cannot be set on existing images
688
image: TEST_DIR/t.IMGFMT
689
@@ -XXX,XX +XXX,XX @@ Format specific information:
690
data file: TEST_DIR/t.IMGFMT.data
691
data file raw: false
692
corrupt: false
693
+ extended l2: false
694
No errors were found on the image.
695
*** done
696
diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065
697
index XXXXXXX..XXXXXXX 100755
698
--- a/tests/qemu-iotests/065
699
+++ b/tests/qemu-iotests/065
700
@@ -XXX,XX +XXX,XX @@ class TestQCow3NotLazy(TestQemuImgInfo):
701
img_options = 'compat=1.1,lazy_refcounts=off'
702
json_compare = { 'compat': '1.1', 'lazy-refcounts': False,
703
'refcount-bits': 16, 'corrupt': False,
704
- 'compression-type': 'zlib' }
705
+ 'compression-type': 'zlib', 'extended-l2': False }
706
human_compare = [ 'compat: 1.1', 'compression type: zlib',
707
'lazy refcounts: false', 'refcount bits: 16',
708
- 'corrupt: false' ]
709
+ 'corrupt: false', 'extended l2: false' ]
710
711
class TestQCow3Lazy(TestQemuImgInfo):
712
'''Testing a qcow2 version 3 image with lazy refcounts enabled'''
713
img_options = 'compat=1.1,lazy_refcounts=on'
714
json_compare = { 'compat': '1.1', 'lazy-refcounts': True,
715
'refcount-bits': 16, 'corrupt': False,
716
- 'compression-type': 'zlib' }
717
+ 'compression-type': 'zlib', 'extended-l2': False }
718
human_compare = [ 'compat: 1.1', 'compression type: zlib',
719
'lazy refcounts: true', 'refcount bits: 16',
720
- 'corrupt: false' ]
721
+ 'corrupt: false', 'extended l2: false' ]
722
723
class TestQCow3NotLazyQMP(TestQMP):
724
'''Testing a qcow2 version 3 image with lazy refcounts disabled, opening
725
@@ -XXX,XX +XXX,XX @@ class TestQCow3NotLazyQMP(TestQMP):
726
qemu_options = 'lazy-refcounts=on'
727
compare = { 'compat': '1.1', 'lazy-refcounts': False,
728
'refcount-bits': 16, 'corrupt': False,
729
- 'compression-type': 'zlib' }
730
+ 'compression-type': 'zlib', 'extended-l2': False }
731
732
733
class TestQCow3LazyQMP(TestQMP):
734
@@ -XXX,XX +XXX,XX @@ class TestQCow3LazyQMP(TestQMP):
735
qemu_options = 'lazy-refcounts=off'
736
compare = { 'compat': '1.1', 'lazy-refcounts': True,
737
'refcount-bits': 16, 'corrupt': False,
738
- 'compression-type': 'zlib' }
739
+ 'compression-type': 'zlib', 'extended-l2': False }
740
741
TestImageInfoSpecific = None
742
TestQemuImgInfo = None
743
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
744
index XXXXXXX..XXXXXXX 100644
745
--- a/tests/qemu-iotests/082.out
746
+++ b/tests/qemu-iotests/082.out
747
@@ -XXX,XX +XXX,XX @@ QA output created by 082
748
=== create: Options specified more than once ===
749
750
Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M
751
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
752
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
753
image: TEST_DIR/t.IMGFMT
754
file format: IMGFMT
755
virtual size: 128 MiB (134217728 bytes)
756
cluster_size: 65536
757
758
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M
759
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=4096 compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16
760
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=4096 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16
761
image: TEST_DIR/t.IMGFMT
762
file format: IMGFMT
763
virtual size: 128 MiB (134217728 bytes)
764
@@ -XXX,XX +XXX,XX @@ Format specific information:
765
lazy refcounts: true
766
refcount bits: 16
767
corrupt: false
768
+ extended l2: false
769
770
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M
771
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16
772
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=on refcount_bits=16
773
image: TEST_DIR/t.IMGFMT
774
file format: IMGFMT
775
virtual size: 128 MiB (134217728 bytes)
776
@@ -XXX,XX +XXX,XX @@ Format specific information:
777
lazy refcounts: true
778
refcount bits: 16
779
corrupt: false
780
+ extended l2: false
781
782
Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M
783
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
784
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=8192 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
785
image: TEST_DIR/t.IMGFMT
786
file format: IMGFMT
787
virtual size: 128 MiB (134217728 bytes)
788
@@ -XXX,XX +XXX,XX @@ Supported options:
789
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
790
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
791
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
792
+ extended_l2=<bool (on/off)> - Extended L2 tables
793
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
794
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
795
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
796
@@ -XXX,XX +XXX,XX @@ Supported options:
797
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
798
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
799
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
800
+ extended_l2=<bool (on/off)> - Extended L2 tables
801
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
802
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
803
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
804
@@ -XXX,XX +XXX,XX @@ Supported options:
805
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
806
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
807
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
808
+ extended_l2=<bool (on/off)> - Extended L2 tables
809
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
810
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
811
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
812
@@ -XXX,XX +XXX,XX @@ Supported options:
813
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
814
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
815
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
816
+ extended_l2=<bool (on/off)> - Extended L2 tables
817
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
818
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
819
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
820
@@ -XXX,XX +XXX,XX @@ Supported options:
821
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
822
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
823
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
824
+ extended_l2=<bool (on/off)> - Extended L2 tables
825
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
826
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
827
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
828
@@ -XXX,XX +XXX,XX @@ Supported options:
829
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
830
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
831
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
832
+ extended_l2=<bool (on/off)> - Extended L2 tables
833
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
834
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
835
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
836
@@ -XXX,XX +XXX,XX @@ Supported options:
837
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
838
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
839
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
840
+ extended_l2=<bool (on/off)> - Extended L2 tables
841
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
842
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
843
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
844
@@ -XXX,XX +XXX,XX @@ Supported options:
845
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
846
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
847
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
848
+ extended_l2=<bool (on/off)> - Extended L2 tables
849
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
850
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
851
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
852
@@ -XXX,XX +XXX,XX @@ Supported options:
853
size=<size> - Virtual disk size
854
855
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help -F qcow2 TEST_DIR/t.qcow2 128M
856
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,help backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
857
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,help backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
858
859
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? -F qcow2 TEST_DIR/t.qcow2 128M
860
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,? backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
861
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2,,? backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
862
863
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
864
qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2,
865
@@ -XXX,XX +XXX,XX @@ Supported qcow2 options:
866
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
867
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
868
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
869
+ extended_l2=<bool (on/off)> - Extended L2 tables
870
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
871
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
872
refcount_bits=<num> - Width of a reference count entry in bits
873
@@ -XXX,XX +XXX,XX @@ qemu-img: Format driver 'bochs' does not support image creation
874
=== convert: Options specified more than once ===
875
876
Testing: create -f qcow2 TEST_DIR/t.qcow2 128M
877
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
878
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
879
880
Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
881
image: TEST_DIR/t.IMGFMT.base
882
@@ -XXX,XX +XXX,XX @@ Format specific information:
883
lazy refcounts: true
884
refcount bits: 16
885
corrupt: false
886
+ extended l2: false
887
888
Testing: convert -O qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
889
image: TEST_DIR/t.IMGFMT.base
890
@@ -XXX,XX +XXX,XX @@ Format specific information:
891
lazy refcounts: true
892
refcount bits: 16
893
corrupt: false
894
+ extended l2: false
895
896
Testing: convert -O qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
897
image: TEST_DIR/t.IMGFMT.base
898
@@ -XXX,XX +XXX,XX @@ Supported options:
899
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
900
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
901
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
902
+ extended_l2=<bool (on/off)> - Extended L2 tables
903
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
904
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
905
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
906
@@ -XXX,XX +XXX,XX @@ Supported options:
907
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
908
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
909
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
910
+ extended_l2=<bool (on/off)> - Extended L2 tables
911
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
912
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
913
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
914
@@ -XXX,XX +XXX,XX @@ Supported options:
915
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
916
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
917
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
918
+ extended_l2=<bool (on/off)> - Extended L2 tables
919
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
920
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
921
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
922
@@ -XXX,XX +XXX,XX @@ Supported options:
923
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
924
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
925
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
926
+ extended_l2=<bool (on/off)> - Extended L2 tables
927
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
928
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
929
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
930
@@ -XXX,XX +XXX,XX @@ Supported options:
931
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
932
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
933
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
934
+ extended_l2=<bool (on/off)> - Extended L2 tables
935
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
936
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
937
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
938
@@ -XXX,XX +XXX,XX @@ Supported options:
939
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
940
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
941
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
942
+ extended_l2=<bool (on/off)> - Extended L2 tables
943
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
944
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
945
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
946
@@ -XXX,XX +XXX,XX @@ Supported options:
947
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
948
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
949
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
950
+ extended_l2=<bool (on/off)> - Extended L2 tables
951
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
952
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
953
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
954
@@ -XXX,XX +XXX,XX @@ Supported options:
955
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
956
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
957
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
958
+ extended_l2=<bool (on/off)> - Extended L2 tables
959
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
960
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
961
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
962
@@ -XXX,XX +XXX,XX @@ Supported qcow2 options:
963
encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
964
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
965
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
966
+ extended_l2=<bool (on/off)> - Extended L2 tables
967
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
968
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
969
refcount_bits=<num> - Width of a reference count entry in bits
970
@@ -XXX,XX +XXX,XX @@ Format specific information:
971
lazy refcounts: true
972
refcount bits: 16
973
corrupt: false
974
+ extended l2: false
975
976
Testing: amend -f qcow2 -o size=130M -o lazy_refcounts=off TEST_DIR/t.qcow2
977
image: TEST_DIR/t.IMGFMT
978
@@ -XXX,XX +XXX,XX @@ Format specific information:
979
lazy refcounts: false
980
refcount bits: 16
981
corrupt: false
982
+ extended l2: false
983
984
Testing: amend -f qcow2 -o size=8M -o lazy_refcounts=on -o size=132M TEST_DIR/t.qcow2
985
image: TEST_DIR/t.IMGFMT
986
@@ -XXX,XX +XXX,XX @@ Format specific information:
987
lazy refcounts: true
988
refcount bits: 16
989
corrupt: false
990
+ extended l2: false
991
992
Testing: amend -f qcow2 -o size=4M,size=148M TEST_DIR/t.qcow2
993
image: TEST_DIR/t.IMGFMT
994
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
995
index XXXXXXX..XXXXXXX 100644
996
--- a/tests/qemu-iotests/085.out
997
+++ b/tests/qemu-iotests/085.out
998
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
999
=== Create a single snapshot on virtio0 ===
1000
1001
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/1-snapshot-v0.IMGFMT', 'format': 'IMGFMT' } }
1002
-Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1003
+Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1004
{"return": {}}
1005
1006
=== Invalid command - missing device and nodename ===
1007
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compress
1008
=== Create several transactional group snapshots ===
1009
1010
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/2-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/2-snapshot-v1.IMGFMT' } } ] } }
1011
-Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1012
-Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1013
+Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1014
+Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1015
{"return": {}}
1016
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/3-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/3-snapshot-v1.IMGFMT' } } ] } }
1017
-Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1018
-Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1019
+Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1020
+Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1021
{"return": {}}
1022
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/4-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/4-snapshot-v1.IMGFMT' } } ] } }
1023
-Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1024
-Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1025
+Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1026
+Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1027
{"return": {}}
1028
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/5-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/5-snapshot-v1.IMGFMT' } } ] } }
1029
-Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1030
-Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1031
+Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1032
+Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1033
{"return": {}}
1034
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/6-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/6-snapshot-v1.IMGFMT' } } ] } }
1035
-Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1036
-Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1037
+Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1038
+Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1039
{"return": {}}
1040
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/7-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/7-snapshot-v1.IMGFMT' } } ] } }
1041
-Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1042
-Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1043
+Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1044
+Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1045
{"return": {}}
1046
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/8-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/8-snapshot-v1.IMGFMT' } } ] } }
1047
-Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1048
-Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1049
+Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1050
+Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1051
{"return": {}}
1052
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/9-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/9-snapshot-v1.IMGFMT' } } ] } }
1053
-Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1054
-Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1055
+Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1056
+Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1057
{"return": {}}
1058
{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': 'TEST_DIR/10-snapshot-v0.IMGFMT' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': 'TEST_DIR/10-snapshot-v1.IMGFMT' } } ] } }
1059
-Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1060
-Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1061
+Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1062
+Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1063
{"return": {}}
1064
1065
=== Create a couple of snapshots using blockdev-snapshot ===
1066
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
1067
index XXXXXXX..XXXXXXX 100644
1068
--- a/tests/qemu-iotests/144.out
1069
+++ b/tests/qemu-iotests/144.out
1070
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912
1071
{ 'execute': 'qmp_capabilities' }
1072
{"return": {}}
1073
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp.IMGFMT', 'format': 'IMGFMT' } }
1074
-Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1075
+Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1076
{"return": {}}
1077
1078
=== Performing block-commit on active layer ===
1079
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 cluster_size=65536 compression_type=z
1080
=== Performing Live Snapshot 2 ===
1081
1082
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'TEST_DIR/tmp2.IMGFMT', 'format': 'IMGFMT' } }
1083
-Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1084
+Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1085
{"return": {}}
1086
*** done
1087
diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out
1088
index XXXXXXX..XXXXXXX 100644
1089
--- a/tests/qemu-iotests/182.out
1090
+++ b/tests/qemu-iotests/182.out
1091
@@ -XXX,XX +XXX,XX @@ Is another process using the image [TEST_DIR/t.qcow2]?
1092
{'execute': 'blockdev-add', 'arguments': { 'node-name': 'node0', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } }
1093
{"return": {}}
1094
{'execute': 'blockdev-snapshot-sync', 'arguments': { 'node-name': 'node0', 'snapshot-file': 'TEST_DIR/t.IMGFMT.overlay', 'snapshot-node-name': 'node1' } }
1095
-Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 cluster_size=65536 compression_type=zlib size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file lazy_refcounts=off refcount_bits=16
1096
+Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file lazy_refcounts=off refcount_bits=16
1097
{"return": {}}
1098
{'execute': 'blockdev-add', 'arguments': { 'node-name': 'node1', 'driver': 'file', 'filename': 'TEST_DIR/t.IMGFMT', 'locking': 'on' } }
1099
{"return": {}}
1100
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
1101
index XXXXXXX..XXXXXXX 100644
1102
--- a/tests/qemu-iotests/185.out
1103
+++ b/tests/qemu-iotests/185.out
1104
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
1105
=== Creating backing chain ===
1106
1107
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT.mid', 'format': 'IMGFMT', 'mode': 'absolute-paths' } }
1108
-Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1109
+Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1110
{"return": {}}
1111
{ 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'qemu-io disk "write 0 4M"' } }
1112
wrote 4194304/4194304 bytes at offset 0
1113
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1114
{"return": ""}
1115
{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'disk', 'snapshot-file': 'TEST_DIR/t.IMGFMT', 'format': 'IMGFMT', 'mode': 'absolute-paths' } }
1116
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1117
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1118
{"return": {}}
1119
1120
=== Start commit job and exit qemu ===
1121
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zli
1122
{ 'execute': 'qmp_capabilities' }
1123
{"return": {}}
1124
{ 'execute': 'drive-mirror', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } }
1125
-Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1126
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1127
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
1128
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
1129
{"return": {}}
1130
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_typ
1131
{ 'execute': 'qmp_capabilities' }
1132
{"return": {}}
1133
{ 'execute': 'drive-backup', 'arguments': { 'device': 'disk', 'target': 'TEST_DIR/t.IMGFMT.copy', 'format': 'IMGFMT', 'sync': 'full', 'speed': 65536 } }
1134
-Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1135
+Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1136
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
1137
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
1138
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
1139
diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198
1140
index XXXXXXX..XXXXXXX 100755
1141
--- a/tests/qemu-iotests/198
1142
+++ b/tests/qemu-iotests/198
1143
@@ -XXX,XX +XXX,XX @@ echo "== checking image base =="
1144
$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info --format-specific \
1145
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
1146
-e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
1147
+ -e '/extended l2:/ D' \
1148
| _filter_json_filename
1149
1150
echo
1151
@@ -XXX,XX +XXX,XX @@ echo "== checking image layer =="
1152
$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info --format-specific \
1153
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
1154
-e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
1155
+ -e '/extended l2:/ D' \
1156
| _filter_json_filename
1157
1158
1159
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
1160
index XXXXXXX..XXXXXXX 100644
1161
--- a/tests/qemu-iotests/206.out
1162
+++ b/tests/qemu-iotests/206.out
1163
@@ -XXX,XX +XXX,XX @@ Format specific information:
1164
lazy refcounts: false
1165
refcount bits: 16
1166
corrupt: false
1167
+ extended l2: false
1168
1169
=== Successful image creation (inline blockdev-add, explicit defaults) ===
1170
1171
@@ -XXX,XX +XXX,XX @@ Format specific information:
1172
lazy refcounts: false
1173
refcount bits: 16
1174
corrupt: false
1175
+ extended l2: false
1176
1177
=== Successful image creation (v3 non-default options) ===
1178
1179
@@ -XXX,XX +XXX,XX @@ Format specific information:
1180
lazy refcounts: true
1181
refcount bits: 1
1182
corrupt: false
1183
+ extended l2: false
1184
1185
=== Successful image creation (v2 non-default options) ===
1186
1187
@@ -XXX,XX +XXX,XX @@ Format specific information:
1188
payload offset: 528384
1189
master key iters: XXX
1190
corrupt: false
1191
+ extended l2: false
1192
1193
=== Invalid BlockdevRef ===
1194
1195
diff --git a/tests/qemu-iotests/242.out b/tests/qemu-iotests/242.out
1196
index XXXXXXX..XXXXXXX 100644
1197
--- a/tests/qemu-iotests/242.out
1198
+++ b/tests/qemu-iotests/242.out
1199
@@ -XXX,XX +XXX,XX @@ Format specific information:
1200
lazy refcounts: false
1201
refcount bits: 16
1202
corrupt: false
1203
+ extended l2: false
1204
1205
No bitmap in JSON format output
1206
1207
@@ -XXX,XX +XXX,XX @@ Format specific information:
1208
granularity: 32768
1209
refcount bits: 16
1210
corrupt: false
1211
+ extended l2: false
1212
1213
The same bitmaps in JSON format:
1214
[
1215
@@ -XXX,XX +XXX,XX @@ Format specific information:
1216
granularity: 65536
1217
refcount bits: 16
1218
corrupt: false
1219
+ extended l2: false
1220
1221
The same bitmaps in JSON format:
1222
[
1223
@@ -XXX,XX +XXX,XX @@ Format specific information:
1224
granularity: 65536
1225
refcount bits: 16
1226
corrupt: false
1227
+ extended l2: false
1228
1229
The same bitmaps in JSON format:
1230
[
1231
@@ -XXX,XX +XXX,XX @@ Format specific information:
1232
granularity: 16384
1233
refcount bits: 16
1234
corrupt: false
1235
+ extended l2: false
1236
1237
Test complete
1238
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
1239
index XXXXXXX..XXXXXXX 100644
1240
--- a/tests/qemu-iotests/255.out
1241
+++ b/tests/qemu-iotests/255.out
1242
@@ -XXX,XX +XXX,XX @@ Finishing a commit job with background reads
1243
1244
=== Create backing chain and start VM ===
1245
1246
-Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1247
+Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1248
1249
-Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1250
+Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1251
1252
=== Start background read requests ===
1253
1254
@@ -XXX,XX +XXX,XX @@ Closing the VM while a job is being cancelled
1255
1256
=== Create images and start VM ===
1257
1258
-Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1259
+Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1260
1261
-Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1262
+Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
1263
1264
wrote 1048576/1048576 bytes at offset 0
1265
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1266
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
1267
index XXXXXXX..XXXXXXX 100644
1268
--- a/tests/qemu-iotests/274.out
1269
+++ b/tests/qemu-iotests/274.out
1270
@@ -XXX,XX +XXX,XX @@
1271
== Commit tests ==
1272
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1273
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1274
1275
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1276
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1277
1278
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1280
1281
wrote 2097152/2097152 bytes at offset 0
1282
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1283
@@ -XXX,XX +XXX,XX @@ Format specific information:
1284
lazy refcounts: false
1285
refcount bits: 16
1286
corrupt: false
1287
+ extended l2: false
1288
1289
read 1048576/1048576 bytes at offset 0
1290
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1291
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1292
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1293
1294
=== Testing HMP commit (top -> mid) ===
1295
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1296
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1297
1298
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1299
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1300
1301
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1302
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1303
1304
wrote 2097152/2097152 bytes at offset 0
1305
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1306
@@ -XXX,XX +XXX,XX @@ Format specific information:
1307
lazy refcounts: false
1308
refcount bits: 16
1309
corrupt: false
1310
+ extended l2: false
1311
1312
read 1048576/1048576 bytes at offset 0
1313
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1314
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1315
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1316
1317
=== Testing QMP active commit (top -> mid) ===
1318
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1319
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
1320
1321
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1322
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1323
1324
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1325
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1326
1327
wrote 2097152/2097152 bytes at offset 0
1328
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1329
@@ -XXX,XX +XXX,XX @@ Format specific information:
1330
lazy refcounts: false
1331
refcount bits: 16
1332
corrupt: false
1333
+ extended l2: false
1334
1335
read 1048576/1048576 bytes at offset 0
1336
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1337
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1338
1339
== Resize tests ==
1340
=== preallocation=off ===
1341
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16
1342
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16
1343
1344
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1345
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1346
1347
wrote 65536/65536 bytes at offset 5368709120
1348
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1349
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 5368709120
1350
{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
1351
1352
=== preallocation=metadata ===
1353
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16
1354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16
1355
1356
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1357
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1358
1359
wrote 65536/65536 bytes at offset 33285996544
1360
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1361
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 33285996544
1362
{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
1363
1364
=== preallocation=falloc ===
1365
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16
1366
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16
1367
1368
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1369
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1370
1371
wrote 65536/65536 bytes at offset 9437184
1372
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1373
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
1374
{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
1375
1376
=== preallocation=full ===
1377
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16
1378
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16
1379
1380
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1381
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1382
1383
wrote 65536/65536 bytes at offset 11534336
1384
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1385
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
1386
{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
1387
1388
=== preallocation=off ===
1389
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16
1390
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16
1391
1392
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1393
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1394
1395
wrote 65536/65536 bytes at offset 259072
1396
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1397
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 259072
1398
{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
1399
1400
=== preallocation=off ===
1401
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16
1402
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16
1403
1404
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1405
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1406
1407
wrote 65536/65536 bytes at offset 344064
1408
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1409
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 344064
1410
{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
1411
1412
=== preallocation=off ===
1413
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16
1414
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16
1415
1416
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1417
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
1418
1419
wrote 65536/65536 bytes at offset 446464
1420
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1421
diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out
1422
index XXXXXXX..XXXXXXX 100644
1423
--- a/tests/qemu-iotests/280.out
1424
+++ b/tests/qemu-iotests/280.out
1425
@@ -XXX,XX +XXX,XX @@
1426
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1427
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
1428
1429
=== Launch VM ===
1430
Enabling migration QMP events on VM...
1431
diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out
1432
index XXXXXXX..XXXXXXX 100644
1433
--- a/tests/qemu-iotests/291.out
1434
+++ b/tests/qemu-iotests/291.out
1435
@@ -XXX,XX +XXX,XX @@ Format specific information:
1436
granularity: 65536
1437
refcount bits: 16
1438
corrupt: false
1439
+ extended l2: false
1440
image: TEST_DIR/t.IMGFMT
1441
file format: IMGFMT
1442
virtual size: 10 MiB (10485760 bytes)
1443
@@ -XXX,XX +XXX,XX @@ Format specific information:
1444
granularity: 65536
1445
refcount bits: 16
1446
corrupt: false
1447
+ extended l2: false
1448
1449
=== Check bitmap contents ===
1450
1451
diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out
1452
index XXXXXXX..XXXXXXX 100644
1453
--- a/tests/qemu-iotests/302.out
1454
+++ b/tests/qemu-iotests/302.out
1455
@@ -XXX,XX +XXX,XX @@ Format specific information:
1456
lazy refcounts: false
1457
refcount bits: 16
1458
corrupt: false
1459
+ extended l2: false
1460
1461
=== Converted image check ===
1462
No errors were found on the image.
1463
diff --git a/tests/qemu-iotests/303.out b/tests/qemu-iotests/303.out
1464
index XXXXXXX..XXXXXXX 100644
1465
--- a/tests/qemu-iotests/303.out
1466
+++ b/tests/qemu-iotests/303.out
1467
@@ -XXX,XX +XXX,XX @@ header_length 112
1468
1469
Header extension:
1470
magic 0x6803f857 (Feature table)
1471
-length 336
1472
+length 384
1473
data <binary>
1474
1475
Header extension:
1476
@@ -XXX,XX +XXX,XX @@ Bitmap table type size offset
1477
{
1478
"name": "Feature table",
1479
"magic": 1745090647,
1480
- "length": 336,
1481
+ "length": 384,
1482
"data_str": "<binary>"
1483
},
1484
{
1485
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
1486
index XXXXXXX..XXXXXXX 100644
1487
--- a/tests/qemu-iotests/common.filter
1488
+++ b/tests/qemu-iotests/common.filter
1489
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
1490
-e "/adapter_type: '[^']*'/d" \
1491
-e "/hwversion: '[^']*'/d" \
1492
-e "/lazy_refcounts: \\(on\\|off\\)/d" \
1493
+ -e "/extended_l2=\\(on\\|off\\)/d" \
1494
-e "/block_size: [0-9]\\+/d" \
1495
-e "/block_state_zero: \\(on\\|off\\)/d" \
1496
-e "/log_size: [0-9]\\+/d" \
265
--
1497
--
266
2.20.1
1498
2.26.2
267
1499
268
1500
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
Traditional qcow2 images don't allow preallocation if a backing file
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
is set. This is because once a cluster is allocated there is no way to
5
tell that its data should be read from the backing file.
5
6
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Extended L2 entries have individual allocation bits for each
8
subcluster, and therefore it is perfectly possible to have an
9
allocated cluster with all its subclusters unallocated.
10
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-10-vsementsov@virtuozzo.com
14
Message-Id: <6d5b0f38e7dc5f2f31d8cab1cb92044e9909aece.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-10-vsementsov@virtuozzo.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
16
---
13
block/qcow2.c | 12 ++----------
17
block/qcow2.c | 7 ++++---
14
1 file changed, 2 insertions(+), 10 deletions(-)
18
tests/qemu-iotests/206.out | 2 +-
19
2 files changed, 5 insertions(+), 4 deletions(-)
15
20
16
diff --git a/block/qcow2.c b/block/qcow2.c
21
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.c
23
--- a/block/qcow2.c
19
+++ b/block/qcow2.c
24
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
25
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
21
{
26
qcow2_opts->preallocation = PREALLOC_MODE_OFF;
22
BDRVQcow2State *s = bs->opaque;
23
QEMUIOVector hd_qiov;
24
- struct iovec iov;
25
int ret;
26
size_t out_len;
27
uint8_t *buf, *out_buf;
28
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
29
goto fail;
30
}
27
}
31
28
if (qcow2_opts->has_backing_file &&
32
- iov = (struct iovec) {
29
- qcow2_opts->preallocation != PREALLOC_MODE_OFF)
33
- .iov_base = out_buf,
30
+ qcow2_opts->preallocation != PREALLOC_MODE_OFF &&
34
- .iov_len = out_len,
31
+ !qcow2_opts->extended_l2)
35
- };
32
{
36
- qemu_iovec_init_external(&hd_qiov, &iov, 1);
33
- error_setg(errp, "Backing file and preallocation cannot be used at "
37
+ qemu_iovec_init_buf(&hd_qiov, out_buf, out_len);
34
- "the same time");
38
35
+ error_setg(errp, "Backing file and preallocation can only be used at "
39
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
36
+ "the same time if extended_l2 is on");
40
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
37
ret = -EINVAL;
41
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
38
goto out;
42
int ret = 0, csize, nb_csectors;
43
uint64_t coffset;
44
uint8_t *buf, *out_buf;
45
- struct iovec iov;
46
QEMUIOVector local_qiov;
47
int offset_in_cluster = offset_into_cluster(s, offset);
48
49
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
50
if (!buf) {
51
return -ENOMEM;
52
}
39
}
53
- iov.iov_base = buf;
40
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
54
- iov.iov_len = csize;
41
index XXXXXXX..XXXXXXX 100644
55
- qemu_iovec_init_external(&local_qiov, &iov, 1);
42
--- a/tests/qemu-iotests/206.out
56
+ qemu_iovec_init_buf(&local_qiov, buf, csize);
43
+++ b/tests/qemu-iotests/206.out
57
44
@@ -XXX,XX +XXX,XX @@ Job failed: Different refcount widths than 16 bits require compatibility level 1
58
out_buf = qemu_blockalign(bs, s->cluster_size);
45
=== Invalid backing file options ===
46
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}}
47
{"return": {}}
48
-Job failed: Backing file and preallocation cannot be used at the same time
49
+Job failed: Backing file and preallocation can only be used at the same time if extended_l2 is on
50
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
51
{"return": {}}
59
52
60
--
53
--
61
2.20.1
54
2.26.2
62
55
63
56
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new qemu_iovec_init_buf() instead of
3
This function is only used by qcow2_expand_zero_clusters() to
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
downgrade a qcow2 image to a previous version. This would require
5
transforming all extended L2 entries into normal L2 entries but this
6
is not a simple task and there are no plans to implement this at the
7
moment.
5
8
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190218140926.333779-5-vsementsov@virtuozzo.com
12
Message-Id: <15e65112b4144381b4d8c0bdf8fb76b0d813e3d1.1594396418.git.berto@igalia.com>
10
Message-Id: <20190218140926.333779-5-vsementsov@virtuozzo.com>
13
[mreitz: Fixed comment style]
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
15
---
13
block/backup.c | 5 +----
16
block/qcow2-cluster.c | 14 ++++++++++++--
14
1 file changed, 1 insertion(+), 4 deletions(-)
17
tests/qemu-iotests/061 | 6 ++++++
18
tests/qemu-iotests/061.out | 5 +++++
19
3 files changed, 23 insertions(+), 2 deletions(-)
15
20
16
diff --git a/block/backup.c b/block/backup.c
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
18
--- a/block/backup.c
23
--- a/block/qcow2-cluster.c
19
+++ b/block/backup.c
24
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
25
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
21
void **bounce_buffer)
22
{
23
int ret;
26
int ret;
24
- struct iovec iov;
27
int i, j;
25
QEMUIOVector qiov;
28
26
BlockBackend *blk = job->common.blk;
29
+ /* qcow2_downgrade() is not allowed in images with subclusters */
27
int nbytes;
30
+ assert(!has_subclusters(s));
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
31
+
29
if (!*bounce_buffer) {
32
slice_size2 = s->l2_slice_size * l2_entry_size(s);
30
*bounce_buffer = blk_blockalign(blk, job->cluster_size);
33
n_slices = s->cluster_size / slice_size2;
31
}
34
32
- iov.iov_base = *bounce_buffer;
35
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
33
- iov.iov_len = nbytes;
36
34
- qemu_iovec_init_external(&qiov, &iov, 1);
37
if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
35
+ qemu_iovec_init_buf(&qiov, *bounce_buffer, nbytes);
38
if (!bs->backing) {
36
39
- /* not backed; therefore we can simply deallocate the
37
ret = blk_co_preadv(blk, start, qiov.size, &qiov, read_flags);
40
- * cluster */
38
if (ret < 0) {
41
+ /*
42
+ * not backed; therefore we can simply deallocate the
43
+ * cluster. No need to call set_l2_bitmap(), this
44
+ * function doesn't support images with subclusters.
45
+ */
46
set_l2_entry(s, l2_slice, j, 0);
47
l2_dirty = true;
48
continue;
49
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
50
} else {
51
set_l2_entry(s, l2_slice, j, offset);
52
}
53
+ /*
54
+ * No need to call set_l2_bitmap() after set_l2_entry() because
55
+ * this function doesn't support images with subclusters.
56
+ */
57
l2_dirty = true;
58
}
59
60
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
61
index XXXXXXX..XXXXXXX 100755
62
--- a/tests/qemu-iotests/061
63
+++ b/tests/qemu-iotests/061
64
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
65
_img_info --format-specific
66
_check_test_img
67
68
+echo
69
+echo "=== Testing version downgrade with extended L2 entries ==="
70
+echo
71
+_make_test_img -o "compat=1.1,extended_l2=on" 64M
72
+$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
73
+
74
echo
75
echo "=== Try changing the external data file ==="
76
echo
77
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
78
index XXXXXXX..XXXXXXX 100644
79
--- a/tests/qemu-iotests/061.out
80
+++ b/tests/qemu-iotests/061.out
81
@@ -XXX,XX +XXX,XX @@ Format specific information:
82
extended l2: false
83
No errors were found on the image.
84
85
+=== Testing version downgrade with extended L2 entries ===
86
+
87
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
88
+qemu-img: Cannot downgrade an image with incompatible features 0x10 set
89
+
90
=== Try changing the external data file ===
91
92
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
39
--
93
--
40
2.20.1
94
2.26.2
41
95
42
96
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Use new QEMU_IOVEC_INIT_BUF() instead of
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
qemu_iovec_init_external( ... , 1), which simplifies the code.
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Message-Id: <e6dd0429cafe84ca603179c298a8703bddca2904.1594396418.git.berto@igalia.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/271 | 901 +++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/271.out | 726 ++++++++++++++++++++++++++++++
10
tests/qemu-iotests/group | 1 +
11
3 files changed, 1628 insertions(+)
12
create mode 100755 tests/qemu-iotests/271
13
create mode 100644 tests/qemu-iotests/271.out
5
14
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
diff --git a/tests/qemu-iotests/271 b/tests/qemu-iotests/271
7
Reviewed-by: Eric Blake <eblake@redhat.com>
16
new file mode 100755
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
index XXXXXXX..XXXXXXX
9
Message-id: 20190218140926.333779-4-vsementsov@virtuozzo.com
18
--- /dev/null
10
Message-Id: <20190218140926.333779-4-vsementsov@virtuozzo.com>
19
+++ b/tests/qemu-iotests/271
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
@@ -XXX,XX +XXX,XX @@
12
---
21
+#!/bin/bash
13
block/block-backend.c | 13 ++-----------
22
+#
14
1 file changed, 2 insertions(+), 11 deletions(-)
23
+# Test qcow2 images with extended L2 entries
15
24
+#
16
diff --git a/block/block-backend.c b/block/block-backend.c
25
+# Copyright (C) 2019-2020 Igalia, S.L.
26
+# Author: Alberto Garcia <berto@igalia.com>
27
+#
28
+# This program is free software; you can redistribute it and/or modify
29
+# it under the terms of the GNU General Public License as published by
30
+# the Free Software Foundation; either version 2 of the License, or
31
+# (at your option) any later version.
32
+#
33
+# This program is distributed in the hope that it will be useful,
34
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
35
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36
+# GNU General Public License for more details.
37
+#
38
+# You should have received a copy of the GNU General Public License
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+#
41
+
42
+# creator
43
+owner=berto@igalia.com
44
+
45
+seq="$(basename $0)"
46
+echo "QA output created by $seq"
47
+
48
+here="$PWD"
49
+status=1    # failure is the default!
50
+
51
+_cleanup()
52
+{
53
+ _cleanup_test_img
54
+ rm -f "$TEST_IMG.raw"
55
+}
56
+trap "_cleanup; exit \$status" 0 1 2 3 15
57
+
58
+# get standard environment, filters and checks
59
+. ./common.rc
60
+. ./common.filter
61
+
62
+_supported_fmt qcow2
63
+_supported_proto file nfs
64
+_supported_os Linux
65
+_unsupported_imgopts extended_l2 compat=0.10 cluster_size data_file refcount_bits=1[^0-9]
66
+
67
+l2_offset=$((0x40000))
68
+
69
+_verify_img()
70
+{
71
+ $QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.raw" | grep -v 'Images are identical'
72
+ $QEMU_IMG check "$TEST_IMG" | _filter_qemu_img_check | \
73
+ grep -v 'No errors were found on the image'
74
+}
75
+
76
+# Compare the bitmap of an extended L2 entry against an expected value
77
+_verify_l2_bitmap()
78
+{
79
+ entry_no="$1" # L2 entry number, starting from 0
80
+ expected_alloc="$alloc" # Space-separated list of allocated subcluster indexes
81
+ expected_zero="$zero" # Space-separated list of zero subcluster indexes
82
+
83
+ offset=$(($l2_offset + $entry_no * 16))
84
+ entry=$(peek_file_be "$TEST_IMG" $offset 8)
85
+ offset=$(($offset + 8))
86
+ bitmap=$(peek_file_be "$TEST_IMG" $offset 8)
87
+
88
+ expected_bitmap=0
89
+ for bit in $expected_alloc; do
90
+ expected_bitmap=$(($expected_bitmap | (1 << $bit)))
91
+ done
92
+ for bit in $expected_zero; do
93
+ expected_bitmap=$(($expected_bitmap | (1 << (32 + $bit))))
94
+ done
95
+ printf -v expected_bitmap "%u" $expected_bitmap # Convert to unsigned
96
+
97
+ printf "L2 entry #%d: 0x%016x %016x\n" "$entry_no" "$entry" "$bitmap"
98
+ if [ "$bitmap" != "$expected_bitmap" ]; then
99
+ printf "ERROR: expecting bitmap 0x%016x\n" "$expected_bitmap"
100
+ fi
101
+}
102
+
103
+# This should be called as _run_test c=XXX sc=XXX off=XXX len=XXX cmd=XXX
104
+# c: cluster number (0 if unset)
105
+# sc: subcluster number inside cluster @c (0 if unset)
106
+# off: offset inside subcluster @sc, in kilobytes (0 if unset)
107
+# len: request length, passed directly to qemu-io (e.g: 256, 4k, 1M, ...)
108
+# cmd: the command to pass to qemu-io, must be one of
109
+# write -> write
110
+# zero -> write -z
111
+# unmap -> write -z -u
112
+# compress -> write -c
113
+# discard -> discard
114
+_run_test()
115
+{
116
+ unset c sc off len cmd
117
+ for var in "$@"; do eval "$var"; done
118
+ case "${cmd:-write}" in
119
+ zero)
120
+ cmd="write -q -z";;
121
+ unmap)
122
+ cmd="write -q -z -u";;
123
+ compress)
124
+ pat=$((${pat:-0} + 1))
125
+ cmd="write -q -c -P ${pat}";;
126
+ write)
127
+ pat=$((${pat:-0} + 1))
128
+ cmd="write -q -P ${pat}";;
129
+ discard)
130
+ cmd="discard -q";;
131
+ *)
132
+ echo "Unknown option $cmd"
133
+ exit 1;;
134
+ esac
135
+ c="${c:-0}"
136
+ sc="${sc:-0}"
137
+ off="${off:-0}"
138
+ offset="$(($c * 64 + $sc * 2 + $off))"
139
+ [ "$offset" != 0 ] && offset="${offset}k"
140
+ cmd="$cmd ${offset} ${len}"
141
+ raw_cmd=$(echo $cmd | sed s/-c//) # Raw images don't support -c
142
+ echo $cmd | sed 's/-P [0-9][0-9]\?/-P PATTERN/'
143
+ $QEMU_IO -c "$cmd" "$TEST_IMG" | _filter_qemu_io
144
+ $QEMU_IO -c "$raw_cmd" -f raw "$TEST_IMG.raw" | _filter_qemu_io
145
+ _verify_img
146
+ _verify_l2_bitmap "$c"
147
+}
148
+
149
+_reset_img()
150
+{
151
+ size="$1"
152
+ $QEMU_IMG create -f raw "$TEST_IMG.raw" "$size" | _filter_img_create
153
+ if [ "$use_backing_file" = "yes" ]; then
154
+ $QEMU_IMG create -f raw "$TEST_IMG.base" "$size" | _filter_img_create
155
+ $QEMU_IO -c "write -q -P 0xFF 0 $size" -f raw "$TEST_IMG.base" | _filter_qemu_io
156
+ $QEMU_IO -c "write -q -P 0xFF 0 $size" -f raw "$TEST_IMG.raw" | _filter_qemu_io
157
+ _make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base" "$size"
158
+ else
159
+ _make_test_img -o extended_l2=on "$size"
160
+ fi
161
+}
162
+
163
+############################################################
164
+############################################################
165
+############################################################
166
+
167
+# Test that writing to an image with subclusters produces the expected
168
+# results, in images with and without backing files
169
+for use_backing_file in yes no; do
170
+ echo
171
+ echo "### Standard write tests (backing file: $use_backing_file) ###"
172
+ echo
173
+ _reset_img 1M
174
+ ### Write subcluster #0 (beginning of subcluster) ###
175
+ alloc="0"; zero=""
176
+ _run_test sc=0 len=1k
177
+
178
+ ### Write subcluster #1 (middle of subcluster) ###
179
+ alloc="0 1"; zero=""
180
+ _run_test sc=1 off=1 len=512
181
+
182
+ ### Write subcluster #2 (end of subcluster) ###
183
+ alloc="0 1 2"; zero=""
184
+ _run_test sc=2 off=1 len=1k
185
+
186
+ ### Write subcluster #3 (full subcluster) ###
187
+ alloc="0 1 2 3"; zero=""
188
+ _run_test sc=3 len=2k
189
+
190
+ ### Write subclusters #4-6 (full subclusters) ###
191
+ alloc="$(seq 0 6)"; zero=""
192
+ _run_test sc=4 len=6k
193
+
194
+ ### Write subclusters #7-9 (partial subclusters) ###
195
+ alloc="$(seq 0 9)"; zero=""
196
+ _run_test sc=7 off=1 len=4k
197
+
198
+ ### Write subcluster #16 (partial subcluster) ###
199
+ alloc="$(seq 0 9) 16"; zero=""
200
+ _run_test sc=16 len=1k
201
+
202
+ ### Write subcluster #31-#33 (cluster overlap) ###
203
+ alloc="$(seq 0 9) 16 31"; zero=""
204
+ _run_test sc=31 off=1 len=4k
205
+ alloc="0 1" ; zero=""
206
+ _verify_l2_bitmap 1
207
+
208
+ ### Zero subcluster #1
209
+ alloc="0 $(seq 2 9) 16 31"; zero="1"
210
+ _run_test sc=1 len=2k cmd=zero
211
+
212
+ ### Zero cluster #0
213
+ alloc=""; zero="$(seq 0 31)"
214
+ _run_test sc=0 len=64k cmd=zero
215
+
216
+ ### Fill cluster #0 with data
217
+ alloc="$(seq 0 31)"; zero=""
218
+ _run_test sc=0 len=64k
219
+
220
+ ### Zero and unmap half of cluster #0 (this won't unmap it)
221
+ alloc="$(seq 16 31)"; zero="$(seq 0 15)"
222
+ _run_test sc=0 len=32k cmd=unmap
223
+
224
+ ### Zero and unmap cluster #0
225
+ alloc=""; zero="$(seq 0 31)"
226
+ _run_test sc=0 len=64k cmd=unmap
227
+
228
+ ### Write subcluster #1 (middle of subcluster)
229
+ alloc="1"; zero="0 $(seq 2 31)"
230
+ _run_test sc=1 off=1 len=512
231
+
232
+ ### Fill cluster #0 with data
233
+ alloc="$(seq 0 31)"; zero=""
234
+ _run_test sc=0 len=64k
235
+
236
+ ### Discard cluster #0
237
+ alloc=""; zero="$(seq 0 31)"
238
+ _run_test sc=0 len=64k cmd=discard
239
+
240
+ ### Write compressed data to cluster #0
241
+ alloc=""; zero=""
242
+ _run_test sc=0 len=64k cmd=compress
243
+
244
+ ### Write subcluster #1 (middle of subcluster)
245
+ alloc="$(seq 0 31)"; zero=""
246
+ _run_test sc=1 off=1 len=512
247
+done
248
+
249
+############################################################
250
+############################################################
251
+############################################################
252
+
253
+# calculate_l2_meta() checks if none of the clusters affected by a
254
+# write operation need COW or changes to their L2 metadata and simply
255
+# returns when they don't. This is a test for that optimization.
256
+# Here clusters #0-#3 are overwritten but only #1 and #2 need changes.
257
+echo
258
+echo '### Overwriting several clusters without COW ###'
259
+echo
260
+use_backing_file="no" _reset_img 1M
261
+# Write cluster #0, subclusters #12-#31
262
+alloc="$(seq 12 31)"; zero=""
263
+_run_test sc=12 len=40k
264
+
265
+# Write cluster #1, subcluster #13
266
+alloc="13"; zero=""
267
+_run_test c=1 sc=13 len=2k
268
+
269
+# Zeroize cluster #2, subcluster #14
270
+alloc="14"; zero=""
271
+_run_test c=2 sc=14 len=2k
272
+alloc=""; zero="14"
273
+_run_test c=2 sc=14 len=2k cmd=zero
274
+
275
+# Write cluster #3, subclusters #0-#16
276
+alloc="$(seq 0 16)"; zero=""
277
+_run_test c=3 sc=0 len=34k
278
+
279
+# Write from cluster #0, subcluster #12 to cluster #3, subcluster #11
280
+alloc="$(seq 12 31)"; zero=""
281
+_run_test sc=12 len=192k
282
+alloc="$(seq 0 31)"; zero=""
283
+_verify_l2_bitmap 1
284
+_verify_l2_bitmap 2
285
+
286
+alloc="$(seq 0 16)"; zero=""
287
+_verify_l2_bitmap 3
288
+
289
+############################################################
290
+############################################################
291
+############################################################
292
+
293
+# Test different patterns of writing zeroes
294
+for use_backing_file in yes no; do
295
+ echo
296
+ echo "### Writing zeroes 1: unallocated clusters (backing file: $use_backing_file) ###"
297
+ echo
298
+ # Note that the image size is not a multiple of the cluster size
299
+ _reset_img 2083k
300
+
301
+ # Cluster-aligned request from clusters #0 to #2
302
+ alloc=""; zero="$(seq 0 31)"
303
+ _run_test c=0 sc=0 len=192k cmd=zero
304
+ _verify_l2_bitmap 1
305
+ _verify_l2_bitmap 2
306
+
307
+ # Subcluster-aligned request from clusters #3 to #5
308
+ alloc=""; zero="$(seq 16 31)"
309
+ _run_test c=3 sc=16 len=128k cmd=zero
310
+ alloc=""; zero="$(seq 0 31)"
311
+ _verify_l2_bitmap 4
312
+ alloc=""; zero="$(seq 0 15)"
313
+ _verify_l2_bitmap 5
314
+
315
+ # Unaligned request from clusters #6 to #8
316
+ if [ "$use_backing_file" = "yes" ]; then
317
+ alloc="15"; zero="$(seq 16 31)" # copy-on-write happening here
318
+ else
319
+ alloc=""; zero="$(seq 15 31)"
320
+ fi
321
+ _run_test c=6 sc=15 off=1 len=128k cmd=zero
322
+ alloc=""; zero="$(seq 0 31)"
323
+ _verify_l2_bitmap 7
324
+ if [ "$use_backing_file" = "yes" ]; then
325
+ alloc="15"; zero="$(seq 0 14)" # copy-on-write happening here
326
+ else
327
+ alloc=""; zero="$(seq 0 15)"
328
+ fi
329
+ _verify_l2_bitmap 8
330
+
331
+ echo
332
+ echo "### Writing zeroes 2: allocated clusters (backing file: $use_backing_file) ###"
333
+ echo
334
+ alloc="$(seq 0 31)"; zero=""
335
+ _run_test c=9 sc=0 len=576k
336
+ _verify_l2_bitmap 10
337
+ _verify_l2_bitmap 11
338
+ _verify_l2_bitmap 12
339
+ _verify_l2_bitmap 13
340
+ _verify_l2_bitmap 14
341
+ _verify_l2_bitmap 15
342
+ _verify_l2_bitmap 16
343
+ _verify_l2_bitmap 17
344
+
345
+ # Cluster-aligned request from clusters #9 to #11
346
+ alloc=""; zero="$(seq 0 31)"
347
+ _run_test c=9 sc=0 len=192k cmd=zero
348
+ _verify_l2_bitmap 10
349
+ _verify_l2_bitmap 11
350
+
351
+ # Subcluster-aligned request from clusters #12 to #14
352
+ alloc="$(seq 0 15)"; zero="$(seq 16 31)"
353
+ _run_test c=12 sc=16 len=128k cmd=zero
354
+ alloc=""; zero="$(seq 0 31)"
355
+ _verify_l2_bitmap 13
356
+ alloc="$(seq 16 31)"; zero="$(seq 0 15)"
357
+ _verify_l2_bitmap 14
358
+
359
+ # Unaligned request from clusters #15 to #17
360
+ alloc="$(seq 0 15)"; zero="$(seq 16 31)"
361
+ _run_test c=15 sc=15 off=1 len=128k cmd=zero
362
+ alloc=""; zero="$(seq 0 31)"
363
+ _verify_l2_bitmap 16
364
+ alloc="$(seq 15 31)"; zero="$(seq 0 14)"
365
+ _verify_l2_bitmap 17
366
+
367
+ echo
368
+ echo "### Writing zeroes 3: compressed clusters (backing file: $use_backing_file) ###"
369
+ echo
370
+ alloc=""; zero=""
371
+ for c in $(seq 18 28); do
372
+ _run_test c=$c sc=0 len=64k cmd=compress
373
+ done
374
+
375
+ # Cluster-aligned request from clusters #18 to #20
376
+ alloc=""; zero="$(seq 0 31)"
377
+ _run_test c=18 sc=0 len=192k cmd=zero
378
+ _verify_l2_bitmap 19
379
+ _verify_l2_bitmap 20
380
+
381
+ # Subcluster-aligned request from clusters #21 to #23.
382
+ # We cannot partially zero a compressed cluster so the code
383
+ # returns -ENOTSUP, which means copy-on-write of the compressed
384
+ # data and fill the rest with actual zeroes on disk.
385
+ # TODO: cluster #22 should use the 'all zeroes' bits.
386
+ alloc="$(seq 0 31)"; zero=""
387
+ _run_test c=21 sc=16 len=128k cmd=zero
388
+ _verify_l2_bitmap 22
389
+ _verify_l2_bitmap 23
390
+
391
+ # Unaligned request from clusters #24 to #26
392
+ # In this case QEMU internally sends a 1k request followed by a
393
+ # subcluster-aligned 128k request. The first request decompresses
394
+ # cluster #24, but that's not enough to perform the second request
395
+ # efficiently because it partially writes to cluster #26 (which is
396
+ # compressed) so we hit the same problem as before.
397
+ alloc="$(seq 0 31)"; zero=""
398
+ _run_test c=24 sc=15 off=1 len=129k cmd=zero
399
+ _verify_l2_bitmap 25
400
+ _verify_l2_bitmap 26
401
+
402
+ # Unaligned request from clusters #27 to #29
403
+ # Similar to the previous case, but this time the tail of the
404
+ # request does not correspond to a compressed cluster, so it can
405
+ # be zeroed efficiently.
406
+ # Note that the very last subcluster is partially written, so if
407
+ # there's a backing file we need to perform cow.
408
+ alloc="$(seq 0 15)"; zero="$(seq 16 31)"
409
+ _run_test c=27 sc=15 off=1 len=128k cmd=zero
410
+ alloc=""; zero="$(seq 0 31)"
411
+ _verify_l2_bitmap 28
412
+ if [ "$use_backing_file" = "yes" ]; then
413
+ alloc="15"; zero="$(seq 0 14)" # copy-on-write happening here
414
+ else
415
+ alloc=""; zero="$(seq 0 15)"
416
+ fi
417
+ _verify_l2_bitmap 29
418
+
419
+ echo
420
+ echo "### Writing zeroes 4: other tests (backing file: $use_backing_file) ###"
421
+ echo
422
+ # Unaligned request in the middle of cluster #30.
423
+ # If there's a backing file we need to allocate and do
424
+ # copy-on-write on the partially zeroed subclusters.
425
+ # If not we can set the 'all zeroes' bit on them.
426
+ if [ "$use_backing_file" = "yes" ]; then
427
+ alloc="15 19"; zero="$(seq 16 18)" # copy-on-write happening here
428
+ else
429
+ alloc=""; zero="$(seq 15 19)"
430
+ fi
431
+ _run_test c=30 sc=15 off=1 len=8k cmd=zero
432
+
433
+ # Fill the last cluster with zeroes, up to the end of the image
434
+ # (the image size is not a multiple of the cluster or subcluster size).
435
+ alloc=""; zero="$(seq 0 17)"
436
+ _run_test c=32 sc=0 len=35k cmd=zero
437
+done
438
+
439
+############################################################
440
+############################################################
441
+############################################################
442
+
443
+# Zero + unmap
444
+for use_backing_file in yes no; do
445
+ echo
446
+ echo "### Zero + unmap 1: allocated clusters (backing file: $use_backing_file) ###"
447
+ echo
448
+ # Note that the image size is not a multiple of the cluster size
449
+ _reset_img 2083k
450
+ alloc="$(seq 0 31)"; zero=""
451
+ _run_test c=9 sc=0 len=576k
452
+ _verify_l2_bitmap 10
453
+ _verify_l2_bitmap 11
454
+ _verify_l2_bitmap 12
455
+ _verify_l2_bitmap 13
456
+ _verify_l2_bitmap 14
457
+ _verify_l2_bitmap 15
458
+ _verify_l2_bitmap 16
459
+ _verify_l2_bitmap 17
460
+
461
+ # Cluster-aligned request from clusters #9 to #11
462
+ alloc=""; zero="$(seq 0 31)"
463
+ _run_test c=9 sc=0 len=192k cmd=unmap
464
+ _verify_l2_bitmap 10
465
+ _verify_l2_bitmap 11
466
+
467
+ # Subcluster-aligned request from clusters #12 to #14
468
+ alloc="$(seq 0 15)"; zero="$(seq 16 31)"
469
+ _run_test c=12 sc=16 len=128k cmd=unmap
470
+ alloc=""; zero="$(seq 0 31)"
471
+ _verify_l2_bitmap 13
472
+ alloc="$(seq 16 31)"; zero="$(seq 0 15)"
473
+ _verify_l2_bitmap 14
474
+
475
+ # Unaligned request from clusters #15 to #17
476
+ alloc="$(seq 0 15)"; zero="$(seq 16 31)"
477
+ _run_test c=15 sc=15 off=1 len=128k cmd=unmap
478
+ alloc=""; zero="$(seq 0 31)"
479
+ _verify_l2_bitmap 16
480
+ alloc="$(seq 15 31)"; zero="$(seq 0 14)"
481
+ _verify_l2_bitmap 17
482
+
483
+ echo
484
+ echo "### Zero + unmap 2: compressed clusters (backing file: $use_backing_file) ###"
485
+ echo
486
+ alloc=""; zero=""
487
+ for c in $(seq 18 28); do
488
+ _run_test c=$c sc=0 len=64k cmd=compress
489
+ done
490
+
491
+ # Cluster-aligned request from clusters #18 to #20
492
+ alloc=""; zero="$(seq 0 31)"
493
+ _run_test c=18 sc=0 len=192k cmd=unmap
494
+ _verify_l2_bitmap 19
495
+ _verify_l2_bitmap 20
496
+
497
+ # Subcluster-aligned request from clusters #21 to #23.
498
+ # We cannot partially zero a compressed cluster so the code
499
+ # returns -ENOTSUP, which means copy-on-write of the compressed
500
+ # data and fill the rest with actual zeroes on disk.
501
+ # TODO: cluster #22 should use the 'all zeroes' bits.
502
+ alloc="$(seq 0 31)"; zero=""
503
+ _run_test c=21 sc=16 len=128k cmd=unmap
504
+ _verify_l2_bitmap 22
505
+ _verify_l2_bitmap 23
506
+
507
+ # Unaligned request from clusters #24 to #26
508
+ # In this case QEMU internally sends a 1k request followed by a
509
+ # subcluster-aligned 128k request. The first request decompresses
510
+ # cluster #24, but that's not enough to perform the second request
511
+ # efficiently because it partially writes to cluster #26 (which is
512
+ # compressed) so we hit the same problem as before.
513
+ alloc="$(seq 0 31)"; zero=""
514
+ _run_test c=24 sc=15 off=1 len=129k cmd=unmap
515
+ _verify_l2_bitmap 25
516
+ _verify_l2_bitmap 26
517
+
518
+ # Unaligned request from clusters #27 to #29
519
+ # Similar to the previous case, but this time the tail of the
520
+ # request does not correspond to a compressed cluster, so it can
521
+ # be zeroed efficiently.
522
+ # Note that the very last subcluster is partially written, so if
523
+ # there's a backing file we need to perform cow.
524
+ alloc="$(seq 0 15)"; zero="$(seq 16 31)"
525
+ _run_test c=27 sc=15 off=1 len=128k cmd=unmap
526
+ alloc=""; zero="$(seq 0 31)"
527
+ _verify_l2_bitmap 28
528
+ if [ "$use_backing_file" = "yes" ]; then
529
+ alloc="15"; zero="$(seq 0 14)" # copy-on-write happening here
530
+ else
531
+ alloc=""; zero="$(seq 0 15)"
532
+ fi
533
+ _verify_l2_bitmap 29
534
+done
535
+
536
+############################################################
537
+############################################################
538
+############################################################
539
+
540
+# Test qcow2_cluster_discard() with full and normal discards
541
+for use_backing_file in yes no; do
542
+ echo
543
+ echo "### Discarding clusters with non-zero bitmaps (backing file: $use_backing_file) ###"
544
+ echo
545
+ if [ "$use_backing_file" = "yes" ]; then
546
+ _make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base" 1M
547
+ else
548
+ _make_test_img -o extended_l2=on 1M
549
+ fi
550
+ # Write clusters #0-#2 and then discard them
551
+ $QEMU_IO -c 'write -q 0 128k' "$TEST_IMG"
552
+ $QEMU_IO -c 'discard -q 0 128k' "$TEST_IMG"
553
+ # 'qemu-io discard' doesn't do a full discard, it zeroizes the
554
+ # cluster, so both clusters have all zero bits set now
555
+ alloc=""; zero="$(seq 0 31)"
556
+ _verify_l2_bitmap 0
557
+ _verify_l2_bitmap 1
558
+ # Now mark the 2nd half of the subclusters from cluster #0 as unallocated
559
+ poke_file "$TEST_IMG" $(($l2_offset+8)) "\x00\x00"
560
+ # Discard cluster #0 again to see how the zero bits have changed
561
+ $QEMU_IO -c 'discard -q 0 64k' "$TEST_IMG"
562
+ # And do a full discard of cluster #1 by shrinking and growing the image
563
+ $QEMU_IMG resize --shrink "$TEST_IMG" 64k
564
+ $QEMU_IMG resize "$TEST_IMG" 1M
565
+ # A normal discard sets all 'zero' bits only if the image has a
566
+ # backing file, otherwise it won't touch them.
567
+ if [ "$use_backing_file" = "yes" ]; then
568
+ alloc=""; zero="$(seq 0 31)"
569
+ else
570
+ alloc=""; zero="$(seq 0 15)"
571
+ fi
572
+ _verify_l2_bitmap 0
573
+ # A full discard should clear the L2 entry completely. However
574
+ # when growing an image with a backing file the new clusters are
575
+ # zeroized to hide the stale data from the backing file
576
+ if [ "$use_backing_file" = "yes" ]; then
577
+ alloc=""; zero="$(seq 0 31)"
578
+ else
579
+ alloc=""; zero=""
580
+ fi
581
+ _verify_l2_bitmap 1
582
+done
583
+
584
+############################################################
585
+############################################################
586
+############################################################
587
+
588
+# Test that corrupted L2 entries are detected in both read and write
589
+# operations
590
+for corruption_test_cmd in read write; do
591
+ echo
592
+ echo "### Corrupted L2 entries - $corruption_test_cmd test (allocated) ###"
593
+ echo
594
+ echo "# 'cluster is zero' bit set on the standard cluster descriptor"
595
+ echo
596
+ # We actually don't consider this a corrupted image.
597
+ # The 'cluster is zero' bit is unused in extended L2 entries so
598
+ # QEMU ignores it.
599
+ # TODO: maybe treat the image as corrupted and make qemu-img check fix it?
600
+ _make_test_img -o extended_l2=on 1M
601
+ $QEMU_IO -c 'write -q -P 0x11 0 2k' "$TEST_IMG"
602
+ poke_file "$TEST_IMG" $(($l2_offset+7)) "\x01"
603
+ alloc="0"; zero=""
604
+ _verify_l2_bitmap 0
605
+ $QEMU_IO -c "$corruption_test_cmd -q -P 0x11 0 1k" "$TEST_IMG"
606
+ if [ "$corruption_test_cmd" = "write" ]; then
607
+ alloc="0"; zero=""
608
+ fi
609
+ _verify_l2_bitmap 0
610
+
611
+ echo
612
+ echo "# Both 'subcluster is zero' and 'subcluster is allocated' bits set"
613
+ echo
614
+ _make_test_img -o extended_l2=on 1M
615
+ # Write from the middle of cluster #0 to the middle of cluster #2
616
+ $QEMU_IO -c 'write -q 32k 128k' "$TEST_IMG"
617
+ # Corrupt the L2 entry from cluster #1
618
+ poke_file_be "$TEST_IMG" $(($l2_offset+24)) 4 1
619
+ alloc="$(seq 0 31)"; zero="0"
620
+ _verify_l2_bitmap 1
621
+ $QEMU_IO -c "$corruption_test_cmd 0 192k" "$TEST_IMG"
622
+
623
+ echo
624
+ echo "### Corrupted L2 entries - $corruption_test_cmd test (unallocated) ###"
625
+ echo
626
+ echo "# 'cluster is zero' bit set on the standard cluster descriptor"
627
+ echo
628
+ # We actually don't consider this a corrupted image.
629
+ # The 'cluster is zero' bit is unused in extended L2 entries so
630
+ # QEMU ignores it.
631
+ # TODO: maybe treat the image as corrupted and make qemu-img check fix it?
632
+ _make_test_img -o extended_l2=on 1M
633
+ # We want to modify the (empty) L2 entry from cluster #0,
634
+ # but we write to #4 in order to initialize the L2 table first
635
+ $QEMU_IO -c 'write -q 256k 1k' "$TEST_IMG"
636
+ poke_file "$TEST_IMG" $(($l2_offset+7)) "\x01"
637
+ alloc=""; zero=""
638
+ _verify_l2_bitmap 0
639
+ $QEMU_IO -c "$corruption_test_cmd -q 0 1k" "$TEST_IMG"
640
+ if [ "$corruption_test_cmd" = "write" ]; then
641
+ alloc="0"; zero=""
642
+ fi
643
+ _verify_l2_bitmap 0
644
+
645
+ echo
646
+ echo "# 'subcluster is allocated' bit set"
647
+ echo
648
+ _make_test_img -o extended_l2=on 1M
649
+ # We want to corrupt the (empty) L2 entry from cluster #0,
650
+ # but we write to #4 in order to initialize the L2 table first
651
+ $QEMU_IO -c 'write -q 256k 1k' "$TEST_IMG"
652
+ poke_file "$TEST_IMG" $(($l2_offset+15)) "\x01"
653
+ alloc="0"; zero=""
654
+ _verify_l2_bitmap 0
655
+ $QEMU_IO -c "$corruption_test_cmd 0 1k" "$TEST_IMG"
656
+
657
+ echo
658
+ echo "# Both 'subcluster is zero' and 'subcluster is allocated' bits set"
659
+ echo
660
+ _make_test_img -o extended_l2=on 1M
661
+ # We want to corrupt the (empty) L2 entry from cluster #1,
662
+ # but we write to #4 in order to initialize the L2 table first
663
+ $QEMU_IO -c 'write -q 256k 1k' "$TEST_IMG"
664
+ # Corrupt the L2 entry from cluster #1
665
+ poke_file_be "$TEST_IMG" $(($l2_offset+24)) 8 $(((1 << 32) | 1))
666
+ alloc="0"; zero="0"
667
+ _verify_l2_bitmap 1
668
+ $QEMU_IO -c "$corruption_test_cmd 0 192k" "$TEST_IMG"
669
+
670
+ echo
671
+ echo "### Compressed cluster with subcluster bitmap != 0 - $corruption_test_cmd test ###"
672
+ echo
673
+ # We actually don't consider this a corrupted image.
674
+ # The bitmap in compressed clusters is unused so QEMU should just ignore it.
675
+ _make_test_img -o extended_l2=on 1M
676
+ $QEMU_IO -c 'write -q -P 11 -c 0 64k' "$TEST_IMG"
677
+ # Change the L2 bitmap to allocate subcluster #31 and zeroize subcluster #0
678
+ poke_file "$TEST_IMG" $(($l2_offset+11)) "\x01\x80"
679
+ alloc="31"; zero="0"
680
+ _verify_l2_bitmap 0
681
+ $QEMU_IO -c "$corruption_test_cmd -P 11 0 64k" "$TEST_IMG" | _filter_qemu_io
682
+ # Writing allocates a new uncompressed cluster so we get a new bitmap
683
+ if [ "$corruption_test_cmd" = "write" ]; then
684
+ alloc="$(seq 0 31)"; zero=""
685
+ fi
686
+ _verify_l2_bitmap 0
687
+done
688
+
689
+############################################################
690
+############################################################
691
+############################################################
692
+
693
+echo
694
+echo "### Detect and repair unaligned clusters ###"
695
+echo
696
+# Create a backing file and fill it with data
697
+$QEMU_IMG create -f raw "$TEST_IMG.base" 128k | _filter_img_create
698
+$QEMU_IO -c "write -q -P 0xff 0 128k" -f raw "$TEST_IMG.base" | _filter_qemu_io
699
+
700
+echo "# Corrupted L2 entry, allocated subcluster #"
701
+# Create a new image, allocate a cluster and write some data to it
702
+_make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base"
703
+$QEMU_IO -c 'write -q -P 1 4k 2k' "$TEST_IMG"
704
+# Corrupt the L2 entry by making the offset unaligned
705
+poke_file "$TEST_IMG" "$(($l2_offset+6))" "\x02"
706
+# This cannot be repaired, qemu-img check will fail to fix it
707
+_check_test_img -r all
708
+# Attempting to read the image will still show that it's corrupted
709
+$QEMU_IO -c 'read -q 0 2k' "$TEST_IMG"
710
+
711
+echo "# Corrupted L2 entry, no allocated subclusters #"
712
+# Create a new image, allocate a cluster and zeroize subcluster #2
713
+_make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base"
714
+$QEMU_IO -c 'write -q -P 1 4k 2k' "$TEST_IMG"
715
+$QEMU_IO -c 'write -q -z 4k 2k' "$TEST_IMG"
716
+# Corrupt the L2 entry by making the offset unaligned
717
+poke_file "$TEST_IMG" "$(($l2_offset+6))" "\x02"
718
+# This time none of the subclusters are allocated so we can repair the image
719
+_check_test_img -r all
720
+# And the data can be read normally
721
+$QEMU_IO -c 'read -q -P 0xff 0 4k' "$TEST_IMG"
722
+$QEMU_IO -c 'read -q -P 0x00 4k 2k' "$TEST_IMG"
723
+$QEMU_IO -c 'read -q -P 0xff 6k 122k' "$TEST_IMG"
724
+
725
+############################################################
726
+############################################################
727
+############################################################
728
+
729
+echo
730
+echo "### Image creation options ###"
731
+echo
732
+echo "# cluster_size < 16k"
733
+_make_test_img -o extended_l2=on,cluster_size=8k 1M
734
+
735
+echo "# backing file and preallocation=metadata"
736
+# For preallocation with backing files, create a backing file first
737
+$QEMU_IMG create -f raw "$TEST_IMG.base" 1M | _filter_img_create
738
+$QEMU_IO -c "write -q -P 0xff 0 1M" -f raw "$TEST_IMG.base" | _filter_qemu_io
739
+
740
+_make_test_img -o extended_l2=on,preallocation=metadata -F raw -b "$TEST_IMG.base" 512k
741
+$QEMU_IMG resize "$TEST_IMG" 1M
742
+$QEMU_IO -c 'read -P 0xff 0 512k' "$TEST_IMG" | _filter_qemu_io
743
+$QEMU_IO -c 'read -P 0x00 512k 512k' "$TEST_IMG" | _filter_qemu_io
744
+$QEMU_IMG map "$TEST_IMG" | _filter_testdir
745
+
746
+echo "# backing file and preallocation=falloc"
747
+_make_test_img -o extended_l2=on,preallocation=falloc -F raw -b "$TEST_IMG.base" 512k
748
+$QEMU_IMG resize "$TEST_IMG" 1M
749
+$QEMU_IO -c 'read -P 0xff 0 512k' "$TEST_IMG" | _filter_qemu_io
750
+$QEMU_IO -c 'read -P 0x00 512k 512k' "$TEST_IMG" | _filter_qemu_io
751
+$QEMU_IMG map "$TEST_IMG" | _filter_testdir
752
+
753
+echo "# backing file and preallocation=full"
754
+_make_test_img -o extended_l2=on,preallocation=full -F raw -b "$TEST_IMG.base" 512k
755
+$QEMU_IMG resize "$TEST_IMG" 1M
756
+$QEMU_IO -c 'read -P 0xff 0 512k' "$TEST_IMG" | _filter_qemu_io
757
+$QEMU_IO -c 'read -P 0x00 512k 512k' "$TEST_IMG" | _filter_qemu_io
758
+$QEMU_IMG map "$TEST_IMG" | _filter_testdir
759
+
760
+echo
761
+echo "### Image resizing with preallocation and backing files ###"
762
+echo
763
+# In this case the new subclusters must have the 'all zeroes' bit set
764
+echo "# resize --preallocation=metadata"
765
+_make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base" 503k
766
+$QEMU_IMG resize --preallocation=metadata "$TEST_IMG" 1013k
767
+$QEMU_IO -c 'read -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
768
+$QEMU_IO -c 'read -P 0x00 503k 510k' "$TEST_IMG" | _filter_qemu_io
769
+
770
+# In this case and the next one the new subclusters must be allocated
771
+echo "# resize --preallocation=falloc"
772
+_make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base" 503k
773
+$QEMU_IMG resize --preallocation=falloc "$TEST_IMG" 1013k
774
+$QEMU_IO -c 'read -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
775
+$QEMU_IO -c 'read -P 0x00 503k 510k' "$TEST_IMG" | _filter_qemu_io
776
+
777
+echo "# resize --preallocation=full"
778
+_make_test_img -o extended_l2=on -F raw -b "$TEST_IMG.base" 503k
779
+$QEMU_IMG resize --preallocation=full "$TEST_IMG" 1013k
780
+$QEMU_IO -c 'read -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
781
+$QEMU_IO -c 'read -P 0x00 503k 510k' "$TEST_IMG" | _filter_qemu_io
782
+
783
+echo
784
+echo "### Image resizing with preallocation without backing files ###"
785
+echo
786
+# In this case the new subclusters must have the 'all zeroes' bit set
787
+echo "# resize --preallocation=metadata"
788
+_make_test_img -o extended_l2=on 503k
789
+$QEMU_IO -c 'write -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
790
+$QEMU_IMG resize --preallocation=metadata "$TEST_IMG" 1013k
791
+$QEMU_IO -c 'read -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
792
+$QEMU_IO -c 'read -P 0x00 503k 510k' "$TEST_IMG" | _filter_qemu_io
793
+
794
+# In this case and the next one the new subclusters must be allocated
795
+echo "# resize --preallocation=falloc"
796
+_make_test_img -o extended_l2=on 503k
797
+$QEMU_IO -c 'write -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
798
+$QEMU_IMG resize --preallocation=falloc "$TEST_IMG" 1013k
799
+$QEMU_IO -c 'read -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
800
+$QEMU_IO -c 'read -P 0x00 503k 510k' "$TEST_IMG" | _filter_qemu_io
801
+
802
+echo "# resize --preallocation=full"
803
+_make_test_img -o extended_l2=on 503k
804
+$QEMU_IO -c 'write -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
805
+$QEMU_IMG resize --preallocation=full "$TEST_IMG" 1013k
806
+$QEMU_IO -c 'read -P 0xff 0 503k' "$TEST_IMG" | _filter_qemu_io
807
+$QEMU_IO -c 'read -P 0x00 503k 510k' "$TEST_IMG" | _filter_qemu_io
808
+
809
+echo
810
+echo "### qemu-img measure ###"
811
+echo
812
+echo "# 512MB, extended_l2=off" # This needs one L2 table
813
+$QEMU_IMG measure --size 512M -O qcow2 -o extended_l2=off
814
+echo "# 512MB, extended_l2=on" # This needs two L2 tables
815
+$QEMU_IMG measure --size 512M -O qcow2 -o extended_l2=on
816
+
817
+echo "# 16K clusters, 64GB, extended_l2=off" # This needs one full L1 table cluster
818
+$QEMU_IMG measure --size 64G -O qcow2 -o cluster_size=16k,extended_l2=off
819
+echo "# 16K clusters, 64GB, extended_l2=on" # This needs two full L2 table clusters
820
+$QEMU_IMG measure --size 64G -O qcow2 -o cluster_size=16k,extended_l2=on
821
+
822
+echo "# 8k clusters" # This should fail
823
+$QEMU_IMG measure --size 1M -O qcow2 -o cluster_size=8k,extended_l2=on
824
+
825
+echo "# 1024 TB" # Maximum allowed size with extended_l2=on and 64K clusters
826
+$QEMU_IMG measure --size 1024T -O qcow2 -o extended_l2=on
827
+echo "# 1025 TB" # This should fail
828
+$QEMU_IMG measure --size 1025T -O qcow2 -o extended_l2=on
829
+
830
+echo
831
+echo "### qemu-img amend ###"
832
+echo
833
+_make_test_img -o extended_l2=on 1M
834
+$QEMU_IMG amend -o extended_l2=off "$TEST_IMG" && echo "Unexpected pass"
835
+
836
+_make_test_img -o extended_l2=off 1M
837
+$QEMU_IMG amend -o extended_l2=on "$TEST_IMG" && echo "Unexpected pass"
838
+
839
+echo
840
+echo "### Test copy-on-write on an image with snapshots ###"
841
+echo
842
+_make_test_img -o extended_l2=on 1M
843
+
844
+# For each cluster from #0 to #9 this loop zeroes subcluster #7
845
+# and allocates subclusters #13 and #18.
846
+alloc="13 18"; zero="7"
847
+for c in $(seq 0 9); do
848
+ $QEMU_IO -c "write -q -z $((64*$c+14))k 2k" \
849
+ -c "write -q -P $((0xd0+$c)) $((64*$c+26))k 2k" \
850
+ -c "write -q -P $((0xe0+$c)) $((64*$c+36))k 2k" "$TEST_IMG"
851
+ _verify_l2_bitmap "$c"
852
+done
853
+
854
+# Create a snapshot and set l2_offset to the new L2 table
855
+$QEMU_IMG snapshot -c snap1 "$TEST_IMG"
856
+l2_offset=$((0x110000))
857
+
858
+# Write different patterns to each one of the clusters
859
+# in order to see how copy-on-write behaves in each case.
860
+$QEMU_IO -c "write -q -P 0xf0 $((64*0+30))k 1k" \
861
+ -c "write -q -P 0xf1 $((64*1+20))k 1k" \
862
+ -c "write -q -P 0xf2 $((64*2+40))k 1k" \
863
+ -c "write -q -P 0xf3 $((64*3+26))k 1k" \
864
+ -c "write -q -P 0xf4 $((64*4+14))k 1k" \
865
+ -c "write -q -P 0xf5 $((64*5+1))k 1k" \
866
+ -c "write -q -z $((64*6+30))k 3k" \
867
+ -c "write -q -z $((64*7+26))k 2k" \
868
+ -c "write -q -z $((64*8+26))k 1k" \
869
+ -c "write -q -z $((64*9+12))k 1k" \
870
+ "$TEST_IMG"
871
+alloc="$(seq 13 18)"; zero="7" _verify_l2_bitmap 0
872
+alloc="$(seq 10 18)"; zero="7" _verify_l2_bitmap 1
873
+alloc="$(seq 13 20)"; zero="7" _verify_l2_bitmap 2
874
+alloc="$(seq 13 18)"; zero="7" _verify_l2_bitmap 3
875
+alloc="$(seq 7 18)"; zero="" _verify_l2_bitmap 4
876
+alloc="$(seq 0 18)"; zero="" _verify_l2_bitmap 5
877
+alloc="13 18"; zero="7 15 16" _verify_l2_bitmap 6
878
+alloc="18"; zero="7 13" _verify_l2_bitmap 7
879
+alloc="$(seq 13 18)"; zero="7" _verify_l2_bitmap 8
880
+alloc="13 18"; zero="6 7" _verify_l2_bitmap 9
881
+
882
+echo
883
+echo "### Test concurrent requests ###"
884
+echo
885
+
886
+_concurrent_io()
887
+{
888
+# Allocate three subclusters in the same cluster.
889
+# This works because handle_dependencies() checks whether the requests
890
+# allocate the same cluster, even if the COW regions don't overlap (in
891
+# this case they don't).
892
+cat <<EOF
893
+open -o driver=$IMGFMT blkdebug::$TEST_IMG
894
+break write_aio A
895
+aio_write -P 10 30k 2k
896
+wait_break A
897
+aio_write -P 11 20k 2k
898
+aio_write -P 12 40k 2k
899
+resume A
900
+aio_flush
901
+EOF
902
+}
903
+
904
+_concurrent_verify()
905
+{
906
+cat <<EOF
907
+open -o driver=$IMGFMT $TEST_IMG
908
+read -q -P 10 30k 2k
909
+read -q -P 11 20k 2k
910
+read -q -P 12 40k 2k
911
+EOF
912
+}
913
+
914
+_make_test_img -o extended_l2=on 1M
915
+_concurrent_io | $QEMU_IO | _filter_qemu_io
916
+_concurrent_verify | $QEMU_IO | _filter_qemu_io
917
+
918
+# success, all done
919
+echo "*** done"
920
+rm -f $seq.full
921
+status=0
922
diff --git a/tests/qemu-iotests/271.out b/tests/qemu-iotests/271.out
923
new file mode 100644
924
index XXXXXXX..XXXXXXX
925
--- /dev/null
926
+++ b/tests/qemu-iotests/271.out
927
@@ -XXX,XX +XXX,XX @@
928
+QA output created by 271
929
+
930
+### Standard write tests (backing file: yes) ###
931
+
932
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=1048576
933
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=1048576
934
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
935
+write -q -P PATTERN 0 1k
936
+L2 entry #0: 0x8000000000050000 0000000000000001
937
+write -q -P PATTERN 3k 512
938
+L2 entry #0: 0x8000000000050000 0000000000000003
939
+write -q -P PATTERN 5k 1k
940
+L2 entry #0: 0x8000000000050000 0000000000000007
941
+write -q -P PATTERN 6k 2k
942
+L2 entry #0: 0x8000000000050000 000000000000000f
943
+write -q -P PATTERN 8k 6k
944
+L2 entry #0: 0x8000000000050000 000000000000007f
945
+write -q -P PATTERN 15k 4k
946
+L2 entry #0: 0x8000000000050000 00000000000003ff
947
+write -q -P PATTERN 32k 1k
948
+L2 entry #0: 0x8000000000050000 00000000000103ff
949
+write -q -P PATTERN 63k 4k
950
+L2 entry #0: 0x8000000000050000 00000000800103ff
951
+L2 entry #1: 0x8000000000060000 0000000000000003
952
+write -q -z 2k 2k
953
+L2 entry #0: 0x8000000000050000 00000002800103fd
954
+write -q -z 0 64k
955
+L2 entry #0: 0x8000000000050000 ffffffff00000000
956
+write -q -P PATTERN 0 64k
957
+L2 entry #0: 0x8000000000050000 00000000ffffffff
958
+write -q -z -u 0 32k
959
+L2 entry #0: 0x8000000000050000 0000ffffffff0000
960
+write -q -z -u 0 64k
961
+L2 entry #0: 0x0000000000000000 ffffffff00000000
962
+write -q -P PATTERN 3k 512
963
+L2 entry #0: 0x8000000000050000 fffffffd00000002
964
+write -q -P PATTERN 0 64k
965
+L2 entry #0: 0x8000000000050000 00000000ffffffff
966
+discard -q 0 64k
967
+L2 entry #0: 0x0000000000000000 ffffffff00000000
968
+write -q -c -P PATTERN 0 64k
969
+L2 entry #0: 0x4000000000050000 0000000000000000
970
+write -q -P PATTERN 3k 512
971
+L2 entry #0: 0x8000000000070000 00000000ffffffff
972
+
973
+### Standard write tests (backing file: no) ###
974
+
975
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=1048576
976
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
977
+write -q -P PATTERN 0 1k
978
+L2 entry #0: 0x8000000000050000 0000000000000001
979
+write -q -P PATTERN 3k 512
980
+L2 entry #0: 0x8000000000050000 0000000000000003
981
+write -q -P PATTERN 5k 1k
982
+L2 entry #0: 0x8000000000050000 0000000000000007
983
+write -q -P PATTERN 6k 2k
984
+L2 entry #0: 0x8000000000050000 000000000000000f
985
+write -q -P PATTERN 8k 6k
986
+L2 entry #0: 0x8000000000050000 000000000000007f
987
+write -q -P PATTERN 15k 4k
988
+L2 entry #0: 0x8000000000050000 00000000000003ff
989
+write -q -P PATTERN 32k 1k
990
+L2 entry #0: 0x8000000000050000 00000000000103ff
991
+write -q -P PATTERN 63k 4k
992
+L2 entry #0: 0x8000000000050000 00000000800103ff
993
+L2 entry #1: 0x8000000000060000 0000000000000003
994
+write -q -z 2k 2k
995
+L2 entry #0: 0x8000000000050000 00000002800103fd
996
+write -q -z 0 64k
997
+L2 entry #0: 0x8000000000050000 ffffffff00000000
998
+write -q -P PATTERN 0 64k
999
+L2 entry #0: 0x8000000000050000 00000000ffffffff
1000
+write -q -z -u 0 32k
1001
+L2 entry #0: 0x8000000000050000 0000ffffffff0000
1002
+write -q -z -u 0 64k
1003
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1004
+write -q -P PATTERN 3k 512
1005
+L2 entry #0: 0x8000000000050000 fffffffd00000002
1006
+write -q -P PATTERN 0 64k
1007
+L2 entry #0: 0x8000000000050000 00000000ffffffff
1008
+discard -q 0 64k
1009
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1010
+write -q -c -P PATTERN 0 64k
1011
+L2 entry #0: 0x4000000000050000 0000000000000000
1012
+write -q -P PATTERN 3k 512
1013
+L2 entry #0: 0x8000000000070000 00000000ffffffff
1014
+
1015
+### Overwriting several clusters without COW ###
1016
+
1017
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=1048576
1018
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1019
+write -q -P PATTERN 24k 40k
1020
+L2 entry #0: 0x8000000000050000 00000000fffff000
1021
+write -q -P PATTERN 90k 2k
1022
+L2 entry #1: 0x8000000000060000 0000000000002000
1023
+write -q -P PATTERN 156k 2k
1024
+L2 entry #2: 0x8000000000070000 0000000000004000
1025
+write -q -z 156k 2k
1026
+L2 entry #2: 0x8000000000070000 0000400000000000
1027
+write -q -P PATTERN 192k 34k
1028
+L2 entry #3: 0x8000000000080000 000000000001ffff
1029
+write -q -P PATTERN 24k 192k
1030
+L2 entry #0: 0x8000000000050000 00000000fffff000
1031
+L2 entry #1: 0x8000000000060000 00000000ffffffff
1032
+L2 entry #2: 0x8000000000070000 00000000ffffffff
1033
+L2 entry #3: 0x8000000000080000 000000000001ffff
1034
+
1035
+### Writing zeroes 1: unallocated clusters (backing file: yes) ###
1036
+
1037
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=2132992
1038
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=2132992
1039
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2132992 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1040
+write -q -z 0 192k
1041
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1042
+L2 entry #1: 0x0000000000000000 ffffffff00000000
1043
+L2 entry #2: 0x0000000000000000 ffffffff00000000
1044
+write -q -z 224k 128k
1045
+L2 entry #3: 0x0000000000000000 ffff000000000000
1046
+L2 entry #4: 0x0000000000000000 ffffffff00000000
1047
+L2 entry #5: 0x0000000000000000 0000ffff00000000
1048
+write -q -z 415k 128k
1049
+L2 entry #6: 0x8000000000050000 ffff000000008000
1050
+L2 entry #7: 0x0000000000000000 ffffffff00000000
1051
+L2 entry #8: 0x8000000000060000 00007fff00008000
1052
+
1053
+### Writing zeroes 2: allocated clusters (backing file: yes) ###
1054
+
1055
+write -q -P PATTERN 576k 576k
1056
+L2 entry #9: 0x8000000000070000 00000000ffffffff
1057
+L2 entry #10: 0x8000000000080000 00000000ffffffff
1058
+L2 entry #11: 0x8000000000090000 00000000ffffffff
1059
+L2 entry #12: 0x80000000000a0000 00000000ffffffff
1060
+L2 entry #13: 0x80000000000b0000 00000000ffffffff
1061
+L2 entry #14: 0x80000000000c0000 00000000ffffffff
1062
+L2 entry #15: 0x80000000000d0000 00000000ffffffff
1063
+L2 entry #16: 0x80000000000e0000 00000000ffffffff
1064
+L2 entry #17: 0x80000000000f0000 00000000ffffffff
1065
+write -q -z 576k 192k
1066
+L2 entry #9: 0x8000000000070000 ffffffff00000000
1067
+L2 entry #10: 0x8000000000080000 ffffffff00000000
1068
+L2 entry #11: 0x8000000000090000 ffffffff00000000
1069
+write -q -z 800k 128k
1070
+L2 entry #12: 0x80000000000a0000 ffff00000000ffff
1071
+L2 entry #13: 0x80000000000b0000 ffffffff00000000
1072
+L2 entry #14: 0x80000000000c0000 0000ffffffff0000
1073
+write -q -z 991k 128k
1074
+L2 entry #15: 0x80000000000d0000 ffff00000000ffff
1075
+L2 entry #16: 0x80000000000e0000 ffffffff00000000
1076
+L2 entry #17: 0x80000000000f0000 00007fffffff8000
1077
+
1078
+### Writing zeroes 3: compressed clusters (backing file: yes) ###
1079
+
1080
+write -q -c -P PATTERN 1152k 64k
1081
+L2 entry #18: 0x4000000000100000 0000000000000000
1082
+write -q -c -P PATTERN 1216k 64k
1083
+L2 entry #19: 0x4000000000110000 0000000000000000
1084
+write -q -c -P PATTERN 1280k 64k
1085
+L2 entry #20: 0x4000000000120000 0000000000000000
1086
+write -q -c -P PATTERN 1344k 64k
1087
+L2 entry #21: 0x4000000000130000 0000000000000000
1088
+write -q -c -P PATTERN 1408k 64k
1089
+L2 entry #22: 0x4000000000140000 0000000000000000
1090
+write -q -c -P PATTERN 1472k 64k
1091
+L2 entry #23: 0x4000000000150000 0000000000000000
1092
+write -q -c -P PATTERN 1536k 64k
1093
+L2 entry #24: 0x4000000000160000 0000000000000000
1094
+write -q -c -P PATTERN 1600k 64k
1095
+L2 entry #25: 0x4000000000170000 0000000000000000
1096
+write -q -c -P PATTERN 1664k 64k
1097
+L2 entry #26: 0x4000000000180000 0000000000000000
1098
+write -q -c -P PATTERN 1728k 64k
1099
+L2 entry #27: 0x4000000000190000 0000000000000000
1100
+write -q -c -P PATTERN 1792k 64k
1101
+L2 entry #28: 0x40000000001a0000 0000000000000000
1102
+write -q -z 1152k 192k
1103
+L2 entry #18: 0x0000000000000000 ffffffff00000000
1104
+L2 entry #19: 0x0000000000000000 ffffffff00000000
1105
+L2 entry #20: 0x0000000000000000 ffffffff00000000
1106
+write -q -z 1376k 128k
1107
+L2 entry #21: 0x8000000000100000 00000000ffffffff
1108
+L2 entry #22: 0x8000000000110000 00000000ffffffff
1109
+L2 entry #23: 0x8000000000120000 00000000ffffffff
1110
+write -q -z 1567k 129k
1111
+L2 entry #24: 0x8000000000130000 00000000ffffffff
1112
+L2 entry #25: 0x8000000000140000 00000000ffffffff
1113
+L2 entry #26: 0x8000000000150000 00000000ffffffff
1114
+write -q -z 1759k 128k
1115
+L2 entry #27: 0x8000000000160000 ffff00000000ffff
1116
+L2 entry #28: 0x0000000000000000 ffffffff00000000
1117
+L2 entry #29: 0x8000000000170000 00007fff00008000
1118
+
1119
+### Writing zeroes 4: other tests (backing file: yes) ###
1120
+
1121
+write -q -z 1951k 8k
1122
+L2 entry #30: 0x8000000000180000 0007000000088000
1123
+write -q -z 2048k 35k
1124
+L2 entry #32: 0x0000000000000000 0003ffff00000000
1125
+
1126
+### Writing zeroes 1: unallocated clusters (backing file: no) ###
1127
+
1128
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=2132992
1129
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2132992
1130
+write -q -z 0 192k
1131
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1132
+L2 entry #1: 0x0000000000000000 ffffffff00000000
1133
+L2 entry #2: 0x0000000000000000 ffffffff00000000
1134
+write -q -z 224k 128k
1135
+L2 entry #3: 0x0000000000000000 ffff000000000000
1136
+L2 entry #4: 0x0000000000000000 ffffffff00000000
1137
+L2 entry #5: 0x0000000000000000 0000ffff00000000
1138
+write -q -z 415k 128k
1139
+L2 entry #6: 0x0000000000000000 ffff800000000000
1140
+L2 entry #7: 0x0000000000000000 ffffffff00000000
1141
+L2 entry #8: 0x0000000000000000 0000ffff00000000
1142
+
1143
+### Writing zeroes 2: allocated clusters (backing file: no) ###
1144
+
1145
+write -q -P PATTERN 576k 576k
1146
+L2 entry #9: 0x8000000000050000 00000000ffffffff
1147
+L2 entry #10: 0x8000000000060000 00000000ffffffff
1148
+L2 entry #11: 0x8000000000070000 00000000ffffffff
1149
+L2 entry #12: 0x8000000000080000 00000000ffffffff
1150
+L2 entry #13: 0x8000000000090000 00000000ffffffff
1151
+L2 entry #14: 0x80000000000a0000 00000000ffffffff
1152
+L2 entry #15: 0x80000000000b0000 00000000ffffffff
1153
+L2 entry #16: 0x80000000000c0000 00000000ffffffff
1154
+L2 entry #17: 0x80000000000d0000 00000000ffffffff
1155
+write -q -z 576k 192k
1156
+L2 entry #9: 0x8000000000050000 ffffffff00000000
1157
+L2 entry #10: 0x8000000000060000 ffffffff00000000
1158
+L2 entry #11: 0x8000000000070000 ffffffff00000000
1159
+write -q -z 800k 128k
1160
+L2 entry #12: 0x8000000000080000 ffff00000000ffff
1161
+L2 entry #13: 0x8000000000090000 ffffffff00000000
1162
+L2 entry #14: 0x80000000000a0000 0000ffffffff0000
1163
+write -q -z 991k 128k
1164
+L2 entry #15: 0x80000000000b0000 ffff00000000ffff
1165
+L2 entry #16: 0x80000000000c0000 ffffffff00000000
1166
+L2 entry #17: 0x80000000000d0000 00007fffffff8000
1167
+
1168
+### Writing zeroes 3: compressed clusters (backing file: no) ###
1169
+
1170
+write -q -c -P PATTERN 1152k 64k
1171
+L2 entry #18: 0x40000000000e0000 0000000000000000
1172
+write -q -c -P PATTERN 1216k 64k
1173
+L2 entry #19: 0x40000000000f0000 0000000000000000
1174
+write -q -c -P PATTERN 1280k 64k
1175
+L2 entry #20: 0x4000000000100000 0000000000000000
1176
+write -q -c -P PATTERN 1344k 64k
1177
+L2 entry #21: 0x4000000000110000 0000000000000000
1178
+write -q -c -P PATTERN 1408k 64k
1179
+L2 entry #22: 0x4000000000120000 0000000000000000
1180
+write -q -c -P PATTERN 1472k 64k
1181
+L2 entry #23: 0x4000000000130000 0000000000000000
1182
+write -q -c -P PATTERN 1536k 64k
1183
+L2 entry #24: 0x4000000000140000 0000000000000000
1184
+write -q -c -P PATTERN 1600k 64k
1185
+L2 entry #25: 0x4000000000150000 0000000000000000
1186
+write -q -c -P PATTERN 1664k 64k
1187
+L2 entry #26: 0x4000000000160000 0000000000000000
1188
+write -q -c -P PATTERN 1728k 64k
1189
+L2 entry #27: 0x4000000000170000 0000000000000000
1190
+write -q -c -P PATTERN 1792k 64k
1191
+L2 entry #28: 0x4000000000180000 0000000000000000
1192
+write -q -z 1152k 192k
1193
+L2 entry #18: 0x0000000000000000 ffffffff00000000
1194
+L2 entry #19: 0x0000000000000000 ffffffff00000000
1195
+L2 entry #20: 0x0000000000000000 ffffffff00000000
1196
+write -q -z 1376k 128k
1197
+L2 entry #21: 0x80000000000e0000 00000000ffffffff
1198
+L2 entry #22: 0x80000000000f0000 00000000ffffffff
1199
+L2 entry #23: 0x8000000000100000 00000000ffffffff
1200
+write -q -z 1567k 129k
1201
+L2 entry #24: 0x8000000000110000 00000000ffffffff
1202
+L2 entry #25: 0x8000000000120000 00000000ffffffff
1203
+L2 entry #26: 0x8000000000130000 00000000ffffffff
1204
+write -q -z 1759k 128k
1205
+L2 entry #27: 0x8000000000140000 ffff00000000ffff
1206
+L2 entry #28: 0x0000000000000000 ffffffff00000000
1207
+L2 entry #29: 0x0000000000000000 0000ffff00000000
1208
+
1209
+### Writing zeroes 4: other tests (backing file: no) ###
1210
+
1211
+write -q -z 1951k 8k
1212
+L2 entry #30: 0x0000000000000000 000f800000000000
1213
+write -q -z 2048k 35k
1214
+L2 entry #32: 0x0000000000000000 0003ffff00000000
1215
+
1216
+### Zero + unmap 1: allocated clusters (backing file: yes) ###
1217
+
1218
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=2132992
1219
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=2132992
1220
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2132992 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1221
+write -q -P PATTERN 576k 576k
1222
+L2 entry #9: 0x8000000000050000 00000000ffffffff
1223
+L2 entry #10: 0x8000000000060000 00000000ffffffff
1224
+L2 entry #11: 0x8000000000070000 00000000ffffffff
1225
+L2 entry #12: 0x8000000000080000 00000000ffffffff
1226
+L2 entry #13: 0x8000000000090000 00000000ffffffff
1227
+L2 entry #14: 0x80000000000a0000 00000000ffffffff
1228
+L2 entry #15: 0x80000000000b0000 00000000ffffffff
1229
+L2 entry #16: 0x80000000000c0000 00000000ffffffff
1230
+L2 entry #17: 0x80000000000d0000 00000000ffffffff
1231
+write -q -z -u 576k 192k
1232
+L2 entry #9: 0x0000000000000000 ffffffff00000000
1233
+L2 entry #10: 0x0000000000000000 ffffffff00000000
1234
+L2 entry #11: 0x0000000000000000 ffffffff00000000
1235
+write -q -z -u 800k 128k
1236
+L2 entry #12: 0x8000000000080000 ffff00000000ffff
1237
+L2 entry #13: 0x0000000000000000 ffffffff00000000
1238
+L2 entry #14: 0x80000000000a0000 0000ffffffff0000
1239
+write -q -z -u 991k 128k
1240
+L2 entry #15: 0x80000000000b0000 ffff00000000ffff
1241
+L2 entry #16: 0x0000000000000000 ffffffff00000000
1242
+L2 entry #17: 0x80000000000d0000 00007fffffff8000
1243
+
1244
+### Zero + unmap 2: compressed clusters (backing file: yes) ###
1245
+
1246
+write -q -c -P PATTERN 1152k 64k
1247
+L2 entry #18: 0x4000000000050000 0000000000000000
1248
+write -q -c -P PATTERN 1216k 64k
1249
+L2 entry #19: 0x4000000000060000 0000000000000000
1250
+write -q -c -P PATTERN 1280k 64k
1251
+L2 entry #20: 0x4000000000070000 0000000000000000
1252
+write -q -c -P PATTERN 1344k 64k
1253
+L2 entry #21: 0x4000000000090000 0000000000000000
1254
+write -q -c -P PATTERN 1408k 64k
1255
+L2 entry #22: 0x40000000000c0000 0000000000000000
1256
+write -q -c -P PATTERN 1472k 64k
1257
+L2 entry #23: 0x40000000000e0000 0000000000000000
1258
+write -q -c -P PATTERN 1536k 64k
1259
+L2 entry #24: 0x40000000000f0000 0000000000000000
1260
+write -q -c -P PATTERN 1600k 64k
1261
+L2 entry #25: 0x4000000000100000 0000000000000000
1262
+write -q -c -P PATTERN 1664k 64k
1263
+L2 entry #26: 0x4000000000110000 0000000000000000
1264
+write -q -c -P PATTERN 1728k 64k
1265
+L2 entry #27: 0x4000000000120000 0000000000000000
1266
+write -q -c -P PATTERN 1792k 64k
1267
+L2 entry #28: 0x4000000000130000 0000000000000000
1268
+write -q -z -u 1152k 192k
1269
+L2 entry #18: 0x0000000000000000 ffffffff00000000
1270
+L2 entry #19: 0x0000000000000000 ffffffff00000000
1271
+L2 entry #20: 0x0000000000000000 ffffffff00000000
1272
+write -q -z -u 1376k 128k
1273
+L2 entry #21: 0x8000000000050000 00000000ffffffff
1274
+L2 entry #22: 0x8000000000060000 00000000ffffffff
1275
+L2 entry #23: 0x8000000000070000 00000000ffffffff
1276
+write -q -z -u 1567k 129k
1277
+L2 entry #24: 0x8000000000090000 00000000ffffffff
1278
+L2 entry #25: 0x80000000000e0000 00000000ffffffff
1279
+L2 entry #26: 0x80000000000f0000 00000000ffffffff
1280
+write -q -z -u 1759k 128k
1281
+L2 entry #27: 0x80000000000c0000 ffff00000000ffff
1282
+L2 entry #28: 0x0000000000000000 ffffffff00000000
1283
+L2 entry #29: 0x8000000000100000 00007fff00008000
1284
+
1285
+### Zero + unmap 1: allocated clusters (backing file: no) ###
1286
+
1287
+Formatting 'TEST_DIR/t.IMGFMT.raw', fmt=raw size=2132992
1288
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2132992
1289
+write -q -P PATTERN 576k 576k
1290
+L2 entry #9: 0x8000000000050000 00000000ffffffff
1291
+L2 entry #10: 0x8000000000060000 00000000ffffffff
1292
+L2 entry #11: 0x8000000000070000 00000000ffffffff
1293
+L2 entry #12: 0x8000000000080000 00000000ffffffff
1294
+L2 entry #13: 0x8000000000090000 00000000ffffffff
1295
+L2 entry #14: 0x80000000000a0000 00000000ffffffff
1296
+L2 entry #15: 0x80000000000b0000 00000000ffffffff
1297
+L2 entry #16: 0x80000000000c0000 00000000ffffffff
1298
+L2 entry #17: 0x80000000000d0000 00000000ffffffff
1299
+write -q -z -u 576k 192k
1300
+L2 entry #9: 0x0000000000000000 ffffffff00000000
1301
+L2 entry #10: 0x0000000000000000 ffffffff00000000
1302
+L2 entry #11: 0x0000000000000000 ffffffff00000000
1303
+write -q -z -u 800k 128k
1304
+L2 entry #12: 0x8000000000080000 ffff00000000ffff
1305
+L2 entry #13: 0x0000000000000000 ffffffff00000000
1306
+L2 entry #14: 0x80000000000a0000 0000ffffffff0000
1307
+write -q -z -u 991k 128k
1308
+L2 entry #15: 0x80000000000b0000 ffff00000000ffff
1309
+L2 entry #16: 0x0000000000000000 ffffffff00000000
1310
+L2 entry #17: 0x80000000000d0000 00007fffffff8000
1311
+
1312
+### Zero + unmap 2: compressed clusters (backing file: no) ###
1313
+
1314
+write -q -c -P PATTERN 1152k 64k
1315
+L2 entry #18: 0x4000000000050000 0000000000000000
1316
+write -q -c -P PATTERN 1216k 64k
1317
+L2 entry #19: 0x4000000000060000 0000000000000000
1318
+write -q -c -P PATTERN 1280k 64k
1319
+L2 entry #20: 0x4000000000070000 0000000000000000
1320
+write -q -c -P PATTERN 1344k 64k
1321
+L2 entry #21: 0x4000000000090000 0000000000000000
1322
+write -q -c -P PATTERN 1408k 64k
1323
+L2 entry #22: 0x40000000000c0000 0000000000000000
1324
+write -q -c -P PATTERN 1472k 64k
1325
+L2 entry #23: 0x40000000000e0000 0000000000000000
1326
+write -q -c -P PATTERN 1536k 64k
1327
+L2 entry #24: 0x40000000000f0000 0000000000000000
1328
+write -q -c -P PATTERN 1600k 64k
1329
+L2 entry #25: 0x4000000000100000 0000000000000000
1330
+write -q -c -P PATTERN 1664k 64k
1331
+L2 entry #26: 0x4000000000110000 0000000000000000
1332
+write -q -c -P PATTERN 1728k 64k
1333
+L2 entry #27: 0x4000000000120000 0000000000000000
1334
+write -q -c -P PATTERN 1792k 64k
1335
+L2 entry #28: 0x4000000000130000 0000000000000000
1336
+write -q -z -u 1152k 192k
1337
+L2 entry #18: 0x0000000000000000 ffffffff00000000
1338
+L2 entry #19: 0x0000000000000000 ffffffff00000000
1339
+L2 entry #20: 0x0000000000000000 ffffffff00000000
1340
+write -q -z -u 1376k 128k
1341
+L2 entry #21: 0x8000000000050000 00000000ffffffff
1342
+L2 entry #22: 0x8000000000060000 00000000ffffffff
1343
+L2 entry #23: 0x8000000000070000 00000000ffffffff
1344
+write -q -z -u 1567k 129k
1345
+L2 entry #24: 0x8000000000090000 00000000ffffffff
1346
+L2 entry #25: 0x80000000000e0000 00000000ffffffff
1347
+L2 entry #26: 0x80000000000f0000 00000000ffffffff
1348
+write -q -z -u 1759k 128k
1349
+L2 entry #27: 0x80000000000c0000 ffff00000000ffff
1350
+L2 entry #28: 0x0000000000000000 ffffffff00000000
1351
+L2 entry #29: 0x0000000000000000 0000ffff00000000
1352
+
1353
+### Discarding clusters with non-zero bitmaps (backing file: yes) ###
1354
+
1355
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1356
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1357
+L2 entry #1: 0x0000000000000000 ffffffff00000000
1358
+Image resized.
1359
+Image resized.
1360
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1361
+L2 entry #1: 0x0000000000000000 ffffffff00000000
1362
+
1363
+### Discarding clusters with non-zero bitmaps (backing file: no) ###
1364
+
1365
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1366
+L2 entry #0: 0x0000000000000000 ffffffff00000000
1367
+L2 entry #1: 0x0000000000000000 ffffffff00000000
1368
+Image resized.
1369
+Image resized.
1370
+L2 entry #0: 0x0000000000000000 0000ffff00000000
1371
+L2 entry #1: 0x0000000000000000 0000000000000000
1372
+
1373
+### Corrupted L2 entries - read test (allocated) ###
1374
+
1375
+# 'cluster is zero' bit set on the standard cluster descriptor
1376
+
1377
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1378
+L2 entry #0: 0x8000000000050001 0000000000000001
1379
+L2 entry #0: 0x8000000000050001 0000000000000001
1380
+
1381
+# Both 'subcluster is zero' and 'subcluster is allocated' bits set
1382
+
1383
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1384
+L2 entry #1: 0x8000000000060000 00000001ffffffff
1385
+qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed
1386
+read failed: Input/output error
1387
+
1388
+### Corrupted L2 entries - read test (unallocated) ###
1389
+
1390
+# 'cluster is zero' bit set on the standard cluster descriptor
1391
+
1392
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1393
+L2 entry #0: 0x0000000000000001 0000000000000000
1394
+L2 entry #0: 0x0000000000000001 0000000000000000
1395
+
1396
+# 'subcluster is allocated' bit set
1397
+
1398
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1399
+L2 entry #0: 0x0000000000000000 0000000000000001
1400
+qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed
1401
+read failed: Input/output error
1402
+
1403
+# Both 'subcluster is zero' and 'subcluster is allocated' bits set
1404
+
1405
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1406
+L2 entry #1: 0x0000000000000000 0000000100000001
1407
+qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed
1408
+read failed: Input/output error
1409
+
1410
+### Compressed cluster with subcluster bitmap != 0 - read test ###
1411
+
1412
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1413
+L2 entry #0: 0x4000000000050000 0000000180000000
1414
+read 65536/65536 bytes at offset 0
1415
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1416
+L2 entry #0: 0x4000000000050000 0000000180000000
1417
+
1418
+### Corrupted L2 entries - write test (allocated) ###
1419
+
1420
+# 'cluster is zero' bit set on the standard cluster descriptor
1421
+
1422
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1423
+L2 entry #0: 0x8000000000050001 0000000000000001
1424
+L2 entry #0: 0x8000000000050001 0000000000000001
1425
+
1426
+# Both 'subcluster is zero' and 'subcluster is allocated' bits set
1427
+
1428
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1429
+L2 entry #1: 0x8000000000060000 00000001ffffffff
1430
+qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed
1431
+write failed: Input/output error
1432
+
1433
+### Corrupted L2 entries - write test (unallocated) ###
1434
+
1435
+# 'cluster is zero' bit set on the standard cluster descriptor
1436
+
1437
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1438
+L2 entry #0: 0x0000000000000001 0000000000000000
1439
+L2 entry #0: 0x8000000000060000 0000000000000001
1440
+
1441
+# 'subcluster is allocated' bit set
1442
+
1443
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1444
+L2 entry #0: 0x0000000000000000 0000000000000001
1445
+qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed
1446
+write failed: Input/output error
1447
+
1448
+# Both 'subcluster is zero' and 'subcluster is allocated' bits set
1449
+
1450
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1451
+L2 entry #1: 0x0000000000000000 0000000100000001
1452
+qcow2: Marking image as corrupt: Invalid cluster entry found (L2 offset: 0x40000, L2 index: 0x1); further corruption events will be suppressed
1453
+write failed: Input/output error
1454
+
1455
+### Compressed cluster with subcluster bitmap != 0 - write test ###
1456
+
1457
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1458
+L2 entry #0: 0x4000000000050000 0000000180000000
1459
+wrote 65536/65536 bytes at offset 0
1460
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1461
+L2 entry #0: 0x8000000000060000 00000000ffffffff
1462
+
1463
+### Detect and repair unaligned clusters ###
1464
+
1465
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=131072
1466
+# Corrupted L2 entry, allocated subcluster #
1467
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1468
+ERROR offset=50200: Data cluster is not properly aligned; L2 entry corrupted.
1469
+ERROR cluster 6 refcount=0 reference=1
1470
+Rebuilding refcount structure
1471
+ERROR offset=50200: Data cluster is not properly aligned; L2 entry corrupted.
1472
+Repairing cluster 1 refcount=1 reference=0
1473
+Repairing cluster 2 refcount=1 reference=0
1474
+ERROR offset=50200: Data cluster is not properly aligned; L2 entry corrupted.
1475
+The following inconsistencies were found and repaired:
1476
+
1477
+ 0 leaked clusters
1478
+ 1 corruptions
1479
+
1480
+Double checking the fixed image now...
1481
+
1482
+1 errors were found on the image.
1483
+Data may be corrupted, or further writes to the image may corrupt it.
1484
+qcow2: Marking image as corrupt: Cluster allocation offset 0x50200 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed
1485
+read failed: Input/output error
1486
+# Corrupted L2 entry, no allocated subclusters #
1487
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1488
+Repairing offset=50200: Preallocated cluster is not properly aligned; L2 entry corrupted.
1489
+Leaked cluster 5 refcount=1 reference=0
1490
+Repairing cluster 5 refcount=1 reference=0
1491
+The following inconsistencies were found and repaired:
1492
+
1493
+ 1 leaked clusters
1494
+ 1 corruptions
1495
+
1496
+Double checking the fixed image now...
1497
+No errors were found on the image.
1498
+
1499
+### Image creation options ###
1500
+
1501
+# cluster_size < 16k
1502
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1503
+qemu-img: TEST_DIR/t.IMGFMT: Extended L2 entries are only supported with cluster sizes of at least 16384 bytes
1504
+# backing file and preallocation=metadata
1505
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=raw size=1048576
1506
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=524288 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw preallocation=metadata
1507
+Image resized.
1508
+read 524288/524288 bytes at offset 0
1509
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1510
+read 524288/524288 bytes at offset 524288
1511
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1512
+Offset Length Mapped to File
1513
+0 0x80000 0 TEST_DIR/t.qcow2.base
1514
+# backing file and preallocation=falloc
1515
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=524288 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw preallocation=falloc
1516
+Image resized.
1517
+read 524288/524288 bytes at offset 0
1518
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1519
+read 524288/524288 bytes at offset 524288
1520
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1521
+Offset Length Mapped to File
1522
+0 0x80000 0 TEST_DIR/t.qcow2.base
1523
+# backing file and preallocation=full
1524
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=524288 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw preallocation=full
1525
+Image resized.
1526
+read 524288/524288 bytes at offset 0
1527
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1528
+read 524288/524288 bytes at offset 524288
1529
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1530
+Offset Length Mapped to File
1531
+0 0x80000 0 TEST_DIR/t.qcow2.base
1532
+
1533
+### Image resizing with preallocation and backing files ###
1534
+
1535
+# resize --preallocation=metadata
1536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=515072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1537
+Image resized.
1538
+read 515072/515072 bytes at offset 0
1539
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1540
+read 522240/522240 bytes at offset 515072
1541
+510 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1542
+# resize --preallocation=falloc
1543
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=515072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1544
+Image resized.
1545
+read 515072/515072 bytes at offset 0
1546
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1547
+read 522240/522240 bytes at offset 515072
1548
+510 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1549
+# resize --preallocation=full
1550
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=515072 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
1551
+Image resized.
1552
+read 515072/515072 bytes at offset 0
1553
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1554
+read 522240/522240 bytes at offset 515072
1555
+510 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1556
+
1557
+### Image resizing with preallocation without backing files ###
1558
+
1559
+# resize --preallocation=metadata
1560
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=515072
1561
+wrote 515072/515072 bytes at offset 0
1562
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1563
+Image resized.
1564
+read 515072/515072 bytes at offset 0
1565
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1566
+read 522240/522240 bytes at offset 515072
1567
+510 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1568
+# resize --preallocation=falloc
1569
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=515072
1570
+wrote 515072/515072 bytes at offset 0
1571
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1572
+Image resized.
1573
+read 515072/515072 bytes at offset 0
1574
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1575
+read 522240/522240 bytes at offset 515072
1576
+510 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1577
+# resize --preallocation=full
1578
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=515072
1579
+wrote 515072/515072 bytes at offset 0
1580
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1581
+Image resized.
1582
+read 515072/515072 bytes at offset 0
1583
+503 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1584
+read 522240/522240 bytes at offset 515072
1585
+510 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1586
+
1587
+### qemu-img measure ###
1588
+
1589
+# 512MB, extended_l2=off
1590
+required size: 327680
1591
+fully allocated size: 537198592
1592
+# 512MB, extended_l2=on
1593
+required size: 393216
1594
+fully allocated size: 537264128
1595
+# 16K clusters, 64GB, extended_l2=off
1596
+required size: 42008576
1597
+fully allocated size: 68761485312
1598
+# 16K clusters, 64GB, extended_l2=on
1599
+required size: 75579392
1600
+fully allocated size: 68795056128
1601
+# 8k clusters
1602
+qemu-img: Extended L2 entries are only supported with cluster sizes of at least 16384 bytes
1603
+# 1024 TB
1604
+required size: 309285027840
1605
+fully allocated size: 1126209191870464
1606
+# 1025 TB
1607
+qemu-img: The image size is too large (try using a larger cluster size)
1608
+
1609
+### qemu-img amend ###
1610
+
1611
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1612
+qemu-img: Invalid parameter 'extended_l2'
1613
+This option is only supported for image creation
1614
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1615
+qemu-img: Invalid parameter 'extended_l2'
1616
+This option is only supported for image creation
1617
+
1618
+### Test copy-on-write on an image with snapshots ###
1619
+
1620
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1621
+L2 entry #0: 0x8000000000050000 0000008000042000
1622
+L2 entry #1: 0x8000000000060000 0000008000042000
1623
+L2 entry #2: 0x8000000000070000 0000008000042000
1624
+L2 entry #3: 0x8000000000080000 0000008000042000
1625
+L2 entry #4: 0x8000000000090000 0000008000042000
1626
+L2 entry #5: 0x80000000000a0000 0000008000042000
1627
+L2 entry #6: 0x80000000000b0000 0000008000042000
1628
+L2 entry #7: 0x80000000000c0000 0000008000042000
1629
+L2 entry #8: 0x80000000000d0000 0000008000042000
1630
+L2 entry #9: 0x80000000000e0000 0000008000042000
1631
+L2 entry #0: 0x8000000000120000 000000800007e000
1632
+L2 entry #1: 0x8000000000130000 000000800007fc00
1633
+L2 entry #2: 0x8000000000140000 00000080001fe000
1634
+L2 entry #3: 0x8000000000150000 000000800007e000
1635
+L2 entry #4: 0x8000000000160000 000000000007ff80
1636
+L2 entry #5: 0x8000000000170000 000000000007ffff
1637
+L2 entry #6: 0x00000000000b0000 0001808000042000
1638
+L2 entry #7: 0x00000000000c0000 0000208000040000
1639
+L2 entry #8: 0x8000000000180000 000000800007e000
1640
+L2 entry #9: 0x00000000000e0000 000000c000042000
1641
+
1642
+### Test concurrent requests ###
1643
+
1644
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1645
+blkdebug: Suspended request 'A'
1646
+blkdebug: Resuming request 'A'
1647
+wrote 2048/2048 bytes at offset 30720
1648
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1649
+wrote 2048/2048 bytes at offset 20480
1650
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1651
+wrote 2048/2048 bytes at offset 40960
1652
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1653
+*** done
1654
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
17
index XXXXXXX..XXXXXXX 100644
1655
index XXXXXXX..XXXXXXX 100644
18
--- a/block/block-backend.c
1656
--- a/tests/qemu-iotests/group
19
+++ b/block/block-backend.c
1657
+++ b/tests/qemu-iotests/group
20
@@ -XXX,XX +XXX,XX @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
1658
@@ -XXX,XX +XXX,XX @@
21
int64_t bytes, CoroutineEntry co_entry,
1659
267 rw auto quick snapshot
22
BdrvRequestFlags flags)
1660
268 rw auto quick
23
{
1661
270 rw backing quick
24
- QEMUIOVector qiov;
1662
+271 rw auto
25
- struct iovec iov;
1663
272 rw
26
- BlkRwCo rwco;
1664
273 backing quick
27
-
1665
274 rw backing
28
- iov = (struct iovec) {
29
- .iov_base = buf,
30
- .iov_len = bytes,
31
- };
32
- qemu_iovec_init_external(&qiov, &iov, 1);
33
-
34
- rwco = (BlkRwCo) {
35
+ QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
36
+ BlkRwCo rwco = {
37
.blk = blk,
38
.offset = offset,
39
.iobuf = &qiov,
40
--
1666
--
41
2.20.1
1667
2.26.2
42
1668
43
1669
diff view generated by jsdifflib