2 * Threaded data processing for Qcow2: compression, encryption
4 * Copyright (c) 2004-2006 Fabrice Bellard
5 * Copyright (c) 2018 Virtuozzo International GmbH. All rights reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "qemu/osdep.h"
32 #include "block/thread-pool.h"
35 static int coroutine_fn
36 qcow2_co_process(BlockDriverState
*bs
, ThreadPoolFunc
*func
, void *arg
)
39 BDRVQcow2State
*s
= bs
->opaque
;
40 ThreadPool
*pool
= aio_get_thread_pool(bdrv_get_aio_context(bs
));
42 qemu_co_mutex_lock(&s
->lock
);
43 while (s
->nb_threads
>= QCOW2_MAX_THREADS
) {
44 qemu_co_queue_wait(&s
->thread_task_queue
, &s
->lock
);
47 qemu_co_mutex_unlock(&s
->lock
);
49 ret
= thread_pool_submit_co(pool
, func
, arg
);
51 qemu_co_mutex_lock(&s
->lock
);
53 qemu_co_queue_next(&s
->thread_task_queue
);
54 qemu_co_mutex_unlock(&s
->lock
);
64 typedef ssize_t (*Qcow2CompressFunc
)(void *dest
, size_t dest_size
,
65 const void *src
, size_t src_size
);
66 typedef struct Qcow2CompressData
{
73 Qcow2CompressFunc func
;
77 * qcow2_zlib_compress()
79 * Compress @src_size bytes of data using zlib compression method
81 * @dest - destination buffer, @dest_size bytes
82 * @src - source buffer, @src_size bytes
84 * Returns: compressed size on success
85 * -ENOMEM destination buffer is not enough to store compressed data
86 * -EIO on any other error
88 static ssize_t
qcow2_zlib_compress(void *dest
, size_t dest_size
,
89 const void *src
, size_t src_size
)
94 /* best compression, small window, no zlib header */
95 memset(&strm
, 0, sizeof(strm
));
96 ret
= deflateInit2(&strm
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
,
97 -12, 9, Z_DEFAULT_STRATEGY
);
103 * strm.next_in is not const in old zlib versions, such as those used on
104 * OpenBSD/NetBSD, so cast the const away
106 strm
.avail_in
= src_size
;
107 strm
.next_in
= (void *) src
;
108 strm
.avail_out
= dest_size
;
109 strm
.next_out
= dest
;
111 ret
= deflate(&strm
, Z_FINISH
);
112 if (ret
== Z_STREAM_END
) {
113 ret
= dest_size
- strm
.avail_out
;
115 ret
= (ret
== Z_OK
? -ENOMEM
: -EIO
);
124 * qcow2_zlib_decompress()
126 * Decompress some data (not more than @src_size bytes) to produce exactly
127 * @dest_size bytes using zlib compression method
129 * @dest - destination buffer, @dest_size bytes
130 * @src - source buffer, @src_size bytes
132 * Returns: 0 on success
135 static ssize_t
qcow2_zlib_decompress(void *dest
, size_t dest_size
,
136 const void *src
, size_t src_size
)
141 memset(&strm
, 0, sizeof(strm
));
142 strm
.avail_in
= src_size
;
143 strm
.next_in
= (void *) src
;
144 strm
.avail_out
= dest_size
;
145 strm
.next_out
= dest
;
147 ret
= inflateInit2(&strm
, -12);
152 ret
= inflate(&strm
, Z_FINISH
);
153 if ((ret
== Z_STREAM_END
|| ret
== Z_BUF_ERROR
) && strm
.avail_out
== 0) {
155 * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
156 * @src buffer may be processed partly (because in qcow2 we know size of
157 * compressed data with precision of one sector)
169 static int qcow2_compress_pool_func(void *opaque
)
171 Qcow2CompressData
*data
= opaque
;
173 data
->ret
= data
->func(data
->dest
, data
->dest_size
,
174 data
->src
, data
->src_size
);
179 static ssize_t coroutine_fn
180 qcow2_co_do_compress(BlockDriverState
*bs
, void *dest
, size_t dest_size
,
181 const void *src
, size_t src_size
, Qcow2CompressFunc func
)
183 Qcow2CompressData arg
= {
185 .dest_size
= dest_size
,
187 .src_size
= src_size
,
191 qcow2_co_process(bs
, qcow2_compress_pool_func
, &arg
);
197 * qcow2_co_compress()
199 * Compress @src_size bytes of data using the compression
200 * method defined by the image compression type
202 * @dest - destination buffer, @dest_size bytes
203 * @src - source buffer, @src_size bytes
205 * Returns: compressed size on success
206 * a negative error code on failure
209 qcow2_co_compress(BlockDriverState
*bs
, void *dest
, size_t dest_size
,
210 const void *src
, size_t src_size
)
212 BDRVQcow2State
*s
= bs
->opaque
;
213 Qcow2CompressFunc fn
;
215 switch (s
->compression_type
) {
216 case QCOW2_COMPRESSION_TYPE_ZLIB
:
217 fn
= qcow2_zlib_compress
;
224 return qcow2_co_do_compress(bs
, dest
, dest_size
, src
, src_size
, fn
);
228 * qcow2_co_decompress()
230 * Decompress some data (not more than @src_size bytes) to produce exactly
231 * @dest_size bytes using the compression method defined by the image
234 * @dest - destination buffer, @dest_size bytes
235 * @src - source buffer, @src_size bytes
237 * Returns: 0 on success
238 * a negative error code on failure
241 qcow2_co_decompress(BlockDriverState
*bs
, void *dest
, size_t dest_size
,
242 const void *src
, size_t src_size
)
244 BDRVQcow2State
*s
= bs
->opaque
;
245 Qcow2CompressFunc fn
;
247 switch (s
->compression_type
) {
248 case QCOW2_COMPRESSION_TYPE_ZLIB
:
249 fn
= qcow2_zlib_decompress
;
256 return qcow2_co_do_compress(bs
, dest
, dest_size
, src
, src_size
, fn
);
265 * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
266 * qcrypto_block_decrypt() functions.
268 typedef int (*Qcow2EncDecFunc
)(QCryptoBlock
*block
, uint64_t offset
,
269 uint8_t *buf
, size_t len
, Error
**errp
);
271 typedef struct Qcow2EncDecData
{
277 Qcow2EncDecFunc func
;
280 static int qcow2_encdec_pool_func(void *opaque
)
282 Qcow2EncDecData
*data
= opaque
;
284 return data
->func(data
->block
, data
->offset
, data
->buf
, data
->len
, NULL
);
287 static int coroutine_fn
288 qcow2_co_encdec(BlockDriverState
*bs
, uint64_t host_offset
,
289 uint64_t guest_offset
, void *buf
, size_t len
,
290 Qcow2EncDecFunc func
)
292 BDRVQcow2State
*s
= bs
->opaque
;
293 Qcow2EncDecData arg
= {
295 .offset
= s
->crypt_physical_offset
? host_offset
: guest_offset
,
300 uint64_t sector_size
;
304 sector_size
= qcrypto_block_get_sector_size(s
->crypto
);
305 assert(QEMU_IS_ALIGNED(guest_offset
, sector_size
));
306 assert(QEMU_IS_ALIGNED(host_offset
, sector_size
));
307 assert(QEMU_IS_ALIGNED(len
, sector_size
));
309 return len
== 0 ? 0 : qcow2_co_process(bs
, qcow2_encdec_pool_func
, &arg
);
315 * Encrypts one or more contiguous aligned sectors
317 * @host_offset - underlying storage offset of the first sector of the
318 * data to be encrypted
320 * @guest_offset - guest (virtual) offset of the first sector of the
321 * data to be encrypted
323 * @buf - buffer with the data to encrypt, that after encryption
324 * will be written to the underlying storage device at
327 * @len - length of the buffer (must be a multiple of the encryption
330 * Depending on the encryption method, @host_offset and/or @guest_offset
331 * may be used for generating the initialization vector for
334 * Note that while the whole range must be aligned on sectors, it
335 * does not have to be aligned on clusters and can also cross cluster
339 qcow2_co_encrypt(BlockDriverState
*bs
, uint64_t host_offset
,
340 uint64_t guest_offset
, void *buf
, size_t len
)
342 return qcow2_co_encdec(bs
, host_offset
, guest_offset
, buf
, len
,
343 qcrypto_block_encrypt
);
349 * Decrypts one or more contiguous aligned sectors
350 * Similar to qcow2_co_encrypt
353 qcow2_co_decrypt(BlockDriverState
*bs
, uint64_t host_offset
,
354 uint64_t guest_offset
, void *buf
, size_t len
)
356 return qcow2_co_encdec(bs
, host_offset
, guest_offset
, buf
, len
,
357 qcrypto_block_decrypt
);