1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "qemu/osdep.h"
27
28#define ZLIB_CONST
29#include <zlib.h>
30
31#ifdef CONFIG_ZSTD
32#include <zstd.h>
33#include <zstd_errors.h>
34#endif
35
36#include "qcow2.h"
37#include "block/thread-pool.h"
38#include "crypto.h"
39
40static int coroutine_fn
41qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
42{
43 int ret;
44 BDRVQcow2State *s = bs->opaque;
45 ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
46
47 qemu_co_mutex_lock(&s->lock);
48 while (s->nb_threads >= QCOW2_MAX_THREADS) {
49 qemu_co_queue_wait(&s->thread_task_queue, &s->lock);
50 }
51 s->nb_threads++;
52 qemu_co_mutex_unlock(&s->lock);
53
54 ret = thread_pool_submit_co(pool, func, arg);
55
56 qemu_co_mutex_lock(&s->lock);
57 s->nb_threads--;
58 qemu_co_queue_next(&s->thread_task_queue);
59 qemu_co_mutex_unlock(&s->lock);
60
61 return ret;
62}
63
64
65
66
67
68
69typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
70 const void *src, size_t src_size);
71typedef struct Qcow2CompressData {
72 void *dest;
73 size_t dest_size;
74 const void *src;
75 size_t src_size;
76 ssize_t ret;
77
78 Qcow2CompressFunc func;
79} Qcow2CompressData;
80
81
82
83
84
85
86
87
88
89
90
91
92
93static ssize_t qcow2_zlib_compress(void *dest, size_t dest_size,
94 const void *src, size_t src_size)
95{
96 ssize_t ret;
97 z_stream strm;
98
99
100 memset(&strm, 0, sizeof(strm));
101 ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
102 -12, 9, Z_DEFAULT_STRATEGY);
103 if (ret != Z_OK) {
104 return -EIO;
105 }
106
107
108
109
110
111 strm.avail_in = src_size;
112 strm.next_in = (void *) src;
113 strm.avail_out = dest_size;
114 strm.next_out = dest;
115
116 ret = deflate(&strm, Z_FINISH);
117 if (ret == Z_STREAM_END) {
118 ret = dest_size - strm.avail_out;
119 } else {
120 ret = (ret == Z_OK ? -ENOMEM : -EIO);
121 }
122
123 deflateEnd(&strm);
124
125 return ret;
126}
127
128
129
130
131
132
133
134
135
136
137
138
139
140static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size,
141 const void *src, size_t src_size)
142{
143 int ret;
144 z_stream strm;
145
146 memset(&strm, 0, sizeof(strm));
147 strm.avail_in = src_size;
148 strm.next_in = (void *) src;
149 strm.avail_out = dest_size;
150 strm.next_out = dest;
151
152 ret = inflateInit2(&strm, -12);
153 if (ret != Z_OK) {
154 return -EIO;
155 }
156
157 ret = inflate(&strm, Z_FINISH);
158 if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
159
160
161
162
163
164 ret = 0;
165 } else {
166 ret = -EIO;
167 }
168
169 inflateEnd(&strm);
170
171 return ret;
172}
173
174#ifdef CONFIG_ZSTD
175
176
177
178
179
180
181
182
183
184
185
186
187
188static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size,
189 const void *src, size_t src_size)
190{
191 ssize_t ret;
192 size_t zstd_ret;
193 ZSTD_outBuffer output = {
194 .dst = dest,
195 .size = dest_size,
196 .pos = 0
197 };
198 ZSTD_inBuffer input = {
199 .src = src,
200 .size = src_size,
201 .pos = 0
202 };
203 ZSTD_CCtx *cctx = ZSTD_createCCtx();
204
205 if (!cctx) {
206 return -EIO;
207 }
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 zstd_ret = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
226
227 if (zstd_ret) {
228 if (zstd_ret > output.size - output.pos) {
229 ret = -ENOMEM;
230 } else {
231 ret = -EIO;
232 }
233 goto out;
234 }
235
236
237 assert(output.pos <= dest_size);
238 ret = output.pos;
239out:
240 ZSTD_freeCCtx(cctx);
241 return ret;
242}
243
244
245
246
247
248
249
250
251
252
253
254
255
256static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
257 const void *src, size_t src_size)
258{
259 size_t zstd_ret = 0;
260 ssize_t ret = 0;
261 ZSTD_outBuffer output = {
262 .dst = dest,
263 .size = dest_size,
264 .pos = 0
265 };
266 ZSTD_inBuffer input = {
267 .src = src,
268 .size = src_size,
269 .pos = 0
270 };
271 ZSTD_DCtx *dctx = ZSTD_createDCtx();
272
273 if (!dctx) {
274 return -EIO;
275 }
276
277
278
279
280
281
282
283
284
285
286
287
288 while (output.pos < output.size) {
289 size_t last_in_pos = input.pos;
290 size_t last_out_pos = output.pos;
291 zstd_ret = ZSTD_decompressStream(dctx, &output, &input);
292
293 if (ZSTD_isError(zstd_ret)) {
294 ret = -EIO;
295 break;
296 }
297
298
299
300
301
302
303
304
305
306 if (last_in_pos >= input.pos &&
307 last_out_pos >= output.pos) {
308 ret = -EIO;
309 break;
310 }
311 }
312
313
314
315
316
317
318 if (zstd_ret > 0) {
319 ret = -EIO;
320 }
321
322 ZSTD_freeDCtx(dctx);
323 assert(ret == 0 || ret == -EIO);
324 return ret;
325}
326#endif
327
328static int qcow2_compress_pool_func(void *opaque)
329{
330 Qcow2CompressData *data = opaque;
331
332 data->ret = data->func(data->dest, data->dest_size,
333 data->src, data->src_size);
334
335 return 0;
336}
337
338static ssize_t coroutine_fn
339qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
340 const void *src, size_t src_size, Qcow2CompressFunc func)
341{
342 Qcow2CompressData arg = {
343 .dest = dest,
344 .dest_size = dest_size,
345 .src = src,
346 .src_size = src_size,
347 .func = func,
348 };
349
350 qcow2_co_process(bs, qcow2_compress_pool_func, &arg);
351
352 return arg.ret;
353}
354
355
356
357
358
359
360
361
362
363
364
365
366
367ssize_t coroutine_fn
368qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
369 const void *src, size_t src_size)
370{
371 BDRVQcow2State *s = bs->opaque;
372 Qcow2CompressFunc fn;
373
374 switch (s->compression_type) {
375 case QCOW2_COMPRESSION_TYPE_ZLIB:
376 fn = qcow2_zlib_compress;
377 break;
378
379#ifdef CONFIG_ZSTD
380 case QCOW2_COMPRESSION_TYPE_ZSTD:
381 fn = qcow2_zstd_compress;
382 break;
383#endif
384 default:
385 abort();
386 }
387
388 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
389}
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404ssize_t coroutine_fn
405qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
406 const void *src, size_t src_size)
407{
408 BDRVQcow2State *s = bs->opaque;
409 Qcow2CompressFunc fn;
410
411 switch (s->compression_type) {
412 case QCOW2_COMPRESSION_TYPE_ZLIB:
413 fn = qcow2_zlib_decompress;
414 break;
415
416#ifdef CONFIG_ZSTD
417 case QCOW2_COMPRESSION_TYPE_ZSTD:
418 fn = qcow2_zstd_decompress;
419 break;
420#endif
421 default:
422 abort();
423 }
424
425 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
426}
427
428
429
430
431
432
433
434
435
436
437typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
438 uint8_t *buf, size_t len, Error **errp);
439
440typedef struct Qcow2EncDecData {
441 QCryptoBlock *block;
442 uint64_t offset;
443 uint8_t *buf;
444 size_t len;
445
446 Qcow2EncDecFunc func;
447} Qcow2EncDecData;
448
449static int qcow2_encdec_pool_func(void *opaque)
450{
451 Qcow2EncDecData *data = opaque;
452
453 return data->func(data->block, data->offset, data->buf, data->len, NULL);
454}
455
456static int coroutine_fn
457qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
458 uint64_t guest_offset, void *buf, size_t len,
459 Qcow2EncDecFunc func)
460{
461 BDRVQcow2State *s = bs->opaque;
462 Qcow2EncDecData arg = {
463 .block = s->crypto,
464 .offset = s->crypt_physical_offset ? host_offset : guest_offset,
465 .buf = buf,
466 .len = len,
467 .func = func,
468 };
469 uint64_t sector_size;
470
471 assert(s->crypto);
472
473 sector_size = qcrypto_block_get_sector_size(s->crypto);
474 assert(QEMU_IS_ALIGNED(guest_offset, sector_size));
475 assert(QEMU_IS_ALIGNED(host_offset, sector_size));
476 assert(QEMU_IS_ALIGNED(len, sector_size));
477
478 return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
479}
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507int coroutine_fn
508qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset,
509 uint64_t guest_offset, void *buf, size_t len)
510{
511 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
512 qcrypto_block_encrypt);
513}
514
515
516
517
518
519
520
521int coroutine_fn
522qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset,
523 uint64_t guest_offset, void *buf, size_t len)
524{
525 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
526 qcrypto_block_decrypt);
527}
528