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
;
79 * @dest - destination buffer, @dest_size bytes
80 * @src - source buffer, @src_size bytes
82 * Returns: compressed size on success
83 * -ENOMEM destination buffer is not enough to store compressed data
84 * -EIO on any other error
86 static ssize_t
qcow2_compress(void *dest
, size_t dest_size
,
87 const void *src
, size_t src_size
)
92 /* best compression, small window, no zlib header */
93 memset(&strm
, 0, sizeof(strm
));
94 ret
= deflateInit2(&strm
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
,
95 -12, 9, Z_DEFAULT_STRATEGY
);
101 * strm.next_in is not const in old zlib versions, such as those used on
102 * OpenBSD/NetBSD, so cast the const away
104 strm
.avail_in
= src_size
;
105 strm
.next_in
= (void *) src
;
106 strm
.avail_out
= dest_size
;
107 strm
.next_out
= dest
;
109 ret
= deflate(&strm
, Z_FINISH
);
110 if (ret
== Z_STREAM_END
) {
111 ret
= dest_size
- strm
.avail_out
;
113 ret
= (ret
== Z_OK
? -ENOMEM
: -EIO
);
124 * Decompress some data (not more than @src_size bytes) to produce exactly
127 * @dest - destination buffer, @dest_size bytes
128 * @src - source buffer, @src_size bytes
130 * Returns: 0 on success
133 static ssize_t
qcow2_decompress(void *dest
, size_t dest_size
,
134 const void *src
, size_t src_size
)
139 memset(&strm
, 0, sizeof(strm
));
140 strm
.avail_in
= src_size
;
141 strm
.next_in
= (void *) src
;
142 strm
.avail_out
= dest_size
;
143 strm
.next_out
= dest
;
145 ret
= inflateInit2(&strm
, -12);
150 ret
= inflate(&strm
, Z_FINISH
);
151 if ((ret
!= Z_STREAM_END
&& ret
!= Z_BUF_ERROR
) || strm
.avail_out
!= 0) {
153 * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
154 * @src buffer may be processed partly (because in qcow2 we know size of
155 * compressed data with precision of one sector)
165 static int qcow2_compress_pool_func(void *opaque
)
167 Qcow2CompressData
*data
= opaque
;
169 data
->ret
= data
->func(data
->dest
, data
->dest_size
,
170 data
->src
, data
->src_size
);
175 static ssize_t coroutine_fn
176 qcow2_co_do_compress(BlockDriverState
*bs
, void *dest
, size_t dest_size
,
177 const void *src
, size_t src_size
, Qcow2CompressFunc func
)
179 Qcow2CompressData arg
= {
181 .dest_size
= dest_size
,
183 .src_size
= src_size
,
187 qcow2_co_process(bs
, qcow2_compress_pool_func
, &arg
);
193 qcow2_co_compress(BlockDriverState
*bs
, void *dest
, size_t dest_size
,
194 const void *src
, size_t src_size
)
196 return qcow2_co_do_compress(bs
, dest
, dest_size
, src
, src_size
,
201 qcow2_co_decompress(BlockDriverState
*bs
, void *dest
, size_t dest_size
,
202 const void *src
, size_t src_size
)
204 return qcow2_co_do_compress(bs
, dest
, dest_size
, src
, src_size
,
214 * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
215 * qcrypto_block_decrypt() functions.
217 typedef int (*Qcow2EncDecFunc
)(QCryptoBlock
*block
, uint64_t offset
,
218 uint8_t *buf
, size_t len
, Error
**errp
);
220 typedef struct Qcow2EncDecData
{
226 Qcow2EncDecFunc func
;
229 static int qcow2_encdec_pool_func(void *opaque
)
231 Qcow2EncDecData
*data
= opaque
;
233 return data
->func(data
->block
, data
->offset
, data
->buf
, data
->len
, NULL
);
236 static int coroutine_fn
237 qcow2_co_encdec(BlockDriverState
*bs
, uint64_t file_cluster_offset
,
238 uint64_t offset
, void *buf
, size_t len
, Qcow2EncDecFunc func
)
240 BDRVQcow2State
*s
= bs
->opaque
;
241 Qcow2EncDecData arg
= {
243 .offset
= s
->crypt_physical_offset
?
244 file_cluster_offset
+ offset_into_cluster(s
, offset
) :
251 return qcow2_co_process(bs
, qcow2_encdec_pool_func
, &arg
);
255 qcow2_co_encrypt(BlockDriverState
*bs
, uint64_t file_cluster_offset
,
256 uint64_t offset
, void *buf
, size_t len
)
258 return qcow2_co_encdec(bs
, file_cluster_offset
, offset
, buf
, len
,
259 qcrypto_block_encrypt
);
263 qcow2_co_decrypt(BlockDriverState
*bs
, uint64_t file_cluster_offset
,
264 uint64_t offset
, void *buf
, size_t len
)
266 return qcow2_co_encdec(bs
, file_cluster_offset
, offset
, buf
, len
,
267 qcrypto_block_decrypt
);