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