]> Git Repo - qemu.git/blame - block/qcow2-threads.c
qcow2: rework the cluster compression routine
[qemu.git] / block / qcow2-threads.c
CommitLineData
56e2f1d8
VSO
1/*
2 * Threaded data processing for Qcow2: compression, encryption
3 *
4 * Copyright (c) 2004-2006 Fabrice Bellard
5 * Copyright (c) 2018 Virtuozzo International GmbH. All rights reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
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
23 * THE SOFTWARE.
24 */
25
26#include "qemu/osdep.h"
27
28#define ZLIB_CONST
29#include <zlib.h>
30
31#include "qcow2.h"
32#include "block/thread-pool.h"
8ac0f15f 33#include "crypto.h"
6f13a316
VSO
34
35static int coroutine_fn
36qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
37{
38 int ret;
39 BDRVQcow2State *s = bs->opaque;
40 ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
41
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);
45 }
46 s->nb_threads++;
47 qemu_co_mutex_unlock(&s->lock);
48
49 ret = thread_pool_submit_co(pool, func, arg);
50
51 qemu_co_mutex_lock(&s->lock);
52 s->nb_threads--;
53 qemu_co_queue_next(&s->thread_task_queue);
54 qemu_co_mutex_unlock(&s->lock);
55
56 return ret;
57}
58
59
60/*
61 * Compression
62 */
56e2f1d8
VSO
63
64typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
65 const void *src, size_t src_size);
66typedef struct Qcow2CompressData {
67 void *dest;
68 size_t dest_size;
69 const void *src;
70 size_t src_size;
71 ssize_t ret;
72
73 Qcow2CompressFunc func;
74} Qcow2CompressData;
75
76/*
25dd077d
DP
77 * qcow2_zlib_compress()
78 *
79 * Compress @src_size bytes of data using zlib compression method
56e2f1d8
VSO
80 *
81 * @dest - destination buffer, @dest_size bytes
82 * @src - source buffer, @src_size bytes
83 *
84 * Returns: compressed size on success
85 * -ENOMEM destination buffer is not enough to store compressed data
86 * -EIO on any other error
87 */
25dd077d
DP
88static ssize_t qcow2_zlib_compress(void *dest, size_t dest_size,
89 const void *src, size_t src_size)
56e2f1d8
VSO
90{
91 ssize_t ret;
92 z_stream strm;
93
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);
98 if (ret != Z_OK) {
99 return -EIO;
100 }
101
102 /*
103 * strm.next_in is not const in old zlib versions, such as those used on
104 * OpenBSD/NetBSD, so cast the const away
105 */
106 strm.avail_in = src_size;
107 strm.next_in = (void *) src;
108 strm.avail_out = dest_size;
109 strm.next_out = dest;
110
111 ret = deflate(&strm, Z_FINISH);
112 if (ret == Z_STREAM_END) {
113 ret = dest_size - strm.avail_out;
114 } else {
115 ret = (ret == Z_OK ? -ENOMEM : -EIO);
116 }
117
118 deflateEnd(&strm);
119
120 return ret;
121}
122
123/*
25dd077d 124 * qcow2_zlib_decompress()
56e2f1d8
VSO
125 *
126 * Decompress some data (not more than @src_size bytes) to produce exactly
25dd077d 127 * @dest_size bytes using zlib compression method
56e2f1d8
VSO
128 *
129 * @dest - destination buffer, @dest_size bytes
130 * @src - source buffer, @src_size bytes
131 *
132 * Returns: 0 on success
e7266570 133 * -EIO on fail
56e2f1d8 134 */
25dd077d
DP
135static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size,
136 const void *src, size_t src_size)
56e2f1d8 137{
e7266570 138 int ret;
56e2f1d8
VSO
139 z_stream strm;
140
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;
146
147 ret = inflateInit2(&strm, -12);
148 if (ret != Z_OK) {
e7266570 149 return -EIO;
56e2f1d8
VSO
150 }
151
152 ret = inflate(&strm, Z_FINISH);
e7266570 153 if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
56e2f1d8
VSO
154 /*
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)
158 */
e7266570
VSO
159 ret = 0;
160 } else {
161 ret = -EIO;
56e2f1d8
VSO
162 }
163
164 inflateEnd(&strm);
165
166 return ret;
167}
168
169static int qcow2_compress_pool_func(void *opaque)
170{
171 Qcow2CompressData *data = opaque;
172
173 data->ret = data->func(data->dest, data->dest_size,
174 data->src, data->src_size);
175
176 return 0;
177}
178
56e2f1d8
VSO
179static ssize_t coroutine_fn
180qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
181 const void *src, size_t src_size, Qcow2CompressFunc func)
182{
56e2f1d8
VSO
183 Qcow2CompressData arg = {
184 .dest = dest,
185 .dest_size = dest_size,
186 .src = src,
187 .src_size = src_size,
188 .func = func,
189 };
190
6f13a316 191 qcow2_co_process(bs, qcow2_compress_pool_func, &arg);
56e2f1d8
VSO
192
193 return arg.ret;
194}
195
25dd077d
DP
196/*
197 * qcow2_co_compress()
198 *
199 * Compress @src_size bytes of data using the compression
200 * method defined by the image compression type
201 *
202 * @dest - destination buffer, @dest_size bytes
203 * @src - source buffer, @src_size bytes
204 *
205 * Returns: compressed size on success
206 * a negative error code on failure
207 */
56e2f1d8
VSO
208ssize_t coroutine_fn
209qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
210 const void *src, size_t src_size)
211{
25dd077d
DP
212 BDRVQcow2State *s = bs->opaque;
213 Qcow2CompressFunc fn;
214
215 switch (s->compression_type) {
216 case QCOW2_COMPRESSION_TYPE_ZLIB:
217 fn = qcow2_zlib_compress;
218 break;
219
220 default:
221 abort();
222 }
223
224 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
56e2f1d8
VSO
225}
226
25dd077d
DP
227/*
228 * qcow2_co_decompress()
229 *
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
232 * compression type
233 *
234 * @dest - destination buffer, @dest_size bytes
235 * @src - source buffer, @src_size bytes
236 *
237 * Returns: 0 on success
238 * a negative error code on failure
239 */
56e2f1d8
VSO
240ssize_t coroutine_fn
241qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
242 const void *src, size_t src_size)
243{
25dd077d
DP
244 BDRVQcow2State *s = bs->opaque;
245 Qcow2CompressFunc fn;
246
247 switch (s->compression_type) {
248 case QCOW2_COMPRESSION_TYPE_ZLIB:
249 fn = qcow2_zlib_decompress;
250 break;
251
252 default:
253 abort();
254 }
255
256 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
56e2f1d8 257}
8ac0f15f
VSO
258
259
260/*
261 * Cryptography
262 */
263
264/*
265 * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
266 * qcrypto_block_decrypt() functions.
267 */
268typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
269 uint8_t *buf, size_t len, Error **errp);
270
271typedef struct Qcow2EncDecData {
272 QCryptoBlock *block;
273 uint64_t offset;
274 uint8_t *buf;
275 size_t len;
276
277 Qcow2EncDecFunc func;
278} Qcow2EncDecData;
279
280static int qcow2_encdec_pool_func(void *opaque)
281{
282 Qcow2EncDecData *data = opaque;
283
284 return data->func(data->block, data->offset, data->buf, data->len, NULL);
285}
286
287static int coroutine_fn
603fbd07
ML
288qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
289 uint64_t guest_offset, void *buf, size_t len,
290 Qcow2EncDecFunc func)
8ac0f15f
VSO
291{
292 BDRVQcow2State *s = bs->opaque;
293 Qcow2EncDecData arg = {
294 .block = s->crypto,
603fbd07 295 .offset = s->crypt_physical_offset ? host_offset : guest_offset,
8ac0f15f
VSO
296 .buf = buf,
297 .len = len,
298 .func = func,
299 };
2d4b5256 300 uint64_t sector_size;
8ac0f15f 301
603fbd07
ML
302 assert(s->crypto);
303
2d4b5256
AG
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));
308
603fbd07 309 return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
8ac0f15f
VSO
310}
311
603fbd07
ML
312/*
313 * qcow2_co_encrypt()
314 *
315 * Encrypts one or more contiguous aligned sectors
316 *
317 * @host_offset - underlying storage offset of the first sector of the
318 * data to be encrypted
319 *
320 * @guest_offset - guest (virtual) offset of the first sector of the
321 * data to be encrypted
322 *
323 * @buf - buffer with the data to encrypt, that after encryption
324 * will be written to the underlying storage device at
325 * @host_offset
326 *
2d4b5256
AG
327 * @len - length of the buffer (must be a multiple of the encryption
328 * sector size)
603fbd07
ML
329 *
330 * Depending on the encryption method, @host_offset and/or @guest_offset
331 * may be used for generating the initialization vector for
332 * encryption.
333 *
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
336 * boundaries
337 */
8ac0f15f 338int coroutine_fn
603fbd07
ML
339qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset,
340 uint64_t guest_offset, void *buf, size_t len)
8ac0f15f 341{
603fbd07
ML
342 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
343 qcrypto_block_encrypt);
8ac0f15f
VSO
344}
345
603fbd07
ML
346/*
347 * qcow2_co_decrypt()
348 *
349 * Decrypts one or more contiguous aligned sectors
350 * Similar to qcow2_co_encrypt
351 */
8ac0f15f 352int coroutine_fn
603fbd07
ML
353qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset,
354 uint64_t guest_offset, void *buf, size_t len)
8ac0f15f 355{
603fbd07
ML
356 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
357 qcrypto_block_decrypt);
8ac0f15f 358}
This page took 0.156968 seconds and 4 git commands to generate.