1
The following changes since commit c25e8bba1f546ea72744ccfab77f8a9e8a323be8:
1
The following changes since commit 30aa19446d82358a30eac3b556b4d6641e00b7c1:
2
2
3
Merge remote-tracking branch 'remotes/otubo/tags/pull-seccomp-20180601' into staging (2018-06-01 13:11:30 +0100)
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 21891a5a3011608845b5d7f1f9cce60cdc2bcc62:
9
for you to fetch changes up to c576fd97d4ca77b5a1a27728df11a61083dbfa98:
10
10
11
main-loop: drop spin_counter (2018-06-01 16:01:29 +0100)
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
15
- qcow2 subclusters (extended L2 entries)
16
* Copy offloading for qemu-img convert (iSCSI, raw, and qcow2)
17
18
If the underlying storage supports copy offloading, qemu-img convert will
19
use it instead of performing reads and writes. This avoids data transfers
20
and thus frees up storage bandwidth for other purposes. SCSI EXTENDED COPY
21
and Linux copy_file_range(2) are used to implement this optimization.
22
23
* Drop spurious "WARNING: I\/O thread spun for 1000 iterations" warning
24
16
25
----------------------------------------------------------------
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
26
54
27
Fam Zheng (10):
55
docs/interop/qcow2.txt | 68 ++-
28
block: Introduce API for copy offloading
56
docs/qcow2-cache.txt | 19 +-
29
raw: Check byte range uniformly
57
qapi/block-core.json | 7 +
30
raw: Implement copy offloading
58
block/qcow2.h | 211 ++++++-
31
qcow2: Implement copy offloading
59
include/block/block_int.h | 1 +
32
file-posix: Implement bdrv_co_copy_range
60
block/qcow2-cluster.c | 906 +++++++++++++++++++++----------
33
iscsi: Query and save device designator when opening
61
block/qcow2-refcount.c | 47 +-
34
iscsi: Create and use iscsi_co_wait_for_task
62
block/qcow2.c | 302 +++++++----
35
iscsi: Implement copy offloading
63
block/trace-events | 2 +-
36
block-backend: Add blk_co_copy_range
64
tests/qemu-iotests/031.out | 8 +-
37
qemu-img: Convert with copy offloading
65
tests/qemu-iotests/036.out | 4 +-
38
66
tests/qemu-iotests/049.out | 102 ++--
39
Stefan Hajnoczi (1):
67
tests/qemu-iotests/060.out | 3 +-
40
main-loop: drop spin_counter
68
tests/qemu-iotests/061 | 6 +
41
69
tests/qemu-iotests/061.out | 25 +-
42
configure | 17 ++
70
tests/qemu-iotests/065 | 12 +-
43
include/block/block.h | 32 ++++
71
tests/qemu-iotests/082.out | 39 +-
44
include/block/block_int.h | 38 ++++
72
tests/qemu-iotests/085.out | 38 +-
45
include/block/raw-aio.h | 10 +-
73
tests/qemu-iotests/144.out | 4 +-
46
include/scsi/constants.h | 4 +
74
tests/qemu-iotests/182.out | 2 +-
47
include/sysemu/block-backend.h | 4 +
75
tests/qemu-iotests/185.out | 8 +-
48
block/block-backend.c | 18 ++
76
tests/qemu-iotests/198 | 2 +
49
block/file-posix.c | 98 +++++++++-
77
tests/qemu-iotests/206.out | 6 +-
50
block/io.c | 97 ++++++++++
78
tests/qemu-iotests/242.out | 5 +
51
block/iscsi.c | 314 +++++++++++++++++++++++++++----
79
tests/qemu-iotests/255.out | 8 +-
52
block/qcow2.c | 229 +++++++++++++++++++---
80
tests/qemu-iotests/271 | 901 ++++++++++++++++++++++++++++++
53
block/raw-format.c | 96 +++++++---
81
tests/qemu-iotests/271.out | 726 +++++++++++++++++++++++++
54
qemu-img.c | 50 ++++-
82
tests/qemu-iotests/274.out | 49 +-
55
util/main-loop.c | 25 ---
83
tests/qemu-iotests/280.out | 2 +-
56
tests/qemu-iotests/common.filter | 1 -
84
tests/qemu-iotests/291.out | 2 +
57
15 files changed, 908 insertions(+), 125 deletions(-)
85
tests/qemu-iotests/302.out | 1 +
86
tests/qemu-iotests/303.out | 4 +-
87
tests/qemu-iotests/common.filter | 1 +
88
tests/qemu-iotests/group | 1 +
89
34 files changed, 2952 insertions(+), 570 deletions(-)
90
create mode 100755 tests/qemu-iotests/271
91
create mode 100644 tests/qemu-iotests/271.out
58
92
59
--
93
--
60
2.17.1
94
2.26.2
61
95
62
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
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
handle_alloc() creates a QCowL2Meta structure in order to update the
4
image metadata and perform the necessary copy-on-write operations.
5
6
This patch moves that code to a separate function so it can be used
7
from other places.
8
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-Id: <e5bc4a648dac31972bfa7a0e554be8064be78799.1594396418.git.berto@igalia.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/qcow2-cluster.c | 77 +++++++++++++++++++++++++++++--------------
15
1 file changed, 53 insertions(+), 24 deletions(-)
16
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-cluster.c
20
+++ b/block/qcow2-cluster.c
21
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
22
}
23
}
24
25
+/*
26
+ * For a given write request, create a new QCowL2Meta structure, add
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;
50
+
51
+ *m = g_malloc0(sizeof(**m));
52
+ **m = (QCowL2Meta) {
53
+ .next = old_m,
54
+
55
+ .alloc_offset = host_cluster_offset,
56
+ .offset = start_of_cluster(s, guest_offset),
57
+ .nb_clusters = nb_clusters,
58
+
59
+ .keep_old_clusters = keep_old,
60
+
61
+ .cow_start = {
62
+ .offset = cow_start_from,
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
+ };
70
+
71
+ qemu_co_queue_init(&(*m)->dependent_requests);
72
+ QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
73
+}
74
+
75
/*
76
* Returns the number of contiguous clusters that can be used for an allocating
77
* write, but require COW to be performed (this includes yet unallocated space,
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);
113
+
114
return 1;
115
116
fail:
117
--
118
2.26.2
119
120
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
This loop is repeated a growing number times. Make a helper.
3
We are going to need it in other places.
4
4
5
Signed-off-by: Fam Zheng <famz@redhat.com>
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20180601092648.24614-8-famz@redhat.com
8
Message-Id: <65e5d9627ca2ebe7e62deaeddf60949c33067d9d.1594396418.git.berto@igalia.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
10
---
11
block/iscsi.c | 54 ++++++++++++++++-----------------------------------
11
block/qcow2-cluster.c | 34 +++++++++++++++++++---------------
12
1 file changed, 17 insertions(+), 37 deletions(-)
12
1 file changed, 19 insertions(+), 15 deletions(-)
13
13
14
diff --git a/block/iscsi.c b/block/iscsi.c
14
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/iscsi.c
16
--- a/block/qcow2-cluster.c
17
+++ b/block/iscsi.c
17
+++ b/block/qcow2-cluster.c
18
@@ -XXX,XX +XXX,XX @@ static inline bool iscsi_allocmap_is_valid(IscsiLun *iscsilun,
18
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
19
offset / iscsilun->cluster_size) == size);
19
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
20
}
20
}
21
21
22
+static void coroutine_fn iscsi_co_wait_for_task(IscsiTask *iTask,
22
+/* Returns true if writing to a cluster requires COW */
23
+ IscsiLun *iscsilun)
23
+static bool cluster_needs_cow(BlockDriverState *bs, uint64_t l2_entry)
24
+{
24
+{
25
+ while (!iTask->complete) {
25
+ switch (qcow2_get_cluster_type(bs, l2_entry)) {
26
+ iscsi_set_events(iscsilun);
26
+ case QCOW2_CLUSTER_NORMAL:
27
+ qemu_mutex_unlock(&iscsilun->mutex);
27
+ if (l2_entry & QCOW_OFLAG_COPIED) {
28
+ qemu_coroutine_yield();
28
+ return false;
29
+ qemu_mutex_lock(&iscsilun->mutex);
29
+ }
30
+ case QCOW2_CLUSTER_UNALLOCATED:
31
+ case QCOW2_CLUSTER_COMPRESSED:
32
+ case QCOW2_CLUSTER_ZERO_PLAIN:
33
+ case QCOW2_CLUSTER_ZERO_ALLOC:
34
+ return true;
35
+ default:
36
+ abort();
30
+ }
37
+ }
31
+}
38
+}
32
+
39
+
33
static int coroutine_fn
40
/*
34
iscsi_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
41
* Returns the number of contiguous clusters that can be used for an allocating
35
QEMUIOVector *iov, int flags)
42
* write, but require COW to be performed (this includes yet unallocated space,
36
@@ -XXX,XX +XXX,XX @@ retry:
43
@@ -XXX,XX +XXX,XX @@ static int count_cow_clusters(BlockDriverState *bs, int nb_clusters,
37
scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
44
38
iov->niov);
45
for (i = 0; i < nb_clusters; i++) {
39
#endif
46
uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
40
- while (!iTask.complete) {
47
- QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry);
41
- iscsi_set_events(iscsilun);
48
-
42
- qemu_mutex_unlock(&iscsilun->mutex);
49
- switch(cluster_type) {
43
- qemu_coroutine_yield();
50
- case QCOW2_CLUSTER_NORMAL:
44
- qemu_mutex_lock(&iscsilun->mutex);
51
- if (l2_entry & QCOW_OFLAG_COPIED) {
45
- }
52
- goto out;
46
+ iscsi_co_wait_for_task(&iTask, iscsilun);
53
- }
47
54
+ if (!cluster_needs_cow(bs, l2_entry)) {
48
if (iTask.task != NULL) {
55
break;
49
scsi_free_scsi_task(iTask.task);
56
- case QCOW2_CLUSTER_UNALLOCATED:
50
@@ -XXX,XX +XXX,XX @@ retry:
57
- case QCOW2_CLUSTER_COMPRESSED:
51
ret = -ENOMEM;
58
- case QCOW2_CLUSTER_ZERO_PLAIN:
52
goto out_unlock;
59
- case QCOW2_CLUSTER_ZERO_ALLOC:
60
- break;
61
- default:
62
- abort();
63
}
53
}
64
}
54
-
65
55
- while (!iTask.complete) {
66
-out:
56
- iscsi_set_events(iscsilun);
67
assert(i <= nb_clusters);
57
- qemu_mutex_unlock(&iscsilun->mutex);
68
return i;
58
- qemu_coroutine_yield();
69
}
59
- qemu_mutex_lock(&iscsilun->mutex);
60
- }
61
+ iscsi_co_wait_for_task(&iTask, iscsilun);
62
63
if (iTask.do_retry) {
64
if (iTask.task != NULL) {
65
@@ -XXX,XX +XXX,XX @@ retry:
66
#if LIBISCSI_API_VERSION < (20160603)
67
scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
68
#endif
69
- while (!iTask.complete) {
70
- iscsi_set_events(iscsilun);
71
- qemu_mutex_unlock(&iscsilun->mutex);
72
- qemu_coroutine_yield();
73
- qemu_mutex_lock(&iscsilun->mutex);
74
- }
75
76
+ iscsi_co_wait_for_task(&iTask, iscsilun);
77
if (iTask.task != NULL) {
78
scsi_free_scsi_task(iTask.task);
79
iTask.task = NULL;
80
@@ -XXX,XX +XXX,XX @@ retry:
81
return -ENOMEM;
82
}
83
84
- while (!iTask.complete) {
85
- iscsi_set_events(iscsilun);
86
- qemu_mutex_unlock(&iscsilun->mutex);
87
- qemu_coroutine_yield();
88
- qemu_mutex_lock(&iscsilun->mutex);
89
- }
90
+ iscsi_co_wait_for_task(&iTask, iscsilun);
91
92
if (iTask.task != NULL) {
93
scsi_free_scsi_task(iTask.task);
94
@@ -XXX,XX +XXX,XX @@ retry:
95
goto out_unlock;
96
}
97
98
- while (!iTask.complete) {
99
- iscsi_set_events(iscsilun);
100
- qemu_mutex_unlock(&iscsilun->mutex);
101
- qemu_coroutine_yield();
102
- qemu_mutex_lock(&iscsilun->mutex);
103
- }
104
+ iscsi_co_wait_for_task(&iTask, iscsilun);
105
106
if (iTask.task != NULL) {
107
scsi_free_scsi_task(iTask.task);
108
@@ -XXX,XX +XXX,XX @@ retry:
109
return -ENOMEM;
110
}
111
112
- while (!iTask.complete) {
113
- iscsi_set_events(iscsilun);
114
- qemu_mutex_unlock(&iscsilun->mutex);
115
- qemu_coroutine_yield();
116
- qemu_mutex_lock(&iscsilun->mutex);
117
- }
118
+ iscsi_co_wait_for_task(&iTask, iscsilun);
119
120
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
121
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
122
--
70
--
123
2.17.1
71
2.26.2
124
72
125
73
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
When writing to a qcow2 file there are two functions that take a
4
virtual offset and return a host offset, possibly allocating new
5
clusters if necessary:
6
7
- handle_copied() looks for normal data clusters that are already
8
allocated and have a reference count of 1. In those clusters we
9
can simply write the data and there is no need to perform any
10
copy-on-write.
11
12
- handle_alloc() looks for clusters that do need copy-on-write,
13
either because they haven't been allocated yet, because their
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>
43
---
44
block/qcow2-cluster.c | 252 +++++++++++++++++++++++-------------------
45
1 file changed, 139 insertions(+), 113 deletions(-)
46
47
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/qcow2-cluster.c
50
+++ b/block/qcow2-cluster.c
51
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
52
53
/*
54
* For a given write request, create a new QCowL2Meta structure, add
55
- * it to @m and the BDRVQcow2State.cluster_allocs list.
56
+ * it to @m and the BDRVQcow2State.cluster_allocs list. If the write
57
+ * request does not need copy-on-write or changes to the L2 metadata
58
+ * then this function does nothing.
59
*
60
* @host_cluster_offset points to the beginning of the first cluster.
61
*
62
* @guest_offset and @bytes indicate the offset and length of the
63
* request.
64
*
65
+ * @l2_slice contains the L2 entries of all clusters involved in this
66
+ * write request.
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
+ }
104
+ }
105
+
106
+ /* Get the L2 entry of the first cluster */
107
+ l2_entry = be64_to_cpu(l2_slice[l2_index]);
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;
467
--
468
2.26.2
469
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
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
Subcluster allocation in qcow2 is implemented by extending the
4
existing L2 table entries and adding additional information to
5
indicate the allocation status of each subcluster.
6
7
This patch documents the changes to the qcow2 format and how they
8
affect the calculation of the L2 cache size.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Message-Id: <5199f2e1c717bcaa58b48142c9062b803145ff7f.1594396418.git.berto@igalia.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
docs/interop/qcow2.txt | 68 ++++++++++++++++++++++++++++++++++++++++--
17
docs/qcow2-cache.txt | 19 +++++++++++-
18
2 files changed, 83 insertions(+), 4 deletions(-)
19
20
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
21
index XXXXXXX..XXXXXXX 100644
22
--- a/docs/interop/qcow2.txt
23
+++ b/docs/interop/qcow2.txt
24
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
25
as the maximum cluster size and won't be able to open images
26
with larger cluster sizes.
27
28
+ Note: if the image has Extended L2 Entries then cluster_bits
29
+ must be at least 14 (i.e. 16384 byte clusters).
30
+
31
24 - 31: size
32
Virtual disk size in bytes.
33
34
@@ -XXX,XX +XXX,XX @@ the next fields through header_length.
35
clusters. The compression_type field must be
36
present and not zero.
37
38
- Bits 4-63: Reserved (set to 0)
39
+ Bit 4: Extended L2 Entries. If this bit is set then
40
+ L2 table entries use an extended format that
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
135
index XXXXXXX..XXXXXXX 100644
136
--- a/docs/qcow2-cache.txt
137
+++ b/docs/qcow2-cache.txt
138
@@ -XXX,XX +XXX,XX @@
139
qcow2 L2/refcount cache configuration
140
=====================================
141
-Copyright (C) 2015, 2018 Igalia, S.L.
142
+Copyright (C) 2015, 2018-2020 Igalia, S.L.
143
Author: Alberto Garcia <berto@igalia.com>
144
145
This work is licensed under the terms of the GNU GPL, version 2 or
146
@@ -XXX,XX +XXX,XX @@ support this functionality, and is 0 (disabled) on other platforms.
147
This functionality currently relies on the MADV_DONTNEED argument for
148
madvise() to actually free the memory. This is a Linux-specific feature,
149
so cache-clean-interval is not supported on other systems.
150
+
151
+
152
+Extended L2 Entries
153
+-------------------
154
+All numbers shown in this document are valid for qcow2 images with normal
155
+64-bit L2 entries.
156
+
157
+Images with extended L2 entries need twice as much L2 metadata, so the L2
158
+cache size must be twice as large for the same disk space.
159
+
160
+ disk_size = l2_cache_size * cluster_size / 16
161
+
162
+i.e.
163
+
164
+ l2_cache_size = disk_size * 16 / cluster_size
165
+
166
+Refcount blocks are not affected by this.
167
--
168
2.26.2
169
170
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This function will be used by the qcow2 code to check if an image has
4
subclusters or not.
5
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>
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: <905526221083581a1b7057bca1585487661c5c13.1594396418.git.berto@igalia.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
block/qcow2.h | 6 ++++++
19
1 file changed, 6 insertions(+)
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 @@ typedef enum QCow2MetadataOverlap {
26
27
#define INV_OFFSET (-1ULL)
28
29
+static inline bool has_subclusters(BDRVQcow2State *s)
30
+{
31
+ /* FIXME: Return false until this feature is complete */
32
+ return false;
33
+}
34
+
35
static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
36
int idx)
37
{
38
--
39
2.26.2
40
41
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This patch adds the following new fields to BDRVQcow2State:
4
5
- subclusters_per_cluster: Number of subclusters in a cluster
6
- subcluster_size: The size of each subcluster, in bytes
7
- subcluster_bits: No. of bits so 1 << subcluster_bits = subcluster_size
8
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>
17
---
18
block/qcow2.h | 5 +++++
19
block/qcow2.c | 5 +++++
20
2 files changed, 10 insertions(+)
21
22
diff --git a/block/qcow2.h b/block/qcow2.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.h
25
+++ b/block/qcow2.h
26
@@ -XXX,XX +XXX,XX @@
27
/* 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
}
51
}
52
53
+ s->subclusters_per_cluster =
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);
57
+
58
/* Check support for various header values */
59
if (header.refcount_order > 6) {
60
error_setg(errp, "Reference count entry width too large; may not "
61
--
62
2.26.2
63
64
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
For a given offset, return the subcluster number within its cluster
4
(i.e. with 32 subclusters per cluster it returns a number between 0
5
and 31).
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-Id: <56e3e4ac0d827c6a2f5f259106c5ddb7c4ca2653.1594396418.git.berto@igalia.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2.h | 5 +++++
14
1 file changed, 5 insertions(+)
15
16
diff --git a/block/qcow2.h b/block/qcow2.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/qcow2.h
19
+++ b/block/qcow2.h
20
@@ -XXX,XX +XXX,XX @@ static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
21
return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
22
}
23
24
+static inline int offset_to_sc_index(BDRVQcow2State *s, int64_t offset)
25
+{
26
+ return (offset >> s->subcluster_bits) & (s->subclusters_per_cluster - 1);
27
+}
28
+
29
static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
30
{
31
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
32
--
33
2.26.2
34
35
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Issue EXTENDED COPY (LID1) command to implement the copy_range API.
3
Like offset_into_cluster() and size_to_clusters(), but for
4
subclusters.
4
5
5
The parameter data construction code is modified from libiscsi's
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
iscsi-dd.c.
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <3cc2390dcdef3d234d47c741b708bd8734490862.1594396418.git.berto@igalia.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2.h | 10 ++++++++++
13
1 file changed, 10 insertions(+)
7
14
8
Signed-off-by: Fam Zheng <famz@redhat.com>
15
diff --git a/block/qcow2.h b/block/qcow2.h
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-id: 20180601092648.24614-9-famz@redhat.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
include/scsi/constants.h | 4 +
14
block/iscsi.c | 219 +++++++++++++++++++++++++++++++++++++++
15
2 files changed, 223 insertions(+)
16
17
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
18
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
19
--- a/include/scsi/constants.h
17
--- a/block/qcow2.h
20
+++ b/include/scsi/constants.h
18
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ static inline int64_t offset_into_cluster(BDRVQcow2State *s, int64_t offset)
22
#define MMC_PROFILE_HDDVD_RW_DL 0x005A
20
return offset & (s->cluster_size - 1);
23
#define MMC_PROFILE_INVALID 0xFFFF
24
25
+#define XCOPY_DESC_OFFSET 16
26
+#define IDENT_DESCR_TGT_DESCR_SIZE 32
27
+#define XCOPY_BLK2BLK_SEG_DESC_SIZE 28
28
+
29
#endif
30
diff --git a/block/iscsi.c b/block/iscsi.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/iscsi.c
33
+++ b/block/iscsi.c
34
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
35
iscsi_allocmap_invalidate(iscsilun);
36
}
21
}
37
22
38
+static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs,
23
+static inline int64_t offset_into_subcluster(BDRVQcow2State *s, int64_t offset)
39
+ BdrvChild *src,
40
+ uint64_t src_offset,
41
+ BdrvChild *dst,
42
+ uint64_t dst_offset,
43
+ uint64_t bytes,
44
+ BdrvRequestFlags flags)
45
+{
24
+{
46
+ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags);
25
+ return offset & (s->subcluster_size - 1);
47
+}
26
+}
48
+
27
+
49
+static struct scsi_task *iscsi_xcopy_task(int param_len)
28
static inline uint64_t size_to_clusters(BDRVQcow2State *s, uint64_t size)
29
{
30
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
31
}
32
33
+static inline uint64_t size_to_subclusters(BDRVQcow2State *s, uint64_t size)
50
+{
34
+{
51
+ struct scsi_task *task;
35
+ return (size + (s->subcluster_size - 1)) >> s->subcluster_bits;
52
+
53
+ task = g_new0(struct scsi_task, 1);
54
+
55
+ task->cdb[0] = EXTENDED_COPY;
56
+ task->cdb[10] = (param_len >> 24) & 0xFF;
57
+ task->cdb[11] = (param_len >> 16) & 0xFF;
58
+ task->cdb[12] = (param_len >> 8) & 0xFF;
59
+ task->cdb[13] = param_len & 0xFF;
60
+ task->cdb_size = 16;
61
+ task->xfer_dir = SCSI_XFER_WRITE;
62
+ task->expxferlen = param_len;
63
+
64
+ return task;
65
+}
36
+}
66
+
37
+
67
+static void iscsi_populate_target_desc(unsigned char *desc, IscsiLun *lun)
38
static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
68
+{
39
{
69
+ struct scsi_inquiry_device_designator *dd = lun->dd;
40
int shift = s->cluster_bits + s->l2_bits;
70
+
71
+ memset(desc, 0, 32);
72
+ desc[0] = 0xE4; /* IDENT_DESCR_TGT_DESCR */
73
+ desc[4] = dd->code_set;
74
+ desc[5] = (dd->designator_type & 0xF)
75
+ | ((dd->association & 3) << 4);
76
+ desc[7] = dd->designator_length;
77
+ memcpy(desc + 8, dd->designator, dd->designator_length);
78
+
79
+ desc[28] = 0;
80
+ desc[29] = (lun->block_size >> 16) & 0xFF;
81
+ desc[30] = (lun->block_size >> 8) & 0xFF;
82
+ desc[31] = lun->block_size & 0xFF;
83
+}
84
+
85
+static void iscsi_xcopy_desc_hdr(uint8_t *hdr, int dc, int cat, int src_index,
86
+ int dst_index)
87
+{
88
+ hdr[0] = 0x02; /* BLK_TO_BLK_SEG_DESCR */
89
+ hdr[1] = ((dc << 1) | cat) & 0xFF;
90
+ hdr[2] = (XCOPY_BLK2BLK_SEG_DESC_SIZE >> 8) & 0xFF;
91
+ /* don't account for the first 4 bytes in descriptor header*/
92
+ hdr[3] = (XCOPY_BLK2BLK_SEG_DESC_SIZE - 4 /* SEG_DESC_SRC_INDEX_OFFSET */) & 0xFF;
93
+ hdr[4] = (src_index >> 8) & 0xFF;
94
+ hdr[5] = src_index & 0xFF;
95
+ hdr[6] = (dst_index >> 8) & 0xFF;
96
+ hdr[7] = dst_index & 0xFF;
97
+}
98
+
99
+static void iscsi_xcopy_populate_desc(uint8_t *desc, int dc, int cat,
100
+ int src_index, int dst_index, int num_blks,
101
+ uint64_t src_lba, uint64_t dst_lba)
102
+{
103
+ iscsi_xcopy_desc_hdr(desc, dc, cat, src_index, dst_index);
104
+
105
+ /* The caller should verify the request size */
106
+ assert(num_blks < 65536);
107
+ desc[10] = (num_blks >> 8) & 0xFF;
108
+ desc[11] = num_blks & 0xFF;
109
+ desc[12] = (src_lba >> 56) & 0xFF;
110
+ desc[13] = (src_lba >> 48) & 0xFF;
111
+ desc[14] = (src_lba >> 40) & 0xFF;
112
+ desc[15] = (src_lba >> 32) & 0xFF;
113
+ desc[16] = (src_lba >> 24) & 0xFF;
114
+ desc[17] = (src_lba >> 16) & 0xFF;
115
+ desc[18] = (src_lba >> 8) & 0xFF;
116
+ desc[19] = src_lba & 0xFF;
117
+ desc[20] = (dst_lba >> 56) & 0xFF;
118
+ desc[21] = (dst_lba >> 48) & 0xFF;
119
+ desc[22] = (dst_lba >> 40) & 0xFF;
120
+ desc[23] = (dst_lba >> 32) & 0xFF;
121
+ desc[24] = (dst_lba >> 24) & 0xFF;
122
+ desc[25] = (dst_lba >> 16) & 0xFF;
123
+ desc[26] = (dst_lba >> 8) & 0xFF;
124
+ desc[27] = dst_lba & 0xFF;
125
+}
126
+
127
+static void iscsi_xcopy_populate_header(unsigned char *buf, int list_id, int str,
128
+ int list_id_usage, int prio,
129
+ int tgt_desc_len,
130
+ int seg_desc_len, int inline_data_len)
131
+{
132
+ buf[0] = list_id;
133
+ buf[1] = ((str & 1) << 5) | ((list_id_usage & 3) << 3) | (prio & 7);
134
+ buf[2] = (tgt_desc_len >> 8) & 0xFF;
135
+ buf[3] = tgt_desc_len & 0xFF;
136
+ buf[8] = (seg_desc_len >> 24) & 0xFF;
137
+ buf[9] = (seg_desc_len >> 16) & 0xFF;
138
+ buf[10] = (seg_desc_len >> 8) & 0xFF;
139
+ buf[11] = seg_desc_len & 0xFF;
140
+ buf[12] = (inline_data_len >> 24) & 0xFF;
141
+ buf[13] = (inline_data_len >> 16) & 0xFF;
142
+ buf[14] = (inline_data_len >> 8) & 0xFF;
143
+ buf[15] = inline_data_len & 0xFF;
144
+}
145
+
146
+static void iscsi_xcopy_data(struct iscsi_data *data,
147
+ IscsiLun *src, int64_t src_lba,
148
+ IscsiLun *dst, int64_t dst_lba,
149
+ uint16_t num_blocks)
150
+{
151
+ uint8_t *buf;
152
+ const int src_offset = XCOPY_DESC_OFFSET;
153
+ const int dst_offset = XCOPY_DESC_OFFSET + IDENT_DESCR_TGT_DESCR_SIZE;
154
+ const int seg_offset = dst_offset + IDENT_DESCR_TGT_DESCR_SIZE;
155
+
156
+ data->size = XCOPY_DESC_OFFSET +
157
+ IDENT_DESCR_TGT_DESCR_SIZE * 2 +
158
+ XCOPY_BLK2BLK_SEG_DESC_SIZE;
159
+ data->data = g_malloc0(data->size);
160
+ buf = data->data;
161
+
162
+ /* Initialise the parameter list header */
163
+ iscsi_xcopy_populate_header(buf, 1, 0, 2 /* LIST_ID_USAGE_DISCARD */,
164
+ 0, 2 * IDENT_DESCR_TGT_DESCR_SIZE,
165
+ XCOPY_BLK2BLK_SEG_DESC_SIZE,
166
+ 0);
167
+
168
+ /* Initialise CSCD list with one src + one dst descriptor */
169
+ iscsi_populate_target_desc(&buf[src_offset], src);
170
+ iscsi_populate_target_desc(&buf[dst_offset], dst);
171
+
172
+ /* Initialise one segment descriptor */
173
+ iscsi_xcopy_populate_desc(&buf[seg_offset], 0, 0, 0, 1, num_blocks,
174
+ src_lba, dst_lba);
175
+}
176
+
177
+static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs,
178
+ BdrvChild *src,
179
+ uint64_t src_offset,
180
+ BdrvChild *dst,
181
+ uint64_t dst_offset,
182
+ uint64_t bytes,
183
+ BdrvRequestFlags flags)
184
+{
185
+ IscsiLun *dst_lun = dst->bs->opaque;
186
+ IscsiLun *src_lun;
187
+ struct IscsiTask iscsi_task;
188
+ struct iscsi_data data;
189
+ int r = 0;
190
+ int block_size;
191
+
192
+ if (src->bs->drv->bdrv_co_copy_range_to != iscsi_co_copy_range_to) {
193
+ return -ENOTSUP;
194
+ }
195
+ src_lun = src->bs->opaque;
196
+
197
+ if (!src_lun->dd || !dst_lun->dd) {
198
+ return -ENOTSUP;
199
+ }
200
+ if (!is_byte_request_lun_aligned(dst_offset, bytes, dst_lun)) {
201
+ return -ENOTSUP;
202
+ }
203
+ if (!is_byte_request_lun_aligned(src_offset, bytes, src_lun)) {
204
+ return -ENOTSUP;
205
+ }
206
+ if (dst_lun->block_size != src_lun->block_size ||
207
+ !dst_lun->block_size) {
208
+ return -ENOTSUP;
209
+ }
210
+
211
+ block_size = dst_lun->block_size;
212
+ if (bytes / block_size > 65535) {
213
+ return -ENOTSUP;
214
+ }
215
+
216
+ iscsi_xcopy_data(&data,
217
+ src_lun, src_offset / block_size,
218
+ dst_lun, dst_offset / block_size,
219
+ bytes / block_size);
220
+
221
+ iscsi_co_init_iscsitask(dst_lun, &iscsi_task);
222
+
223
+ qemu_mutex_lock(&dst_lun->mutex);
224
+ iscsi_task.task = iscsi_xcopy_task(data.size);
225
+retry:
226
+ if (iscsi_scsi_command_async(dst_lun->iscsi, dst_lun->lun,
227
+ iscsi_task.task, iscsi_co_generic_cb,
228
+ &data,
229
+ &iscsi_task) != 0) {
230
+ r = -EIO;
231
+ goto out_unlock;
232
+ }
233
+
234
+ iscsi_co_wait_for_task(&iscsi_task, dst_lun);
235
+
236
+ if (iscsi_task.do_retry) {
237
+ iscsi_task.complete = 0;
238
+ goto retry;
239
+ }
240
+
241
+ if (iscsi_task.status != SCSI_STATUS_GOOD) {
242
+ r = iscsi_task.err_code;
243
+ goto out_unlock;
244
+ }
245
+
246
+out_unlock:
247
+ g_free(iscsi_task.task);
248
+ qemu_mutex_unlock(&dst_lun->mutex);
249
+ g_free(iscsi_task.err_str);
250
+ return r;
251
+}
252
+
253
static QemuOptsList iscsi_create_opts = {
254
.name = "iscsi-create-opts",
255
.head = QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head),
256
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
257
258
.bdrv_co_block_status = iscsi_co_block_status,
259
.bdrv_co_pdiscard = iscsi_co_pdiscard,
260
+ .bdrv_co_copy_range_from = iscsi_co_copy_range_from,
261
+ .bdrv_co_copy_range_to = iscsi_co_copy_range_to,
262
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
263
.bdrv_co_readv = iscsi_co_readv,
264
.bdrv_co_writev = iscsi_co_writev,
265
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = {
266
267
.bdrv_co_block_status = iscsi_co_block_status,
268
.bdrv_co_pdiscard = iscsi_co_pdiscard,
269
+ .bdrv_co_copy_range_from = iscsi_co_copy_range_from,
270
+ .bdrv_co_copy_range_to = iscsi_co_copy_range_to,
271
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
272
.bdrv_co_readv = iscsi_co_readv,
273
.bdrv_co_writev = iscsi_co_writev,
274
--
41
--
275
2.17.1
42
2.26.2
276
43
277
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: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
With copy_file_range(2), we can implement the bdrv_co_copy_range
3
Extended L2 entries are 128-bit wide: 64 bits for the entry itself and
4
semantics.
4
64 bits for the subcluster allocation bitmap.
5
5
6
Signed-off-by: Fam Zheng <famz@redhat.com>
6
In order to support them correctly get/set_l2_entry() need to be
7
Message-id: 20180601092648.24614-6-famz@redhat.com
7
updated so they take the entry width into account in order to
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Message-Id: <6ee0f81ae3329c991de125618b3675e1e46acdbb.1594396418.git.berto@igalia.com>
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
20
---
10
configure | 17 +++++++
21
block/qcow2.h | 21 +++++++++++++++++++++
11
include/block/raw-aio.h | 10 ++++-
22
1 file changed, 21 insertions(+)
12
block/file-posix.c | 98 +++++++++++++++++++++++++++++++++++++++--
13
3 files changed, 120 insertions(+), 5 deletions(-)
14
23
15
diff --git a/configure b/configure
24
diff --git a/block/qcow2.h b/block/qcow2.h
16
index XXXXXXX..XXXXXXX 100755
17
--- a/configure
18
+++ b/configure
19
@@ -XXX,XX +XXX,XX @@ if test "$fortify_source" != "no"; then
20
fi
21
fi
22
23
+###############################################
24
+# Check if copy_file_range is provided by glibc
25
+have_copy_file_range=no
26
+cat > $TMPC << EOF
27
+#include <unistd.h>
28
+int main(void) {
29
+ copy_file_range(0, NULL, 0, NULL, 0, 0);
30
+ return 0;
31
+}
32
+EOF
33
+if compile_prog "" "" ; then
34
+ have_copy_file_range=yes
35
+fi
36
+
37
##########################################
38
# check if struct fsxattr is available via linux/fs.h
39
40
@@ -XXX,XX +XXX,XX @@ fi
41
if test "$have_fsxattr" = "yes" ; then
42
echo "HAVE_FSXATTR=y" >> $config_host_mak
43
fi
44
+if test "$have_copy_file_range" = "yes" ; then
45
+ echo "HAVE_COPY_FILE_RANGE=y" >> $config_host_mak
46
+fi
47
if test "$vte" = "yes" ; then
48
echo "CONFIG_VTE=y" >> $config_host_mak
49
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
50
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
51
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
52
--- a/include/block/raw-aio.h
26
--- a/block/qcow2.h
53
+++ b/include/block/raw-aio.h
27
+++ b/block/qcow2.h
54
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@ static inline size_t l2_entry_size(BDRVQcow2State *s)
55
#define QEMU_AIO_FLUSH 0x0008
29
static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
56
#define QEMU_AIO_DISCARD 0x0010
30
int idx)
57
#define QEMU_AIO_WRITE_ZEROES 0x0020
31
{
58
+#define QEMU_AIO_COPY_RANGE 0x0040
32
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
59
#define QEMU_AIO_TYPE_MASK \
33
return be64_to_cpu(l2_slice[idx]);
60
- (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \
61
- QEMU_AIO_DISCARD|QEMU_AIO_WRITE_ZEROES)
62
+ (QEMU_AIO_READ | \
63
+ QEMU_AIO_WRITE | \
64
+ QEMU_AIO_IOCTL | \
65
+ QEMU_AIO_FLUSH | \
66
+ QEMU_AIO_DISCARD | \
67
+ QEMU_AIO_WRITE_ZEROES | \
68
+ QEMU_AIO_COPY_RANGE)
69
70
/* AIO flags */
71
#define QEMU_AIO_MISALIGNED 0x1000
72
diff --git a/block/file-posix.c b/block/file-posix.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/block/file-posix.c
75
+++ b/block/file-posix.c
76
@@ -XXX,XX +XXX,XX @@
77
#ifdef __linux__
78
#include <sys/ioctl.h>
79
#include <sys/param.h>
80
+#include <sys/syscall.h>
81
#include <linux/cdrom.h>
82
#include <linux/fd.h>
83
#include <linux/fs.h>
84
@@ -XXX,XX +XXX,XX @@ typedef struct RawPosixAIOData {
85
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
86
off_t aio_offset;
87
int aio_type;
88
+ int aio_fd2;
89
+ off_t aio_offset2;
90
} RawPosixAIOData;
91
92
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
93
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
94
return -ENOTSUP;
95
}
34
}
96
35
97
+#ifndef HAVE_COPY_FILE_RANGE
36
+static inline uint64_t get_l2_bitmap(BDRVQcow2State *s, uint64_t *l2_slice,
98
+static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
37
+ int idx)
99
+ off_t *out_off, size_t len, unsigned int flags)
100
+{
38
+{
101
+#ifdef __NR_copy_file_range
39
+ if (has_subclusters(s)) {
102
+ return syscall(__NR_copy_file_range, in_fd, in_off, out_fd,
40
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
103
+ out_off, len, flags);
41
+ return be64_to_cpu(l2_slice[idx + 1]);
104
+#else
42
+ } else {
105
+ errno = ENOSYS;
43
+ return 0; /* For convenience only; this value has no meaning. */
106
+ return -1;
107
+#endif
108
+}
109
+#endif
110
+
111
+static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb)
112
+{
113
+ uint64_t bytes = aiocb->aio_nbytes;
114
+ off_t in_off = aiocb->aio_offset;
115
+ off_t out_off = aiocb->aio_offset2;
116
+
117
+ while (bytes) {
118
+ ssize_t ret = copy_file_range(aiocb->aio_fildes, &in_off,
119
+ aiocb->aio_fd2, &out_off,
120
+ bytes, 0);
121
+ if (ret == -EINTR) {
122
+ continue;
123
+ }
124
+ if (ret < 0) {
125
+ if (errno == ENOSYS) {
126
+ return -ENOTSUP;
127
+ } else {
128
+ return -errno;
129
+ }
130
+ }
131
+ if (!ret) {
132
+ /* No progress (e.g. when beyond EOF), fall back to buffer I/O. */
133
+ return -ENOTSUP;
134
+ }
135
+ bytes -= ret;
136
+ }
44
+ }
137
+ return 0;
138
+}
45
+}
139
+
46
+
140
static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
47
static inline void set_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
48
int idx, uint64_t entry)
141
{
49
{
142
int ret = -EOPNOTSUPP;
50
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
143
@@ -XXX,XX +XXX,XX @@ static int aio_worker(void *arg)
51
l2_slice[idx] = cpu_to_be64(entry);
144
case QEMU_AIO_WRITE_ZEROES:
145
ret = handle_aiocb_write_zeroes(aiocb);
146
break;
147
+ case QEMU_AIO_COPY_RANGE:
148
+ ret = handle_aiocb_copy_range(aiocb);
149
+ break;
150
default:
151
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
152
ret = -EINVAL;
153
@@ -XXX,XX +XXX,XX @@ static int aio_worker(void *arg)
154
return ret;
155
}
52
}
156
53
157
-static int paio_submit_co(BlockDriverState *bs, int fd,
54
+static inline void set_l2_bitmap(BDRVQcow2State *s, uint64_t *l2_slice,
158
- int64_t offset, QEMUIOVector *qiov,
55
+ int idx, uint64_t bitmap)
159
- int bytes, int type)
160
+static int paio_submit_co_full(BlockDriverState *bs, int fd,
161
+ int64_t offset, int fd2, int64_t offset2,
162
+ QEMUIOVector *qiov,
163
+ int bytes, int type)
164
{
165
RawPosixAIOData *acb = g_new(RawPosixAIOData, 1);
166
ThreadPool *pool;
167
@@ -XXX,XX +XXX,XX @@ static int paio_submit_co(BlockDriverState *bs, int fd,
168
acb->bs = bs;
169
acb->aio_type = type;
170
acb->aio_fildes = fd;
171
+ acb->aio_fd2 = fd2;
172
+ acb->aio_offset2 = offset2;
173
174
acb->aio_nbytes = bytes;
175
acb->aio_offset = offset;
176
@@ -XXX,XX +XXX,XX @@ static int paio_submit_co(BlockDriverState *bs, int fd,
177
return thread_pool_submit_co(pool, aio_worker, acb);
178
}
179
180
+static inline int paio_submit_co(BlockDriverState *bs, int fd,
181
+ int64_t offset, QEMUIOVector *qiov,
182
+ int bytes, int type)
183
+{
56
+{
184
+ return paio_submit_co_full(bs, fd, offset, -1, 0, qiov, bytes, type);
57
+ assert(has_subclusters(s));
58
+ idx *= l2_entry_size(s) / sizeof(uint64_t);
59
+ l2_slice[idx + 1] = cpu_to_be64(bitmap);
185
+}
60
+}
186
+
61
+
187
static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd,
62
static inline bool has_data_file(BlockDriverState *bs)
188
int64_t offset, QEMUIOVector *qiov, int bytes,
63
{
189
BlockCompletionFunc *cb, void *opaque, int type)
64
BDRVQcow2State *s = bs->opaque;
190
@@ -XXX,XX +XXX,XX @@ static void raw_abort_perm_update(BlockDriverState *bs)
191
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
192
}
193
194
+static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
195
+ BdrvChild *src, uint64_t src_offset,
196
+ BdrvChild *dst, uint64_t dst_offset,
197
+ uint64_t bytes, BdrvRequestFlags flags)
198
+{
199
+ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags);
200
+}
201
+
202
+static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
203
+ BdrvChild *src, uint64_t src_offset,
204
+ BdrvChild *dst, uint64_t dst_offset,
205
+ uint64_t bytes, BdrvRequestFlags flags)
206
+{
207
+ BDRVRawState *s = bs->opaque;
208
+ BDRVRawState *src_s;
209
+
210
+ assert(dst->bs == bs);
211
+ if (src->bs->drv->bdrv_co_copy_range_to != raw_co_copy_range_to) {
212
+ return -ENOTSUP;
213
+ }
214
+
215
+ src_s = src->bs->opaque;
216
+ if (fd_open(bs) < 0 || fd_open(bs) < 0) {
217
+ return -EIO;
218
+ }
219
+ return paio_submit_co_full(bs, src_s->fd, src_offset, s->fd, dst_offset,
220
+ NULL, bytes, QEMU_AIO_COPY_RANGE);
221
+}
222
+
223
BlockDriver bdrv_file = {
224
.format_name = "file",
225
.protocol_name = "file",
226
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
227
.bdrv_co_pwritev = raw_co_pwritev,
228
.bdrv_aio_flush = raw_aio_flush,
229
.bdrv_aio_pdiscard = raw_aio_pdiscard,
230
+ .bdrv_co_copy_range_from = raw_co_copy_range_from,
231
+ .bdrv_co_copy_range_to = raw_co_copy_range_to,
232
.bdrv_refresh_limits = raw_refresh_limits,
233
.bdrv_io_plug = raw_aio_plug,
234
.bdrv_io_unplug = raw_aio_unplug,
235
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = {
236
.bdrv_co_pwritev = raw_co_pwritev,
237
.bdrv_aio_flush    = raw_aio_flush,
238
.bdrv_aio_pdiscard = hdev_aio_pdiscard,
239
+ .bdrv_co_copy_range_from = raw_co_copy_range_from,
240
+ .bdrv_co_copy_range_to = raw_co_copy_range_to,
241
.bdrv_refresh_limits = raw_refresh_limits,
242
.bdrv_io_plug = raw_aio_plug,
243
.bdrv_io_unplug = raw_aio_unplug,
244
--
65
--
245
2.17.1
66
2.26.2
246
67
247
68
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
This patch adds QCow2SubclusterType, which is the subcluster-level
4
version of QCow2ClusterType. All QCOW2_SUBCLUSTER_* values have the
5
the same meaning as their QCOW2_CLUSTER_* equivalents (when they
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>
44
Reviewed-by: Eric Blake <eblake@redhat.com>
45
Reviewed-by: Max Reitz <mreitz@redhat.com>
46
Message-Id: <26ef38e270f25851c98b51278852b4c4a7f97e69.1594396418.git.berto@igalia.com>
47
Signed-off-by: Max Reitz <mreitz@redhat.com>
48
---
49
block/qcow2.h | 126 +++++++++++++++++++++++++++++++++++++++++++++++++-
50
1 file changed, 125 insertions(+), 1 deletion(-)
51
52
diff --git a/block/qcow2.h b/block/qcow2.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/block/qcow2.h
55
+++ b/block/qcow2.h
56
@@ -XXX,XX +XXX,XX @@
57
58
#define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32
59
60
+/* The subcluster X [0..31] is allocated */
61
+#define QCOW_OFLAG_SUB_ALLOC(X) (1ULL << (X))
62
+/* The subcluster X [0..31] reads as zeroes */
63
+#define QCOW_OFLAG_SUB_ZERO(X) (QCOW_OFLAG_SUB_ALLOC(X) << 32)
64
+/* Subclusters [X, Y) (0 <= X <= Y <= 32) are allocated */
65
+#define QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) \
66
+ (QCOW_OFLAG_SUB_ALLOC(Y) - QCOW_OFLAG_SUB_ALLOC(X))
67
+/* Subclusters [X, Y) (0 <= X <= Y <= 32) read as zeroes */
68
+#define QCOW_OFLAG_SUB_ZERO_RANGE(X, Y) \
69
+ (QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) << 32)
70
+/* L2 entry bitmap with all allocation bits set */
71
+#define QCOW_L2_BITMAP_ALL_ALLOC (QCOW_OFLAG_SUB_ALLOC_RANGE(0, 32))
72
+/* L2 entry bitmap with all "read as zeroes" bits set */
73
+#define QCOW_L2_BITMAP_ALL_ZEROES (QCOW_OFLAG_SUB_ZERO_RANGE(0, 32))
74
+
75
/* Size of normal and extended L2 entries */
76
#define L2E_SIZE_NORMAL (sizeof(uint64_t))
77
#define L2E_SIZE_EXTENDED (sizeof(uint64_t) * 2)
78
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
79
QLIST_ENTRY(QCowL2Meta) next_in_flight;
80
} QCowL2Meta;
81
82
+/*
83
+ * In images with standard L2 entries all clusters are treated as if
84
+ * they had one subcluster so QCow2ClusterType and QCow2SubclusterType
85
+ * can be mapped to each other and have the exact same meaning
86
+ * (QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC cannot happen in these images).
87
+ *
88
+ * In images with extended L2 entries QCow2ClusterType refers to the
89
+ * complete cluster and QCow2SubclusterType to each of the individual
90
+ * subclusters, so there are several possible combinations:
91
+ *
92
+ * |--------------+---------------------------|
93
+ * | Cluster type | Possible subcluster types |
94
+ * |--------------+---------------------------|
95
+ * | UNALLOCATED | UNALLOCATED_PLAIN |
96
+ * | | ZERO_PLAIN |
97
+ * |--------------+---------------------------|
98
+ * | NORMAL | UNALLOCATED_ALLOC |
99
+ * | | ZERO_ALLOC |
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
+ }
167
+}
168
+
169
+/*
170
+ * In an image without subsclusters @l2_bitmap is ignored and
171
+ * @sc_index must be 0.
172
+ * Return QCOW2_SUBCLUSTER_INVALID if an invalid l2 entry is detected
173
+ * (this checks the whole entry and bitmap, not only the bits related
174
+ * to subcluster @sc_index).
175
+ */
176
+static inline
177
+QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
178
+ uint64_t l2_entry,
179
+ uint64_t l2_bitmap,
180
+ unsigned sc_index)
181
+{
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
+ }
214
+}
215
+
216
/* Check whether refcounts are eager or lazy */
217
static inline bool qcow2_need_accurate_refcounts(BDRVQcow2State *s)
218
{
219
--
220
2.26.2
221
222
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
The device designator data returned in INQUIRY command will be useful to
3
There are situations in which we want to know how many contiguous
4
fill in source/target fields during copy offloading. Do this when
4
subclusters of the same type there are in a given cluster. This can be
5
connecting to the target and save the data for later use.
5
done by simply iterating over the subclusters and repeatedly calling
6
qcow2_get_subcluster_type() for each one of them.
6
7
7
Signed-off-by: Fam Zheng <famz@redhat.com>
8
However once we determined the type of a subcluster we can check the
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
rest efficiently by counting the number of adjacent ones (or zeroes)
9
Message-id: 20180601092648.24614-7-famz@redhat.com
10
in the bitmap. This is what this function does.
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
12
Signed-off-by: Alberto Garcia <berto@igalia.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>
11
---
17
---
12
block/iscsi.c | 41 +++++++++++++++++++++++++++++++++++++++++
18
block/qcow2-cluster.c | 51 +++++++++++++++++++++++++++++++++++++++++++
13
1 file changed, 41 insertions(+)
19
1 file changed, 51 insertions(+)
14
20
15
diff --git a/block/iscsi.c b/block/iscsi.c
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
16
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
17
--- a/block/iscsi.c
23
--- a/block/qcow2-cluster.c
18
+++ b/block/iscsi.c
24
+++ b/block/qcow2-cluster.c
19
@@ -XXX,XX +XXX,XX @@ typedef struct IscsiLun {
25
@@ -XXX,XX +XXX,XX @@ fail:
20
QemuMutex mutex;
26
return ret;
21
struct scsi_inquiry_logical_block_provisioning lbp;
27
}
22
struct scsi_inquiry_block_limits bl;
28
23
+ struct scsi_inquiry_device_designator *dd;
29
+/*
24
unsigned char *zeroblock;
30
+ * For a given L2 entry, count the number of contiguous subclusters of
25
/* The allocmap tracks which clusters (pages) on the iSCSI target are
31
+ * the same type starting from @sc_from. Compressed clusters are
26
* allocated and which are not. In case a target returns zeros for
32
+ * treated as if they were divided into subclusters of size
27
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
33
+ * s->subcluster_size.
28
},
34
+ *
29
};
35
+ * Return the number of contiguous subclusters and set @type to the
30
36
+ * subcluster type.
31
+static void iscsi_save_designator(IscsiLun *lun,
37
+ *
32
+ struct scsi_inquiry_device_identification *inq_di)
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)
33
+{
47
+{
34
+ struct scsi_inquiry_device_designator *desig, *copy = NULL;
48
+ BDRVQcow2State *s = bs->opaque;
49
+ uint32_t val;
35
+
50
+
36
+ for (desig = inq_di->designators; desig; desig = desig->next) {
51
+ *type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_from);
37
+ if (desig->association ||
52
+
38
+ desig->designator_type > SCSI_DESIGNATOR_TYPE_NAA) {
53
+ if (*type == QCOW2_SUBCLUSTER_INVALID) {
39
+ continue;
54
+ return -EINVAL;
40
+ }
55
+ } else if (!has_subclusters(s) || *type == QCOW2_SUBCLUSTER_COMPRESSED) {
41
+ /* NAA works better than T10 vendor ID based designator. */
56
+ return s->subclusters_per_cluster - sc_from;
42
+ if (!copy || copy->designator_type < desig->designator_type) {
43
+ copy = desig;
44
+ }
45
+ }
57
+ }
46
+ if (copy) {
58
+
47
+ lun->dd = g_new(struct scsi_inquiry_device_designator, 1);
59
+ switch (*type) {
48
+ *lun->dd = *copy;
60
+ case QCOW2_SUBCLUSTER_NORMAL:
49
+ lun->dd->next = NULL;
61
+ val = l2_bitmap | QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
50
+ lun->dd->designator = g_malloc(copy->designator_length);
62
+ return cto32(val) - sc_from;
51
+ memcpy(lun->dd->designator, copy->designator, copy->designator_length);
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();
52
+ }
77
+ }
53
+}
78
+}
54
+
79
+
55
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
80
/*
56
Error **errp)
81
* Checks how many clusters in a given L2 slice are contiguous in the image
57
{
82
* file. As soon as one of the flags in the bitmask stop_flags changes compared
58
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
59
struct scsi_task *inq_task;
60
struct scsi_inquiry_logical_block_provisioning *inq_lbp;
61
struct scsi_inquiry_block_limits *inq_bl;
62
+ struct scsi_inquiry_device_identification *inq_di;
63
switch (inq_vpd->pages[i]) {
64
case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
65
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
66
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
67
sizeof(struct scsi_inquiry_block_limits));
68
scsi_free_scsi_task(inq_task);
69
break;
70
+ case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION:
71
+ inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
72
+ SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION,
73
+ (void **) &inq_di, errp);
74
+ if (inq_task == NULL) {
75
+ ret = -EINVAL;
76
+ goto out;
77
+ }
78
+ iscsi_save_designator(iscsilun, inq_di);
79
+ scsi_free_scsi_task(inq_task);
80
+ break;
81
default:
82
break;
83
}
84
@@ -XXX,XX +XXX,XX @@ static void iscsi_close(BlockDriverState *bs)
85
iscsi_logout_sync(iscsi);
86
}
87
iscsi_destroy_context(iscsi);
88
+ if (iscsilun->dd) {
89
+ g_free(iscsilun->dd->designator);
90
+ g_free(iscsilun->dd);
91
+ }
92
g_free(iscsilun->zeroblock);
93
iscsi_allocmap_free(iscsilun);
94
qemu_mutex_destroy(&iscsilun->mutex);
95
--
83
--
96
2.17.1
84
2.26.2
97
85
98
86
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Just pass down to ->file.
3
This helper function tells us if a cluster is allocated (that is,
4
there is an associated host offset for it).
4
5
5
Signed-off-by: Fam Zheng <famz@redhat.com>
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-id: 20180601092648.24614-4-famz@redhat.com
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-Id: <6d8771c5c79cbdc6c519875a5078e1cc85856d63.1594396418.git.berto@igalia.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
11
---
10
block/raw-format.c | 32 ++++++++++++++++++++++++++++++++
12
block/qcow2.h | 6 ++++++
11
1 file changed, 32 insertions(+)
13
1 file changed, 6 insertions(+)
12
14
13
diff --git a/block/raw-format.c b/block/raw-format.c
15
diff --git a/block/qcow2.h b/block/qcow2.h
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/block/raw-format.c
17
--- a/block/qcow2.h
16
+++ b/block/raw-format.c
18
+++ b/block/qcow2.h
17
@@ -XXX,XX +XXX,XX @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
19
@@ -XXX,XX +XXX,XX @@ QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
18
return bdrv_probe_geometry(bs->file->bs, geo);
20
}
19
}
21
}
20
22
21
+static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
23
+static inline bool qcow2_cluster_is_allocated(QCow2ClusterType type)
22
+ BdrvChild *src, uint64_t src_offset,
23
+ BdrvChild *dst, uint64_t dst_offset,
24
+ uint64_t bytes, BdrvRequestFlags flags)
25
+{
24
+{
26
+ int ret;
25
+ return (type == QCOW2_CLUSTER_COMPRESSED || type == QCOW2_CLUSTER_NORMAL ||
27
+
26
+ type == QCOW2_CLUSTER_ZERO_ALLOC);
28
+ ret = raw_adjust_offset(bs, &src_offset, bytes, false);
29
+ if (ret) {
30
+ return ret;
31
+ }
32
+ return bdrv_co_copy_range_from(bs->file, src_offset, dst, dst_offset,
33
+ bytes, flags);
34
+}
27
+}
35
+
28
+
36
+static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
29
/* Check whether refcounts are eager or lazy */
37
+ BdrvChild *src, uint64_t src_offset,
30
static inline bool qcow2_need_accurate_refcounts(BDRVQcow2State *s)
38
+ BdrvChild *dst, uint64_t dst_offset,
31
{
39
+ uint64_t bytes, BdrvRequestFlags flags)
40
+{
41
+ int ret;
42
+
43
+ ret = raw_adjust_offset(bs, &dst_offset, bytes, true);
44
+ if (ret) {
45
+ return ret;
46
+ }
47
+ return bdrv_co_copy_range_to(src, src_offset, bs->file, dst_offset, bytes,
48
+ flags);
49
+}
50
+
51
BlockDriver bdrv_raw = {
52
.format_name = "raw",
53
.instance_size = sizeof(BDRVRawState),
54
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
55
.bdrv_co_pwrite_zeroes = &raw_co_pwrite_zeroes,
56
.bdrv_co_pdiscard = &raw_co_pdiscard,
57
.bdrv_co_block_status = &raw_co_block_status,
58
+ .bdrv_co_copy_range_from = &raw_co_copy_range_from,
59
+ .bdrv_co_copy_range_to = &raw_co_copy_range_to,
60
.bdrv_truncate = &raw_truncate,
61
.bdrv_getlength = &raw_getlength,
62
.has_variable_length = true,
63
--
32
--
64
2.17.1
33
2.26.2
65
34
66
35
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
The new blk_co_copy_range interface offers a more efficient way in the
3
This function returns an integer that can be either an error code or a
4
case of network based storage. Make use of it to allow faster convert
4
cluster type (a value from the QCow2ClusterType enum).
5
operation.
6
5
7
Since copy offloading cannot do zero detection ('-S') and compression
6
We are going to start using subcluster types instead of cluster types
8
(-c), only try it when these options are not used.
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.
9
9
10
Signed-off-by: Fam Zheng <famz@redhat.com>
10
This patch makes qcow2_get_host_offset() return 0 on success and
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
puts the returned cluster type in a separate parameter. There are no
12
Message-id: 20180601092648.24614-11-famz@redhat.com
12
semantic changes.
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
14
Signed-off-by: Alberto Garcia <berto@igalia.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
qemu-img.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
20
block/qcow2.h | 3 ++-
16
1 file changed, 48 insertions(+), 2 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/qemu-img.c b/qemu-img.c
25
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
20
--- a/qemu-img.c
27
--- a/block/qcow2.h
21
+++ b/qemu-img.c
28
+++ b/block/qcow2.h
22
@@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState {
29
@@ -XXX,XX +XXX,XX @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
23
bool compressed;
30
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
24
bool target_has_backing;
31
25
bool wr_in_order;
32
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
26
+ bool copy_range;
33
- unsigned int *bytes, uint64_t *host_offset);
27
int min_sparse;
34
+ unsigned int *bytes, uint64_t *host_offset,
28
size_t cluster_sectors;
35
+ QCow2ClusterType *cluster_type);
29
size_t buf_sectors;
36
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
30
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
37
unsigned int *bytes, uint64_t *host_offset,
31
return 0;
38
QCowL2Meta **m);
32
}
39
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
33
40
index XXXXXXX..XXXXXXX 100644
34
+static int coroutine_fn convert_co_copy_range(ImgConvertState *s, int64_t sector_num,
41
--- a/block/qcow2-cluster.c
35
+ int nb_sectors)
42
+++ b/block/qcow2-cluster.c
36
+{
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
37
+ int n, ret;
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)
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
- return type;
66
+ *cluster_type = type;
38
+
67
+
39
+ while (nb_sectors > 0) {
40
+ BlockBackend *blk;
41
+ int src_cur;
42
+ int64_t bs_sectors, src_cur_offset;
43
+ int64_t offset;
44
+
45
+ convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
46
+ offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
47
+ blk = s->src[src_cur];
48
+ bs_sectors = s->src_sectors[src_cur];
49
+
50
+ n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
51
+
52
+ ret = blk_co_copy_range(blk, offset, s->target,
53
+ sector_num << BDRV_SECTOR_BITS,
54
+ n << BDRV_SECTOR_BITS, 0);
55
+ if (ret < 0) {
56
+ return ret;
57
+ }
58
+
59
+ sector_num += n;
60
+ nb_sectors -= n;
61
+ }
62
+ return 0;
68
+ return 0;
63
+}
69
64
+
70
fail:
65
static void coroutine_fn convert_co_do_copy(void *opaque)
71
qcow2_cache_put(s->l2_table_cache, (void **)&l2_slice);
66
{
72
diff --git a/block/qcow2.c b/block/qcow2.c
67
ImgConvertState *s = opaque;
73
index XXXXXXX..XXXXXXX 100644
68
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn convert_co_do_copy(void *opaque)
74
--- a/block/qcow2.c
69
int n;
75
+++ b/block/qcow2.c
70
int64_t sector_num;
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
71
enum ImgConvertBlockStatus status;
77
BDRVQcow2State *s = bs->opaque;
72
+ bool copy_range;
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,
85
}
86
87
bytes = MIN(INT_MAX, count);
88
- ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset);
89
+ ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset, &type);
90
qemu_co_mutex_unlock(&s->lock);
91
if (ret < 0) {
92
return ret;
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
94
95
*pnum = bytes;
96
97
- if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
98
+ if ((type == QCOW2_CLUSTER_NORMAL || type == QCOW2_CLUSTER_ZERO_ALLOC) &&
99
!s->crypto) {
100
*map = host_offset;
101
*file = s->data_file->bs;
102
status |= BDRV_BLOCK_OFFSET_VALID;
103
}
104
- if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) {
105
+ if (type == QCOW2_CLUSTER_ZERO_PLAIN || type == QCOW2_CLUSTER_ZERO_ALLOC) {
106
status |= BDRV_BLOCK_ZERO;
107
- } else if (ret != QCOW2_CLUSTER_UNALLOCATED) {
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
}
73
122
74
qemu_co_mutex_lock(&s->lock);
123
qemu_co_mutex_lock(&s->lock);
75
if (s->ret != -EINPROGRESS || s->sector_num >= s->total_sectors) {
124
- ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset);
76
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn convert_co_do_copy(void *opaque)
125
+ ret = qcow2_get_host_offset(bs, offset, &cur_bytes,
77
s->allocated_sectors, 0);
126
+ &host_offset, &type);
127
qemu_co_mutex_unlock(&s->lock);
128
if (ret < 0) {
129
goto out;
78
}
130
}
79
131
80
- if (status == BLK_DATA) {
132
- if (ret == QCOW2_CLUSTER_ZERO_PLAIN ||
81
+retry:
133
- ret == QCOW2_CLUSTER_ZERO_ALLOC ||
82
+ copy_range = s->copy_range && s->status == BLK_DATA;
134
- (ret == QCOW2_CLUSTER_UNALLOCATED && !bs->backing))
83
+ if (status == BLK_DATA && !copy_range) {
135
+ if (type == QCOW2_CLUSTER_ZERO_PLAIN ||
84
ret = convert_co_read(s, sector_num, n, buf);
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);
85
if (ret < 0) {
148
if (ret < 0) {
86
error_report("error while reading sector %" PRId64
149
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
87
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn convert_co_do_copy(void *opaque)
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;
88
}
172
}
89
173
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
90
if (s->ret == -EINPROGRESS) {
174
91
- ret = convert_co_write(s, sector_num, n, buf, status);
175
while (bytes != 0) {
92
+ if (copy_range) {
176
uint64_t copy_offset = 0;
93
+ ret = convert_co_copy_range(s, sector_num, n);
177
+ QCow2ClusterType type;
94
+ if (ret) {
178
/* prepare next request */
95
+ s->copy_range = false;
179
cur_bytes = MIN(bytes, INT_MAX);
96
+ goto retry;
180
cur_write_flags = write_flags;
97
+ }
181
98
+ } else {
182
- ret = qcow2_get_host_offset(bs, src_offset, &cur_bytes, &copy_offset);
99
+ ret = convert_co_write(s, sector_num, n, buf, status);
183
+ ret = qcow2_get_host_offset(bs, src_offset, &cur_bytes,
100
+ }
184
+ &copy_offset, &type);
101
if (ret < 0) {
185
if (ret < 0) {
102
error_report("error while writing sector %" PRId64
186
goto out;
103
": %s", sector_num, strerror(-ret));
104
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
105
ImgConvertState s = (ImgConvertState) {
106
/* Need at least 4k of zeros for sparse detection */
107
.min_sparse = 8,
108
+ .copy_range = true,
109
.buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
110
.wr_in_order = true,
111
.num_coroutines = 8,
112
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
113
break;
114
case 'c':
115
s.compressed = true;
116
+ s.copy_range = false;
117
break;
118
case 'o':
119
if (!is_valid_option_list(optarg)) {
120
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
121
}
122
123
s.min_sparse = sval / BDRV_SECTOR_SIZE;
124
+ s.copy_range = false;
125
break;
126
}
187
}
127
case 'p':
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);
128
--
194
--
129
2.17.1
195
2.26.2
130
196
131
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
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
When dealing with subcluster types there is a new value called
4
QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC that has no equivalent in
5
QCow2ClusterType.
6
7
This patch handles that value in all places where subcluster types
8
are processed.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Max Reitz <mreitz@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>
15
---
16
block/qcow2.c | 12 +++++++++---
17
1 file changed, 9 insertions(+), 3 deletions(-)
18
19
diff --git a/block/qcow2.c b/block/qcow2.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
22
+++ b/block/qcow2.c
23
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
24
*pnum = bytes;
25
26
if ((type == QCOW2_SUBCLUSTER_NORMAL ||
27
- type == QCOW2_SUBCLUSTER_ZERO_ALLOC) && !s->crypto) {
28
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
29
+ type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC) && !s->crypto) {
30
*map = host_offset;
31
*file = s->data_file->bs;
32
status |= BDRV_BLOCK_OFFSET_VALID;
33
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
34
if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
35
type == QCOW2_SUBCLUSTER_ZERO_ALLOC) {
36
status |= BDRV_BLOCK_ZERO;
37
- } else if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN) {
38
+ } else if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
39
+ type != QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC) {
40
status |= BDRV_BLOCK_DATA;
41
}
42
if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
43
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
44
g_assert_not_reached();
45
46
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
47
+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
48
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
49
50
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
51
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
52
53
if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
54
type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
55
- (type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing))
56
+ (type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing) ||
57
+ (type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC && !bs->backing))
58
{
59
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
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) {
77
--
78
2.26.2
79
80
diff view generated by jsdifflib
New patch
1
1
From: Alberto Garcia <berto@igalia.com>
2
3
If an image has subclusters then there are more copy-on-write
4
scenarios that we need to consider. Let's say we have a write request
5
from the middle of subcluster #3 until the end of the cluster:
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>
32
Reviewed-by: Eric Blake <eblake@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
34
Message-Id: <4292dd56e4446d386a2fe307311737a711c00708.1594396418.git.berto@igalia.com>
35
Signed-off-by: Max Reitz <mreitz@redhat.com>
36
---
37
block/qcow2-cluster.c | 167 +++++++++++++++++++++++++++++++++---------
38
1 file changed, 133 insertions(+), 34 deletions(-)
39
40
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/block/qcow2-cluster.c
43
+++ b/block/qcow2-cluster.c
44
@@ -XXX,XX +XXX,XX @@ fail:
45
* If the L2 entry is invalid return -errno and set @type to
46
* QCOW2_SUBCLUSTER_INVALID.
47
*/
48
-G_GNUC_UNUSED
49
static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
50
uint64_t l2_entry,
51
uint64_t l2_bitmap,
52
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
53
* If @keep_old is true it means that the clusters were already
54
* allocated and will be overwritten. If false then the clusters are
55
* new and we have to decrease the reference count of the old ones.
56
+ *
57
+ * Returns 0 on success, -errno on failure.
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)
66
{
67
BDRVQcow2State *s = bs->opaque;
68
- int l2_index = offset_to_l2_slice_index(s, guest_offset);
69
- uint64_t l2_entry;
70
+ int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset);
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
}
121
}
122
123
+ if (skip_cow) {
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);
130
-
131
- if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
132
- cow_start_from = cow_start_to;
133
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
134
+ sc_index = offset_to_sc_index(s, guest_offset);
135
+ type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);
136
+
137
+ if (!keep_old) {
138
+ switch (type) {
139
+ case QCOW2_SUBCLUSTER_COMPRESSED:
140
+ cow_start_from = 0;
141
+ break;
142
+ case QCOW2_SUBCLUSTER_NORMAL:
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
+ }
174
}
175
176
/* Get the L2 entry of the last cluster */
177
- l2_entry = get_l2_entry(s, l2_slice, l2_index + nb_clusters - 1);
178
- type = qcow2_get_cluster_type(bs, l2_entry);
179
-
180
- if (type == QCOW2_CLUSTER_NORMAL && keep_old) {
181
- cow_end_to = cow_end_from;
182
+ l2_index += nb_clusters - 1;
183
+ l2_entry = get_l2_entry(s, l2_slice, l2_index);
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
+ }
225
}
226
227
*m = g_malloc0(sizeof(**m));
228
@@ -XXX,XX +XXX,XX @@ static void calculate_l2_meta(BlockDriverState *bs,
229
230
qemu_co_queue_init(&(*m)->dependent_requests);
231
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
232
+
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
276
--
277
2.26.2
278
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
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
The QCOW_OFLAG_ZERO bit that indicates that a cluster reads as
4
zeroes is only used in standard L2 entries. Extended L2 entries use
5
individual 'all zeroes' bits for each subcluster.
6
7
This must be taken into account when updating the L2 entry and also
8
when deciding that an existing entry does not need to be updated.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.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>
15
---
16
block/qcow2-cluster.c | 38 ++++++++++++++++++++------------------
17
1 file changed, 20 insertions(+), 18 deletions(-)
18
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2-cluster.c
22
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
24
int l2_index;
25
int ret;
26
int i;
27
- bool unmap = !!(flags & BDRV_REQ_MAY_UNMAP);
28
29
ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
30
if (ret < 0) {
31
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
32
assert(nb_clusters <= INT_MAX);
33
34
for (i = 0; i < nb_clusters; i++) {
35
- uint64_t old_offset;
36
- QCow2ClusterType cluster_type;
37
-
38
- old_offset = get_l2_entry(s, l2_slice, l2_index + i);
39
+ uint64_t old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
40
+ uint64_t old_l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
41
+ QCow2ClusterType type = qcow2_get_cluster_type(bs, old_l2_entry);
42
+ bool unmap = (type == QCOW2_CLUSTER_COMPRESSED) ||
43
+ ((flags & BDRV_REQ_MAY_UNMAP) && qcow2_cluster_is_allocated(type));
44
+ uint64_t new_l2_entry = unmap ? 0 : old_l2_entry;
45
+ uint64_t new_l2_bitmap = old_l2_bitmap;
46
+
47
+ if (has_subclusters(s)) {
48
+ new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES;
49
+ } else {
50
+ new_l2_entry |= QCOW_OFLAG_ZERO;
51
+ }
52
53
- /*
54
- * Minimize L2 changes if the cluster already reads back as
55
- * zeroes with correct allocation.
56
- */
57
- cluster_type = qcow2_get_cluster_type(bs, old_offset);
58
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN ||
59
- (cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) {
60
+ if (old_l2_entry == new_l2_entry && old_l2_bitmap == new_l2_bitmap) {
61
continue;
62
}
63
64
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
65
- if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
66
- set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
67
- qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
68
- } else {
69
- uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
70
- set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO);
71
+ if (unmap) {
72
+ qcow2_free_any_clusters(bs, old_l2_entry, 1, QCOW2_DISCARD_REQUEST);
73
+ }
74
+ set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry);
75
+ if (has_subclusters(s)) {
76
+ set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
77
}
78
}
79
80
--
81
2.26.2
82
83
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
Two things need to be taken into account here:
4
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>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Reviewed-by: Max Reitz <mreitz@redhat.com>
23
Message-Id: <5ef8274e628aa3ab559bfac467abf488534f2b76.1594396418.git.berto@igalia.com>
24
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
---
26
block/qcow2-cluster.c | 52 +++++++++++++++++++------------------------
27
1 file changed, 23 insertions(+), 29 deletions(-)
28
29
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/block/qcow2-cluster.c
32
+++ b/block/qcow2-cluster.c
33
@@ -XXX,XX +XXX,XX @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
34
assert(nb_clusters <= INT_MAX);
35
36
for (i = 0; i < nb_clusters; i++) {
37
- uint64_t old_l2_entry;
38
-
39
- old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
40
+ uint64_t old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
41
+ uint64_t old_l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
42
+ uint64_t new_l2_entry = old_l2_entry;
43
+ uint64_t new_l2_bitmap = old_l2_bitmap;
44
+ QCow2ClusterType cluster_type =
45
+ qcow2_get_cluster_type(bs, old_l2_entry);
46
47
/*
48
+ * If full_discard is true, the cluster should not read back as zeroes,
49
+ * but rather fall through to the backing file.
50
+ *
51
* If full_discard is false, make sure that a discarded area reads back
52
* as zeroes for v3 images (we cannot do it for v2 without actually
53
* writing a zero-filled buffer). We can skip the operation if the
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;
80
}
81
- break;
82
-
83
- case QCOW2_CLUSTER_ZERO_ALLOC:
84
- case QCOW2_CLUSTER_NORMAL:
85
- case QCOW2_CLUSTER_COMPRESSED:
86
- break;
87
+ }
88
89
- default:
90
- abort();
91
+ if (old_l2_entry == new_l2_entry && old_l2_bitmap == new_l2_bitmap) {
92
+ continue;
93
}
94
95
/* First remove L2 entries */
96
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
97
- if (!full_discard && s->qcow_version >= 3) {
98
- set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
99
- } else {
100
- set_l2_entry(s, l2_slice, l2_index + i, 0);
101
+ set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry);
102
+ if (has_subclusters(s)) {
103
+ set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
104
}
105
-
106
/* Then decrease the refcount */
107
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
108
}
109
--
110
2.26.2
111
112
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
The offset field of an uncompressed cluster's L2 entry must be aligned
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.
8
9
On traditional qcow2 images this can only happen when QCOW_OFLAG_ZERO
10
is set, and repairing such entries turns the clusters from ZERO_ALLOC
11
into ZERO_PLAIN.
12
13
Extended L2 entries have no ZERO_ALLOC clusters and no QCOW_OFLAG_ZERO
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>
21
---
22
block/qcow2-refcount.c | 16 +++++++++++-----
23
tests/qemu-iotests/060.out | 2 +-
24
2 files changed, 12 insertions(+), 6 deletions(-)
25
26
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/qcow2-refcount.c
29
+++ b/block/qcow2-refcount.c
30
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
31
32
/* Correct offsets are cluster aligned */
33
if (offset_into_cluster(s, offset)) {
34
+ bool contains_data;
35
res->corruptions++;
36
37
- if (qcow2_get_cluster_type(bs, l2_entry) ==
38
- QCOW2_CLUSTER_ZERO_ALLOC)
39
- {
40
- fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
41
+ if (has_subclusters(s)) {
42
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i);
43
+ contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC);
44
+ } else {
45
+ contains_data = !(l2_entry & QCOW_OFLAG_ZERO);
46
+ }
47
+
48
+ if (!contains_data) {
49
+ fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated "
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
75
--
76
2.26.2
77
78
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
The L2 bitmap needs to be updated after each write to indicate what
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.
6
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>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Message-Id: <0875620d49f44320334b6a91c73b3f301f975f38.1594396418.git.berto@igalia.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
block/qcow2-cluster.c | 18 ++++++++++++++++++
19
1 file changed, 18 insertions(+)
20
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2-cluster.c
24
+++ b/block/qcow2-cluster.c
25
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
26
assert((offset & L2E_OFFSET_MASK) == offset);
27
28
set_l2_entry(s, l2_slice, l2_index + i, offset | QCOW_OFLAG_COPIED);
29
+
30
+ /* Update bitmap with the subclusters that were just written */
31
+ if (has_subclusters(s)) {
32
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
33
+ unsigned written_from = m->cow_start.offset;
34
+ unsigned written_to = m->cow_end.offset + m->cow_end.nb_bytes ?:
35
+ m->nb_clusters << s->cluster_bits;
36
+ int first_sc, last_sc;
37
+ /* Narrow written_from and written_to down to the current cluster */
38
+ written_from = MAX(written_from, i << s->cluster_bits);
39
+ written_to = MIN(written_to, (i + 1) << s->cluster_bits);
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
50
--
51
2.26.2
52
53
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
Compressed clusters always have the bitmap part of the extended L2
4
entry set to 0.
5
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <04455b3de5dfeb9d1cfe1fc7b02d7060a6e09710.1594396418.git.berto@igalia.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/qcow2-cluster.c | 3 +++
12
1 file changed, 3 insertions(+)
13
14
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qcow2-cluster.c
17
+++ b/block/qcow2-cluster.c
18
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
19
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
20
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
21
set_l2_entry(s, l2_slice, l2_index, cluster_offset);
22
+ if (has_subclusters(s)) {
23
+ set_l2_bitmap(s, l2_slice, l2_index, 0);
24
+ }
25
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
26
27
*host_offset = cluster_offset & s->cluster_offset_mask;
28
--
29
2.26.2
30
31
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
The two callbacks are implemented quite similarly to the read/write
3
The bdrv_co_pwrite_zeroes() call here fills complete clusters with
4
functions: bdrv_co_copy_range_from maps for read and calls into bs->file
4
zeroes, but it can happen that some subclusters are not part of the
5
or bs->backing depending on the allocation status; bdrv_co_copy_range_to
5
write request or the copy-on-write. This patch makes sure that only
6
maps for write and calls into bs->file.
6
the affected subclusters are overwritten.
7
7
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
A potential improvement would be to also fill with zeroes the other
9
Signed-off-by: Fam Zheng <famz@redhat.com>
9
subclusters if we can guarantee that we are not overwriting existing
10
Message-id: 20180601092648.24614-5-famz@redhat.com
10
data. However this would waste more disk space, so we should first
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
evaluate if it's really worth doing.
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: <b3dc97e8e2240ddb5191a4f930e8fc9653f94621.1594396418.git.berto@igalia.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
18
---
13
block/qcow2.c | 229 +++++++++++++++++++++++++++++++++++++++++++-------
19
block/qcow2.c | 9 +++++----
14
1 file changed, 199 insertions(+), 30 deletions(-)
20
1 file changed, 5 insertions(+), 4 deletions(-)
15
21
16
diff --git a/block/qcow2.c b/block/qcow2.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/qcow2.c
24
--- a/block/qcow2.c
19
+++ b/block/qcow2.c
25
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
26
@@ -XXX,XX +XXX,XX @@ static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
21
return status;
27
22
}
28
for (m = l2meta; m != NULL; m = m->next) {
23
29
int ret;
24
+static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
30
+ uint64_t start_offset = m->alloc_offset + m->cow_start.offset;
25
+ QCowL2Meta **pl2meta,
31
+ unsigned nb_bytes = m->cow_end.offset + m->cow_end.nb_bytes -
26
+ bool link_l2)
32
+ m->cow_start.offset;
27
+{
33
28
+ int ret = 0;
34
if (!m->cow_start.nb_bytes && !m->cow_end.nb_bytes) {
29
+ QCowL2Meta *l2meta = *pl2meta;
35
continue;
30
+
36
@@ -XXX,XX +XXX,XX @@ static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
31
+ while (l2meta != NULL) {
37
* efficiently zero out the whole clusters
32
+ QCowL2Meta *next;
38
*/
33
+
39
34
+ if (!ret && link_l2) {
40
- ret = qcow2_pre_write_overlap_check(bs, 0, m->alloc_offset,
35
+ ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
41
- m->nb_clusters * s->cluster_size,
36
+ if (ret) {
42
+ ret = qcow2_pre_write_overlap_check(bs, 0, start_offset, nb_bytes,
37
+ goto out;
43
true);
38
+ }
44
if (ret < 0) {
39
+ }
45
return ret;
40
+
41
+ /* Take the request off the list of running requests */
42
+ if (l2meta->nb_clusters != 0) {
43
+ QLIST_REMOVE(l2meta, next_in_flight);
44
+ }
45
+
46
+ qemu_co_queue_restart_all(&l2meta->dependent_requests);
47
+
48
+ next = l2meta->next;
49
+ g_free(l2meta);
50
+ l2meta = next;
51
+ }
52
+out:
53
+ *pl2meta = l2meta;
54
+ return ret;
55
+}
56
+
57
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
58
uint64_t bytes, QEMUIOVector *qiov,
59
int flags)
60
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
61
}
62
}
46
}
63
47
64
- while (l2meta != NULL) {
48
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
65
- QCowL2Meta *next;
49
- ret = bdrv_co_pwrite_zeroes(s->data_file, m->alloc_offset,
66
-
50
- m->nb_clusters * s->cluster_size,
67
- ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
51
+ ret = bdrv_co_pwrite_zeroes(s->data_file, start_offset, nb_bytes,
68
- if (ret < 0) {
52
BDRV_REQ_NO_FALLBACK);
69
- goto fail;
53
if (ret < 0) {
70
- }
54
if (ret != -ENOTSUP && ret != -EAGAIN) {
71
-
72
- /* Take the request off the list of running requests */
73
- if (l2meta->nb_clusters != 0) {
74
- QLIST_REMOVE(l2meta, next_in_flight);
75
- }
76
-
77
- qemu_co_queue_restart_all(&l2meta->dependent_requests);
78
-
79
- next = l2meta->next;
80
- g_free(l2meta);
81
- l2meta = next;
82
+ ret = qcow2_handle_l2meta(bs, &l2meta, true);
83
+ if (ret) {
84
+ goto fail;
85
}
86
87
bytes -= cur_bytes;
88
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
89
ret = 0;
90
91
fail:
92
- while (l2meta != NULL) {
93
- QCowL2Meta *next;
94
-
95
- if (l2meta->nb_clusters != 0) {
96
- QLIST_REMOVE(l2meta, next_in_flight);
97
- }
98
- qemu_co_queue_restart_all(&l2meta->dependent_requests);
99
-
100
- next = l2meta->next;
101
- g_free(l2meta);
102
- l2meta = next;
103
- }
104
+ qcow2_handle_l2meta(bs, &l2meta, false);
105
106
qemu_co_mutex_unlock(&s->lock);
107
108
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
109
return ret;
110
}
111
112
+static int coroutine_fn
113
+qcow2_co_copy_range_from(BlockDriverState *bs,
114
+ BdrvChild *src, uint64_t src_offset,
115
+ BdrvChild *dst, uint64_t dst_offset,
116
+ uint64_t bytes, BdrvRequestFlags flags)
117
+{
118
+ BDRVQcow2State *s = bs->opaque;
119
+ int ret;
120
+ unsigned int cur_bytes; /* number of bytes in current iteration */
121
+ BdrvChild *child = NULL;
122
+ BdrvRequestFlags cur_flags;
123
+
124
+ assert(!bs->encrypted);
125
+ qemu_co_mutex_lock(&s->lock);
126
+
127
+ while (bytes != 0) {
128
+ uint64_t copy_offset = 0;
129
+ /* prepare next request */
130
+ cur_bytes = MIN(bytes, INT_MAX);
131
+ cur_flags = flags;
132
+
133
+ ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes, &copy_offset);
134
+ if (ret < 0) {
135
+ goto out;
136
+ }
137
+
138
+ switch (ret) {
139
+ case QCOW2_CLUSTER_UNALLOCATED:
140
+ if (bs->backing && bs->backing->bs) {
141
+ int64_t backing_length = bdrv_getlength(bs->backing->bs);
142
+ if (src_offset >= backing_length) {
143
+ cur_flags |= BDRV_REQ_ZERO_WRITE;
144
+ } else {
145
+ child = bs->backing;
146
+ cur_bytes = MIN(cur_bytes, backing_length - src_offset);
147
+ copy_offset = src_offset;
148
+ }
149
+ } else {
150
+ cur_flags |= BDRV_REQ_ZERO_WRITE;
151
+ }
152
+ break;
153
+
154
+ case QCOW2_CLUSTER_ZERO_PLAIN:
155
+ case QCOW2_CLUSTER_ZERO_ALLOC:
156
+ cur_flags |= BDRV_REQ_ZERO_WRITE;
157
+ break;
158
+
159
+ case QCOW2_CLUSTER_COMPRESSED:
160
+ ret = -ENOTSUP;
161
+ goto out;
162
+ break;
163
+
164
+ case QCOW2_CLUSTER_NORMAL:
165
+ child = bs->file;
166
+ copy_offset += offset_into_cluster(s, src_offset);
167
+ if ((copy_offset & 511) != 0) {
168
+ ret = -EIO;
169
+ goto out;
170
+ }
171
+ break;
172
+
173
+ default:
174
+ abort();
175
+ }
176
+ qemu_co_mutex_unlock(&s->lock);
177
+ ret = bdrv_co_copy_range_from(child,
178
+ copy_offset,
179
+ dst, dst_offset,
180
+ cur_bytes, cur_flags);
181
+ qemu_co_mutex_lock(&s->lock);
182
+ if (ret < 0) {
183
+ goto out;
184
+ }
185
+
186
+ bytes -= cur_bytes;
187
+ src_offset += cur_bytes;
188
+ dst_offset += cur_bytes;
189
+ }
190
+ ret = 0;
191
+
192
+out:
193
+ qemu_co_mutex_unlock(&s->lock);
194
+ return ret;
195
+}
196
+
197
+static int coroutine_fn
198
+qcow2_co_copy_range_to(BlockDriverState *bs,
199
+ BdrvChild *src, uint64_t src_offset,
200
+ BdrvChild *dst, uint64_t dst_offset,
201
+ uint64_t bytes, BdrvRequestFlags flags)
202
+{
203
+ BDRVQcow2State *s = bs->opaque;
204
+ int offset_in_cluster;
205
+ int ret;
206
+ unsigned int cur_bytes; /* number of sectors in current iteration */
207
+ uint64_t cluster_offset;
208
+ uint8_t *cluster_data = NULL;
209
+ QCowL2Meta *l2meta = NULL;
210
+
211
+ assert(!bs->encrypted);
212
+ s->cluster_cache_offset = -1; /* disable compressed cache */
213
+
214
+ qemu_co_mutex_lock(&s->lock);
215
+
216
+ while (bytes != 0) {
217
+
218
+ l2meta = NULL;
219
+
220
+ offset_in_cluster = offset_into_cluster(s, dst_offset);
221
+ cur_bytes = MIN(bytes, INT_MAX);
222
+
223
+ /* TODO:
224
+ * If src->bs == dst->bs, we could simply copy by incrementing
225
+ * the refcnt, without copying user data.
226
+ * Or if src->bs == dst->bs->backing->bs, we could copy by discarding. */
227
+ ret = qcow2_alloc_cluster_offset(bs, dst_offset, &cur_bytes,
228
+ &cluster_offset, &l2meta);
229
+ if (ret < 0) {
230
+ goto fail;
231
+ }
232
+
233
+ assert((cluster_offset & 511) == 0);
234
+
235
+ ret = qcow2_pre_write_overlap_check(bs, 0,
236
+ cluster_offset + offset_in_cluster, cur_bytes);
237
+ if (ret < 0) {
238
+ goto fail;
239
+ }
240
+
241
+ qemu_co_mutex_unlock(&s->lock);
242
+ ret = bdrv_co_copy_range_to(src, src_offset,
243
+ bs->file,
244
+ cluster_offset + offset_in_cluster,
245
+ cur_bytes, flags);
246
+ qemu_co_mutex_lock(&s->lock);
247
+ if (ret < 0) {
248
+ goto fail;
249
+ }
250
+
251
+ ret = qcow2_handle_l2meta(bs, &l2meta, true);
252
+ if (ret) {
253
+ goto fail;
254
+ }
255
+
256
+ bytes -= cur_bytes;
257
+ dst_offset += cur_bytes;
258
+ }
259
+ ret = 0;
260
+
261
+fail:
262
+ qcow2_handle_l2meta(bs, &l2meta, false);
263
+
264
+ qemu_co_mutex_unlock(&s->lock);
265
+
266
+ qemu_vfree(cluster_data);
267
+ trace_qcow2_writev_done_req(qemu_coroutine_self(), ret);
268
+
269
+ return ret;
270
+}
271
+
272
static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
273
PreallocMode prealloc, Error **errp)
274
{
275
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
276
277
.bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,
278
.bdrv_co_pdiscard = qcow2_co_pdiscard,
279
+ .bdrv_co_copy_range_from = qcow2_co_copy_range_from,
280
+ .bdrv_co_copy_range_to = qcow2_co_copy_range_to,
281
.bdrv_truncate = qcow2_truncate,
282
.bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed,
283
.bdrv_make_empty = qcow2_make_empty,
284
--
55
--
285
2.17.1
56
2.26.2
286
57
287
58
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
We don't verify the request range against s->size in the I/O callbacks
3
This works now at the subcluster level and pwrite_zeroes_alignment is
4
except for raw_co_pwritev. This is inconsistent (especially for
4
updated accordingly.
5
raw_co_pwrite_zeroes and raw_co_pdiscard), so fix them, in the meanwhile
5
6
make the helper reusable by the coming new callbacks.
6
qcow2_cluster_zeroize() is turned into qcow2_subcluster_zeroize() with
7
7
the following changes:
8
Note that in most cases the block layer already verifies the request
8
9
byte range against our reported image length, before invoking the driver
9
- The request can now be subcluster-aligned.
10
callbacks. The exception is during image creating, after
10
11
blk_set_allow_write_beyond_eof(blk, true) is called. But in that case,
11
- The cluster-aligned body of the request is still zeroized using
12
the requests are not directly from the user or guest. So there is no
12
zero_in_l2_slice() as before.
13
visible behavior change in adding the check code.
13
14
14
- The subcluster-aligned head and tail of the request are zeroized
15
The int64_t -> uint64_t inconsistency, as shown by the type casting, is
15
with the new zero_l2_subclusters() function.
16
pre-existing due to the interface.
16
17
17
There is just one thing to take into account for a possible future
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
improvement: compressed clusters cannot be partially zeroized so
19
Reviewed-by: Eric Blake <eblake@redhat.com>
19
zero_l2_subclusters() on the head or the tail can return -ENOTSUP.
20
Signed-off-by: Fam Zheng <famz@redhat.com>
20
This makes the caller repeat the *complete* request and write actual
21
Message-id: 20180601092648.24614-3-famz@redhat.com
21
zeroes to disk. This is sub-optimal because
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
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>
23
---
33
---
24
block/raw-format.c | 64 ++++++++++++++++++++++++++++------------------
34
block/qcow2.h | 4 +--
25
1 file changed, 39 insertions(+), 25 deletions(-)
35
block/qcow2-cluster.c | 81 +++++++++++++++++++++++++++++++++++++++----
26
36
block/qcow2.c | 33 +++++++++---------
27
diff --git a/block/raw-format.c b/block/raw-format.c
37
3 files changed, 94 insertions(+), 24 deletions(-)
38
39
diff --git a/block/qcow2.h b/block/qcow2.h
28
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
29
--- a/block/raw-format.c
41
--- a/block/qcow2.h
30
+++ b/block/raw-format.c
42
+++ b/block/qcow2.h
31
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_abort(BDRVReopenState *state)
43
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
32
state->opaque = NULL;
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;
33
}
60
}
34
61
35
+/* Check and adjust the offset, against 'offset' and 'size' options. */
62
-int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
36
+static inline int raw_adjust_offset(BlockDriverState *bs, uint64_t *offset,
63
- uint64_t bytes, int flags)
37
+ uint64_t bytes, bool is_write)
64
+static int zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
65
+ unsigned nb_subclusters)
38
+{
66
+{
39
+ BDRVRawState *s = bs->opaque;
67
+ BDRVQcow2State *s = bs->opaque;
40
+
68
+ uint64_t *l2_slice;
41
+ if (s->has_size && (*offset > s->size || bytes > (s->size - *offset))) {
69
+ uint64_t old_l2_bitmap, l2_bitmap;
42
+ /* There's not enough space for the write, or the read request is
70
+ int l2_index, ret, sc = offset_to_sc_index(s, offset);
43
+ * out-of-range. Don't read/write anything to prevent leaking out of
71
+
44
+ * the size specified in options. */
72
+ /* For full clusters use zero_in_l2_slice() instead */
45
+ return is_write ? -ENOSPC : -EINVAL;;
73
+ assert(nb_subclusters > 0 && nb_subclusters < s->subclusters_per_cluster);
46
+ }
74
+ assert(sc + nb_subclusters <= s->subclusters_per_cluster);
47
+
75
+ assert(offset_into_subcluster(s, offset) == 0);
48
+ if (*offset > INT64_MAX - s->offset) {
76
+
49
+ return -EINVAL;
77
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
50
+ }
78
+ if (ret < 0) {
51
+ *offset += s->offset;
79
+ return ret;
52
+
80
+ }
53
+ return 0;
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;
54
+}
108
+}
55
+
109
+
56
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
110
+int qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,
57
uint64_t bytes, QEMUIOVector *qiov,
111
+ uint64_t bytes, int flags)
58
int flags)
59
{
112
{
60
- BDRVRawState *s = bs->opaque;
113
BDRVQcow2State *s = bs->opaque;
61
+ int ret;
114
uint64_t end_offset = offset + bytes;
62
115
uint64_t nb_clusters;
63
- if (offset > UINT64_MAX - s->offset) {
116
+ unsigned head, tail;
64
- return -EINVAL;
117
int64_t cleared;
65
+ ret = raw_adjust_offset(bs, &offset, bytes, false);
66
+ if (ret) {
67
+ return ret;
68
}
69
- offset += s->offset;
70
71
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
72
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
74
uint64_t bytes, QEMUIOVector *qiov,
75
int flags)
76
{
77
- BDRVRawState *s = bs->opaque;
78
void *buf = NULL;
79
BlockDriver *drv;
80
QEMUIOVector local_qiov;
81
int ret;
118
int ret;
82
119
83
- if (s->has_size && (offset > s->size || bytes > (s->size - offset))) {
120
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
84
- /* There's not enough space for the data. Don't write anything and just
121
}
85
- * fail to prevent leaking out of the size specified in options. */
122
86
- return -ENOSPC;
123
/* Caller must pass aligned values, except at image end */
87
- }
124
- assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
88
-
125
- assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
89
- if (offset > UINT64_MAX - s->offset) {
126
+ assert(offset_into_subcluster(s, offset) == 0);
90
- ret = -EINVAL;
127
+ assert(offset_into_subcluster(s, end_offset) == 0 ||
91
- goto fail;
128
end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
92
- }
129
93
-
130
/*
94
if (bs->probed && offset < BLOCK_PROBE_BUF_SIZE && bytes) {
131
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
95
/* Handling partial writes would be a pain - so we just
132
return -ENOTSUP;
96
* require that guests have 512-byte request alignment if
133
}
97
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
134
98
qiov = &local_qiov;
135
- /* Each L2 slice is handled by its own loop iteration */
99
}
136
- nb_clusters = size_to_clusters(s, bytes);
100
137
+ head = MIN(end_offset, ROUND_UP(offset, s->cluster_size)) - offset;
101
- offset += s->offset;
138
+ offset += head;
102
+ ret = raw_adjust_offset(bs, &offset, bytes, true);
139
+
103
+ if (ret) {
140
+ tail = (end_offset >= bs->total_sectors << BDRV_SECTOR_BITS) ? 0 :
104
+ goto fail;
141
+ end_offset - MAX(offset, start_of_cluster(s, end_offset));
105
+ }
142
+ end_offset -= tail;
106
143
107
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
144
s->cache_discards = true;
108
ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
145
109
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
146
+ if (head) {
110
int64_t offset, int bytes,
147
+ ret = zero_l2_subclusters(bs, offset - head,
111
BdrvRequestFlags flags)
148
+ size_to_subclusters(s, head));
112
{
149
+ if (ret < 0) {
113
- BDRVRawState *s = bs->opaque;
150
+ goto fail;
114
- if (offset > UINT64_MAX - s->offset) {
151
+ }
115
- return -EINVAL;
152
+ }
116
+ int ret;
153
+
117
+
154
+ /* Each L2 slice is handled by its own loop iteration */
118
+ ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
155
+ nb_clusters = size_to_clusters(s, end_offset - offset);
119
+ if (ret) {
156
+
120
+ return ret;
157
while (nb_clusters > 0) {
121
}
158
cleared = zero_in_l2_slice(bs, offset, nb_clusters, flags);
122
- offset += s->offset;
159
if (cleared < 0) {
123
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
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;
124
}
185
}
125
186
126
static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs,
187
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
127
int64_t offset, int bytes)
188
int ret;
128
{
189
BDRVQcow2State *s = bs->opaque;
129
- BDRVRawState *s = bs->opaque;
190
130
- if (offset > UINT64_MAX - s->offset) {
191
- uint32_t head = offset % s->cluster_size;
131
- return -EINVAL;
192
- uint32_t tail = (offset + bytes) % s->cluster_size;
132
+ int ret;
193
+ uint32_t head = offset_into_subcluster(s, offset);
133
+
194
+ uint32_t tail = ROUND_UP(offset + bytes, s->subcluster_size) -
134
+ ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
195
+ (offset + bytes);
135
+ if (ret) {
196
136
+ return ret;
197
trace_qcow2_pwrite_zeroes_start_req(qemu_coroutine_self(), offset, bytes);
137
}
198
if (offset + bytes == bs->total_sectors * BDRV_SECTOR_SIZE) {
138
- offset += s->offset;
199
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
139
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
200
unsigned int nr;
140
}
201
QCow2SubclusterType type;
141
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;
142
--
258
--
143
2.17.1
259
2.26.2
144
260
145
261
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
Extended L2 entries are bigger than normal L2 entries so this has an
4
impact on the amount of metadata needed for a qcow2 file.
5
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <7efae2efd5e36b42d2570743a12576d68ce53685.1594396418.git.berto@igalia.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
block/qcow2.c | 20 +++++++++++++-------
12
1 file changed, 13 insertions(+), 7 deletions(-)
13
14
diff --git a/block/qcow2.c b/block/qcow2.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qcow2.c
17
+++ b/block/qcow2.c
18
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
19
* @total_size: virtual disk size in bytes
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)
32
{
33
int64_t meta_size = 0;
34
uint64_t nl1e, nl2e;
35
int64_t aligned_total_size = ROUND_UP(total_size, cluster_size);
36
+ size_t l2e_size = extended_l2 ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
37
38
/* header: 1 cluster */
39
meta_size += cluster_size;
40
41
/* total size of L2 tables */
42
nl2e = aligned_total_size / cluster_size;
43
- nl2e = ROUND_UP(nl2e, cluster_size / sizeof(uint64_t));
44
- meta_size += nl2e * sizeof(uint64_t);
45
+ nl2e = ROUND_UP(nl2e, cluster_size / l2e_size);
46
+ meta_size += nl2e * l2e_size;
47
48
/* total size of L1 tables */
49
- nl1e = nl2e * sizeof(uint64_t) / cluster_size;
50
+ nl1e = nl2e * l2e_size / cluster_size;
51
nl1e = ROUND_UP(nl1e, cluster_size / sizeof(uint64_t));
52
meta_size += nl1e * sizeof(uint64_t);
53
54
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
55
PreallocMode prealloc;
56
bool has_backing_file;
57
bool has_luks;
58
+ bool extended_l2 = false; /* Set to false until the option is added */
59
+ size_t l2e_size;
60
61
/* Parse image creation options */
62
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
63
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
64
virtual_size = ROUND_UP(virtual_size, cluster_size);
65
66
/* Check that virtual disk size is valid */
67
+ l2e_size = extended_l2 ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
68
l2_tables = DIV_ROUND_UP(virtual_size / cluster_size,
69
- cluster_size / sizeof(uint64_t));
70
+ cluster_size / l2e_size);
71
if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) {
72
error_setg(&local_err, "The image size is too large "
73
"(try using a larger cluster size)");
74
@@ -XXX,XX +XXX,XX @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
75
}
76
77
info = g_new0(BlockMeasureInfo, 1);
78
- info->fully_allocated =
79
+ info->fully_allocated = luks_payload_size +
80
qcow2_calc_prealloc_size(virtual_size, cluster_size,
81
- ctz32(refcount_bits)) + luks_payload_size;
82
+ ctz32(refcount_bits), extended_l2);
83
84
/*
85
* Remove data clusters that are not required. This overestimates the
86
--
87
2.26.2
88
89
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This field allows us to indicate that the L2 metadata update does not
4
come from a write request with actual data but from a preallocation
5
request.
6
7
For traditional images this does not make any difference, but for
8
images with extended L2 entries this means that the clusters are
9
allocated normally in the L2 table but individual subclusters are
10
marked as unallocated.
11
12
This will allow preallocating images that have a backing file.
13
14
There is one special case: when we resize an existing image we can
15
also request that the new clusters are preallocated. If the image
16
already had a backing file then we have to hide any possible stale
17
data and zero out the new clusters (see commit 955c7d6687 for more
18
details).
19
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>
28
---
29
block/qcow2.h | 8 ++++++++
30
block/qcow2-cluster.c | 2 +-
31
block/qcow2.c | 6 ++++++
32
3 files changed, 15 insertions(+), 1 deletion(-)
33
34
diff --git a/block/qcow2.h b/block/qcow2.h
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/qcow2.h
37
+++ b/block/qcow2.h
38
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
39
*/
40
bool skip_cow;
41
42
+ /**
43
+ * Indicates that this is not a normal write request but a preallocation.
44
+ * If the image has extended L2 entries this means that no new individual
45
+ * subclusters will be marked as allocated in the L2 bitmap (but any
46
+ * existing contents of that bitmap will be kept).
47
+ */
48
+ bool prealloc;
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
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/qcow2-cluster.c
56
+++ b/block/qcow2-cluster.c
57
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
58
set_l2_entry(s, l2_slice, l2_index + i, offset | QCOW_OFLAG_COPIED);
59
60
/* Update bitmap with the subclusters that were just written */
61
- if (has_subclusters(s)) {
62
+ if (has_subclusters(s) && !m->prealloc) {
63
uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
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);
110
111
--
112
2.26.2
113
114
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Introduce the bdrv_co_copy_range() API for copy offloading. Block
3
Now that the implementation of subclusters is complete we can finally
4
drivers implementing this API support efficient copy operations that
4
add the necessary options to create and read images with this feature,
5
avoid reading each block from the source device and writing it to the
5
which we call "extended L2 entries".
6
destination devices. Examples of copy offload primitives are SCSI
7
EXTENDED COPY and Linux copy_file_range(2).
8
6
9
Signed-off-by: Fam Zheng <famz@redhat.com>
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-id: 20180601092648.24614-2-famz@redhat.com
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@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
---
13
---
14
include/block/block.h | 32 +++++++++++++
14
qapi/block-core.json | 7 +++
15
include/block/block_int.h | 38 +++++++++++++++
15
block/qcow2.h | 8 ++-
16
block/io.c | 97 +++++++++++++++++++++++++++++++++++++++
16
include/block/block_int.h | 1 +
17
3 files changed, 167 insertions(+)
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(-)
18
40
19
diff --git a/include/block/block.h b/include/block/block.h
41
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/block.h
43
--- a/qapi/block-core.json
22
+++ b/include/block/block.h
44
+++ b/qapi/block-core.json
23
@@ -XXX,XX +XXX,XX @@ bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
45
@@ -XXX,XX +XXX,XX @@
24
*/
46
# standalone (read-only) raw image without looking at qcow2
25
void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size);
47
# metadata (since: 4.0)
26
void bdrv_unregister_buf(BlockDriverState *bs, void *host);
48
#
27
+
49
+# @extended-l2: true if the image has extended L2 entries; only valid for
28
+/**
50
+# compat >= 1.1 (since 5.2)
29
+ *
51
+#
30
+ * bdrv_co_copy_range:
52
# @lazy-refcounts: on or off; only valid for compat >= 1.1
31
+ *
53
#
32
+ * Do offloaded copy between two children. If the operation is not implemented
54
# @corrupt: true if the image has been marked corrupt; only valid for
33
+ * by the driver, or if the backend storage doesn't support it, a negative
55
@@ -XXX,XX +XXX,XX @@
34
+ * error code will be returned.
56
'compat': 'str',
35
+ *
57
'*data-file': 'str',
36
+ * Note: block layer doesn't emulate or fallback to a bounce buffer approach
58
'*data-file-raw': 'bool',
37
+ * because usually the caller shouldn't attempt offloaded copy any more (e.g.
59
+ '*extended-l2': 'bool',
38
+ * calling copy_file_range(2)) after the first error, thus it should fall back
60
'*lazy-refcounts': 'bool',
39
+ * to a read+write path in the caller level.
61
'*corrupt': 'bool',
40
+ *
62
'refcount-bits': 'int',
41
+ * @src: Source child to copy data from
63
@@ -XXX,XX +XXX,XX @@
42
+ * @src_offset: offset in @src image to read data
64
# @data-file-raw: True if the external data file must stay valid as a
43
+ * @dst: Destination child to copy data to
65
# standalone (read-only) raw image without looking at qcow2
44
+ * @dst_offset: offset in @dst image to write data
66
# metadata (default: false; since: 4.0)
45
+ * @bytes: number of bytes to copy
67
+# @extended-l2 True to make the image have extended L2 entries
46
+ * @flags: request flags. Must be one of:
68
+# (default: false; since 5.2)
47
+ * 0 - actually read data from src;
69
# @size: Size of the virtual disk in bytes
48
+ * BDRV_REQ_ZERO_WRITE - treat the @src range as zero data and do zero
70
# @version: Compatibility level (default: v3)
49
+ * write on @dst as if bdrv_co_pwrite_zeroes is
71
# @backing-file: File name of the backing file if a backing file
50
+ * called. Used to simplify caller code, or
72
@@ -XXX,XX +XXX,XX @@
51
+ * during BlockDriver.bdrv_co_copy_range_from()
73
'data': { 'file': 'BlockdevRef',
52
+ * recursion.
74
'*data-file': 'BlockdevRef',
53
+ *
75
'*data-file-raw': 'bool',
54
+ * Returns: 0 if succeeded; negative error code if failed.
76
+ '*extended-l2': 'bool',
55
+ **/
77
'size': 'size',
56
+int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
78
'*version': 'BlockdevQcow2Version',
57
+ BdrvChild *dst, uint64_t dst_offset,
79
'*backing-file': 'str',
58
+ uint64_t bytes, BdrvRequestFlags flags);
80
diff --git a/block/qcow2.h b/block/qcow2.h
59
#endif
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,
101
};
102
103
/* Compatible feature bits */
104
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
105
106
static inline bool has_subclusters(BDRVQcow2State *s)
107
{
108
- /* FIXME: Return false until this feature is complete */
109
- return false;
110
+ return s->incompatible_features & QCOW2_INCOMPAT_EXTL2;
111
}
112
113
static inline size_t l2_entry_size(BDRVQcow2State *s)
60
diff --git a/include/block/block_int.h b/include/block/block_int.h
114
diff --git a/include/block/block_int.h b/include/block/block_int.h
61
index XXXXXXX..XXXXXXX 100644
115
index XXXXXXX..XXXXXXX 100644
62
--- a/include/block/block_int.h
116
--- a/include/block/block_int.h
63
+++ b/include/block/block_int.h
117
+++ b/include/block/block_int.h
64
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
118
@@ -XXX,XX +XXX,XX @@
65
int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs,
119
#define BLOCK_OPT_DATA_FILE "data_file"
66
int64_t offset, int bytes);
120
#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw"
67
121
#define BLOCK_OPT_COMPRESSION_TYPE "compression_type"
68
+ /* Map [offset, offset + nbytes) range onto a child of @bs to copy from,
122
+#define BLOCK_OPT_EXTL2 "extended_l2"
69
+ * and invoke bdrv_co_copy_range_from(child, ...), or invoke
123
70
+ * bdrv_co_copy_range_to() if @bs is the leaf child to copy data from.
124
#define BLOCK_PROBE_BUF_SIZE 512
71
+ *
125
72
+ * See the comment of bdrv_co_copy_range for the parameter and return value
126
diff --git a/block/qcow2.c b/block/qcow2.c
73
+ * semantics.
127
index XXXXXXX..XXXXXXX 100644
74
+ */
128
--- a/block/qcow2.c
75
+ int coroutine_fn (*bdrv_co_copy_range_from)(BlockDriverState *bs,
129
+++ b/block/qcow2.c
76
+ BdrvChild *src,
130
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
77
+ uint64_t offset,
131
s->subcluster_size = s->cluster_size / s->subclusters_per_cluster;
78
+ BdrvChild *dst,
132
s->subcluster_bits = ctz32(s->subcluster_size);
79
+ uint64_t dst_offset,
133
80
+ uint64_t bytes,
134
+ if (s->subcluster_size < (1 << MIN_CLUSTER_BITS)) {
81
+ BdrvRequestFlags flags);
135
+ error_setg(errp, "Unsupported subcluster size: %d", s->subcluster_size);
82
+
136
+ ret = -EINVAL;
83
+ /* Map [offset, offset + nbytes) range onto a child of bs to copy data to,
137
+ goto fail;
84
+ * and invoke bdrv_co_copy_range_to(child, src, ...), or perform the copy
85
+ * operation if @bs is the leaf and @src has the same BlockDriver. Return
86
+ * -ENOTSUP if @bs is the leaf but @src has a different BlockDriver.
87
+ *
88
+ * See the comment of bdrv_co_copy_range for the parameter and return value
89
+ * semantics.
90
+ */
91
+ int coroutine_fn (*bdrv_co_copy_range_to)(BlockDriverState *bs,
92
+ BdrvChild *src,
93
+ uint64_t src_offset,
94
+ BdrvChild *dst,
95
+ uint64_t dst_offset,
96
+ uint64_t bytes,
97
+ BdrvRequestFlags flags);
98
+
99
/*
100
* Building block for bdrv_block_status[_above] and
101
* bdrv_is_allocated[_above]. The driver should answer only
102
@@ -XXX,XX +XXX,XX @@ void bdrv_dec_in_flight(BlockDriverState *bs);
103
104
void blockdev_close_all_bdrv_states(void);
105
106
+int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
107
+ BdrvChild *dst, uint64_t dst_offset,
108
+ uint64_t bytes, BdrvRequestFlags flags);
109
+int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
110
+ BdrvChild *dst, uint64_t dst_offset,
111
+ uint64_t bytes, BdrvRequestFlags flags);
112
+
113
#endif /* BLOCK_INT_H */
114
diff --git a/block/io.c b/block/io.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/block/io.c
117
+++ b/block/io.c
118
@@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host)
119
bdrv_unregister_buf(child->bs, host);
120
}
121
}
122
+
123
+static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
124
+ uint64_t src_offset,
125
+ BdrvChild *dst,
126
+ uint64_t dst_offset,
127
+ uint64_t bytes,
128
+ BdrvRequestFlags flags,
129
+ bool recurse_src)
130
+{
131
+ int ret;
132
+
133
+ if (!src || !dst || !src->bs || !dst->bs) {
134
+ return -ENOMEDIUM;
135
+ }
136
+ ret = bdrv_check_byte_request(src->bs, src_offset, bytes);
137
+ if (ret) {
138
+ return ret;
139
+ }
138
+ }
140
+
139
+
141
+ ret = bdrv_check_byte_request(dst->bs, dst_offset, bytes);
140
/* Check support for various header values */
142
+ if (ret) {
141
if (header.refcount_order > 6) {
143
+ return ret;
142
error_setg(errp, "Reference count entry width too large; may not "
144
+ }
143
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
145
+ if (flags & BDRV_REQ_ZERO_WRITE) {
144
.bit = QCOW2_INCOMPAT_COMPRESSION_BITNR,
146
+ return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, flags);
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
+ }
147
+ }
178
+ }
148
+
179
+
149
+ if (!src->bs->drv->bdrv_co_copy_range_from
180
return true;
150
+ || !dst->bs->drv->bdrv_co_copy_range_to
181
}
151
+ || src->bs->encrypted || dst->bs->encrypted) {
182
152
+ return -ENOTSUP;
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;
153
+ }
203
+ }
154
+ if (recurse_src) {
204
+ if (qcow2_opts->extended_l2) {
155
+ return src->bs->drv->bdrv_co_copy_range_from(src->bs,
205
+ if (version < 3) {
156
+ src, src_offset,
206
+ error_setg(errp, "Extended L2 entries are only supported with "
157
+ dst, dst_offset,
207
+ "compatibility level 1.1 and above (use version=v3 or "
158
+ bytes, flags);
208
+ "greater)");
159
+ } else {
209
+ ret = -EINVAL;
160
+ return dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
210
+ goto out;
161
+ src, src_offset,
211
+ }
162
+ dst, dst_offset,
163
+ bytes, flags);
164
+ }
212
+ }
165
+}
166
+
213
+
167
+/* Copy range from @src to @dst.
214
+ if (!validate_cluster_size(cluster_size, qcow2_opts->extended_l2, errp)) {
168
+ *
215
ret = -EINVAL;
169
+ * See the comment of bdrv_co_copy_range for the parameter and return value
216
goto out;
170
+ * semantics. */
217
}
171
+int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
218
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
172
+ BdrvChild *dst, uint64_t dst_offset,
219
cpu_to_be64(QCOW2_INCOMPAT_COMPRESSION);
173
+ uint64_t bytes, BdrvRequestFlags flags)
220
}
174
+{
221
175
+ return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
222
+ if (qcow2_opts->extended_l2) {
176
+ bytes, flags, true);
223
+ header->incompatible_features |=
177
+}
224
+ cpu_to_be64(QCOW2_INCOMPAT_EXTL2);
225
+ }
178
+
226
+
179
+/* Copy range from @src to @dst.
227
ret = blk_pwrite(blk, 0, header, cluster_size, 0);
180
+ *
228
g_free(header);
181
+ * See the comment of bdrv_co_copy_range for the parameter and return value
229
if (ret < 0) {
182
+ * semantics. */
230
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv,
183
+int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
231
{ BLOCK_OPT_BACKING_FMT, "backing-fmt" },
184
+ BdrvChild *dst, uint64_t dst_offset,
232
{ BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
185
+ uint64_t bytes, BdrvRequestFlags flags)
233
{ BLOCK_OPT_LAZY_REFCOUNTS, "lazy-refcounts" },
186
+{
234
+ { BLOCK_OPT_EXTL2, "extended-l2" },
187
+ return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
235
{ BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" },
188
+ bytes, flags, false);
236
{ BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
189
+}
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);
190
+
249
+
191
+int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
250
+ cluster_size = qcow2_opt_get_cluster_size_del(opts, extended_l2,
192
+ BdrvChild *dst, uint64_t dst_offset,
251
+ &local_err);
193
+ uint64_t bytes, BdrvRequestFlags flags)
252
if (local_err) {
194
+{
253
goto err;
195
+ BdrvTrackedRequest src_req, dst_req;
254
}
196
+ BlockDriverState *src_bs = src->bs;
255
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
197
+ BlockDriverState *dst_bs = dst->bs;
256
.corrupt = s->incompatible_features &
198
+ int ret;
257
QCOW2_INCOMPAT_CORRUPT,
199
+
258
.has_corrupt = true,
200
+ bdrv_inc_in_flight(src_bs);
259
+ .has_extended_l2 = true,
201
+ bdrv_inc_in_flight(dst_bs);
260
+ .extended_l2 = has_subclusters(s),
202
+ tracked_request_begin(&src_req, src_bs, src_offset,
261
.refcount_bits = s->refcount_bits,
203
+ bytes, BDRV_TRACKED_READ);
262
.has_bitmaps = !!bitmaps,
204
+ tracked_request_begin(&dst_req, dst_bs, dst_offset,
263
.bitmaps = bitmaps,
205
+ bytes, BDRV_TRACKED_WRITE);
264
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qcow2_create_opts = {
206
+
265
.help = "qcow2 cluster size", \
207
+ wait_serialising_requests(&src_req);
266
.def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \
208
+ wait_serialising_requests(&dst_req);
267
}, \
209
+ ret = bdrv_co_copy_range_from(src, src_offset,
268
+ { \
210
+ dst, dst_offset,
269
+ .name = BLOCK_OPT_EXTL2, \
211
+ bytes, flags);
270
+ .type = QEMU_OPT_BOOL, \
212
+
271
+ .help = "Extended L2 tables", \
213
+ tracked_request_end(&src_req);
272
+ .def_value_str = "off" \
214
+ tracked_request_end(&dst_req);
273
+ }, \
215
+ bdrv_dec_in_flight(src_bs);
274
{ \
216
+ bdrv_dec_in_flight(dst_bs);
275
.name = BLOCK_OPT_PREALLOC, \
217
+ return ret;
276
.type = QEMU_OPT_STRING, \
218
+}
277
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
278
index XXXXXXX..XXXXXXX 100644
279
--- a/tests/qemu-iotests/031.out
280
+++ b/tests/qemu-iotests/031.out
281
@@ -XXX,XX +XXX,XX @@ header_length 112
282
283
Header extension:
284
magic 0x6803f857 (Feature table)
285
-length 336
286
+length 384
287
data <binary>
288
289
Header extension:
290
@@ -XXX,XX +XXX,XX @@ header_length 112
291
292
Header extension:
293
magic 0x6803f857 (Feature table)
294
-length 336
295
+length 384
296
data <binary>
297
298
Header extension:
299
@@ -XXX,XX +XXX,XX @@ No errors were found on the image.
300
301
magic 0x514649fb
302
version 3
303
-backing_file_offset 0x210
304
+backing_file_offset 0x240
305
backing_file_size 0x17
306
cluster_bits 16
307
size 67108864
308
@@ -XXX,XX +XXX,XX @@ data 'host_device'
309
310
Header extension:
311
magic 0x6803f857 (Feature table)
312
-length 336
313
+length 384
314
data <binary>
315
316
Header extension:
317
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
318
index XXXXXXX..XXXXXXX 100644
319
--- a/tests/qemu-iotests/036.out
320
+++ b/tests/qemu-iotests/036.out
321
@@ -XXX,XX +XXX,XX @@ compatible_features []
322
autoclear_features [63]
323
Header extension:
324
magic 0x6803f857 (Feature table)
325
-length 336
326
+length 384
327
data <binary>
328
329
330
@@ -XXX,XX +XXX,XX @@ compatible_features []
331
autoclear_features []
332
Header extension:
333
magic 0x6803f857 (Feature table)
334
-length 336
335
+length 384
336
data <binary>
337
338
*** done
339
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
340
index XXXXXXX..XXXXXXX 100644
341
--- a/tests/qemu-iotests/049.out
342
+++ b/tests/qemu-iotests/049.out
343
@@ -XXX,XX +XXX,XX @@ QA output created by 049
344
== 1. Traditional size parameter ==
345
346
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
347
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
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
349
350
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
351
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
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
353
354
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
355
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
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
357
358
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
359
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 compression_type=zlib size=1024 lazy_refcounts=off refcount_bits=16
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" \
219
--
1497
--
220
2.17.1
1498
2.26.2
221
1499
222
1500
diff view generated by jsdifflib
1
Commit d759c951f3287fad04210a52f2dc93f94cf58c7f ("replay: push
1
From: Alberto Garcia <berto@igalia.com>
2
replay_mutex_lock up the call tree") removed the !timeout lock
3
optimization in the main loop.
4
2
5
The idea of the optimization was to avoid ping-pongs between threads by
3
Traditional qcow2 images don't allow preallocation if a backing file
6
keeping the Big QEMU Lock held across non-blocking (!timeout) main loop
4
is set. This is because once a cluster is allocated there is no way to
7
iterations.
5
tell that its data should be read from the backing file.
8
6
9
A warning is printed when the main loop spins without releasing BQL for
7
Extended L2 entries have individual allocation bits for each
10
long periods of time. These warnings were supposed to aid debugging but
8
subcluster, and therefore it is perfectly possible to have an
11
in practice they just alarm users. They are considered noise because
9
allocated cluster with all its subclusters unallocated.
12
the cause of spinning is not shown and is hard to find.
13
10
14
Now that the lock optimization has been removed, there is no danger of
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
15
hogging the BQL. Drop the spin counter and the infamous warning.
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Message-Id: <6d5b0f38e7dc5f2f31d8cab1cb92044e9909aece.1594396418.git.berto@igalia.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
---
17
block/qcow2.c | 7 ++++---
18
tests/qemu-iotests/206.out | 2 +-
19
2 files changed, 5 insertions(+), 4 deletions(-)
16
20
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
diff --git a/block/qcow2.c b/block/qcow2.c
18
Reviewed-by: Jeff Cody <jcody@redhat.com>
19
---
20
util/main-loop.c | 25 -------------------------
21
tests/qemu-iotests/common.filter | 1 -
22
2 files changed, 26 deletions(-)
23
24
diff --git a/util/main-loop.c b/util/main-loop.c
25
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
26
--- a/util/main-loop.c
23
--- a/block/qcow2.c
27
+++ b/util/main-loop.c
24
+++ b/block/qcow2.c
28
@@ -XXX,XX +XXX,XX @@ static int os_host_main_loop_wait(int64_t timeout)
25
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
29
{
26
qcow2_opts->preallocation = PREALLOC_MODE_OFF;
30
GMainContext *context = g_main_context_default();
27
}
31
int ret;
28
if (qcow2_opts->has_backing_file &&
32
- static int spin_counter;
29
- qcow2_opts->preallocation != PREALLOC_MODE_OFF)
33
30
+ qcow2_opts->preallocation != PREALLOC_MODE_OFF &&
34
g_main_context_acquire(context);
31
+ !qcow2_opts->extended_l2)
35
32
{
36
glib_pollfds_fill(&timeout);
33
- error_setg(errp, "Backing file and preallocation cannot be used at "
37
34
- "the same time");
38
- /* If the I/O thread is very busy or we are incorrectly busy waiting in
35
+ error_setg(errp, "Backing file and preallocation can only be used at "
39
- * the I/O thread, this can lead to starvation of the BQL such that the
36
+ "the same time if extended_l2 is on");
40
- * VCPU threads never run. To make sure we can detect the later case,
37
ret = -EINVAL;
41
- * print a message to the screen. If we run into this condition, create
38
goto out;
42
- * a fake timeout in order to give the VCPU threads a chance to run.
39
}
43
- */
40
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
44
- if (!timeout && (spin_counter > MAX_MAIN_LOOP_SPIN)) {
45
- static bool notified;
46
-
47
- if (!notified && !qtest_enabled() && !qtest_driver()) {
48
- warn_report("I/O thread spun for %d iterations",
49
- MAX_MAIN_LOOP_SPIN);
50
- notified = true;
51
- }
52
-
53
- timeout = SCALE_MS;
54
- }
55
-
56
-
57
- if (timeout) {
58
- spin_counter = 0;
59
- } else {
60
- spin_counter++;
61
- }
62
qemu_mutex_unlock_iothread();
63
replay_mutex_unlock();
64
65
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
66
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
67
--- a/tests/qemu-iotests/common.filter
42
--- a/tests/qemu-iotests/206.out
68
+++ b/tests/qemu-iotests/common.filter
43
+++ b/tests/qemu-iotests/206.out
69
@@ -XXX,XX +XXX,XX @@ _filter_qemu()
44
@@ -XXX,XX +XXX,XX @@ Job failed: Different refcount widths than 16 bits require compatibility level 1
70
{
45
=== Invalid backing file options ===
71
sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
46
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}}
72
-e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \
47
{"return": {}}
73
- -e '/main-loop: WARNING: I\/O thread spun for [0-9]\+ iterations/d' \
48
-Job failed: Backing file and preallocation cannot be used at the same time
74
-e $'s#\r##' # QEMU monitor uses \r\n line endings
49
+Job failed: Backing file and preallocation can only be used at the same time if extended_l2 is on
75
}
50
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
51
{"return": {}}
76
52
77
--
53
--
78
2.17.1
54
2.26.2
79
55
80
56
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
This function is only used by qcow2_expand_zero_clusters() to
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.
8
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-Id: <15e65112b4144381b4d8c0bdf8fb76b0d813e3d1.1594396418.git.berto@igalia.com>
13
[mreitz: Fixed comment style]
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
block/qcow2-cluster.c | 14 ++++++++++++--
17
tests/qemu-iotests/061 | 6 ++++++
18
tests/qemu-iotests/061.out | 5 +++++
19
3 files changed, 23 insertions(+), 2 deletions(-)
20
21
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow2-cluster.c
24
+++ b/block/qcow2-cluster.c
25
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
26
int ret;
27
int i, j;
28
29
+ /* qcow2_downgrade() is not allowed in images with subclusters */
30
+ assert(!has_subclusters(s));
31
+
32
slice_size2 = s->l2_slice_size * l2_entry_size(s);
33
n_slices = s->cluster_size / slice_size2;
34
35
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
36
37
if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
38
if (!bs->backing) {
39
- /* not backed; therefore we can simply deallocate the
40
- * cluster */
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
93
--
94
2.26.2
95
96
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
It's a BlockBackend wrapper of the BDS interface.
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
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
4
14
5
Signed-off-by: Fam Zheng <famz@redhat.com>
15
diff --git a/tests/qemu-iotests/271 b/tests/qemu-iotests/271
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
new file mode 100755
7
Message-id: 20180601092648.24614-10-famz@redhat.com
17
index XXXXXXX..XXXXXXX
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
--- /dev/null
9
---
19
+++ b/tests/qemu-iotests/271
10
include/sysemu/block-backend.h | 4 ++++
20
@@ -XXX,XX +XXX,XX @@
11
block/block-backend.c | 18 ++++++++++++++++++
21
+#!/bin/bash
12
2 files changed, 22 insertions(+)
22
+#
13
23
+# Test qcow2 images with extended L2 entries
14
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
24
+#
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
15
index XXXXXXX..XXXXXXX 100644
1655
index XXXXXXX..XXXXXXX 100644
16
--- a/include/sysemu/block-backend.h
1656
--- a/tests/qemu-iotests/group
17
+++ b/include/sysemu/block-backend.h
1657
+++ b/tests/qemu-iotests/group
18
@@ -XXX,XX +XXX,XX @@ void blk_set_force_allow_inactivate(BlockBackend *blk);
1658
@@ -XXX,XX +XXX,XX @@
19
void blk_register_buf(BlockBackend *blk, void *host, size_t size);
1659
267 rw auto quick snapshot
20
void blk_unregister_buf(BlockBackend *blk, void *host);
1660
268 rw auto quick
21
1661
270 rw backing quick
22
+int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
1662
+271 rw auto
23
+ BlockBackend *blk_out, int64_t off_out,
1663
272 rw
24
+ int bytes, BdrvRequestFlags flags);
1664
273 backing quick
25
+
1665
274 rw backing
26
#endif
27
diff --git a/block/block-backend.c b/block/block-backend.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/block-backend.c
30
+++ b/block/block-backend.c
31
@@ -XXX,XX +XXX,XX @@ void blk_unregister_buf(BlockBackend *blk, void *host)
32
{
33
bdrv_unregister_buf(blk_bs(blk), host);
34
}
35
+
36
+int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
37
+ BlockBackend *blk_out, int64_t off_out,
38
+ int bytes, BdrvRequestFlags flags)
39
+{
40
+ int r;
41
+ r = blk_check_byte_request(blk_in, off_in, bytes);
42
+ if (r) {
43
+ return r;
44
+ }
45
+ r = blk_check_byte_request(blk_out, off_out, bytes);
46
+ if (r) {
47
+ return r;
48
+ }
49
+ return bdrv_co_copy_range(blk_in->root, off_in,
50
+ blk_out->root, off_out,
51
+ bytes, flags);
52
+}
53
--
1666
--
54
2.17.1
1667
2.26.2
55
1668
56
1669
diff view generated by jsdifflib