xref: /qemu/block/qcow2-threads.c (revision aef04fc7)
156e2f1d8SVladimir Sementsov-Ogievskiy /*
256e2f1d8SVladimir Sementsov-Ogievskiy  * Threaded data processing for Qcow2: compression, encryption
356e2f1d8SVladimir Sementsov-Ogievskiy  *
456e2f1d8SVladimir Sementsov-Ogievskiy  * Copyright (c) 2004-2006 Fabrice Bellard
556e2f1d8SVladimir Sementsov-Ogievskiy  * Copyright (c) 2018 Virtuozzo International GmbH. All rights reserved.
656e2f1d8SVladimir Sementsov-Ogievskiy  *
756e2f1d8SVladimir Sementsov-Ogievskiy  * Permission is hereby granted, free of charge, to any person obtaining a copy
856e2f1d8SVladimir Sementsov-Ogievskiy  * of this software and associated documentation files (the "Software"), to deal
956e2f1d8SVladimir Sementsov-Ogievskiy  * in the Software without restriction, including without limitation the rights
1056e2f1d8SVladimir Sementsov-Ogievskiy  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1156e2f1d8SVladimir Sementsov-Ogievskiy  * copies of the Software, and to permit persons to whom the Software is
1256e2f1d8SVladimir Sementsov-Ogievskiy  * furnished to do so, subject to the following conditions:
1356e2f1d8SVladimir Sementsov-Ogievskiy  *
1456e2f1d8SVladimir Sementsov-Ogievskiy  * The above copyright notice and this permission notice shall be included in
1556e2f1d8SVladimir Sementsov-Ogievskiy  * all copies or substantial portions of the Software.
1656e2f1d8SVladimir Sementsov-Ogievskiy  *
1756e2f1d8SVladimir Sementsov-Ogievskiy  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1856e2f1d8SVladimir Sementsov-Ogievskiy  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1956e2f1d8SVladimir Sementsov-Ogievskiy  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2056e2f1d8SVladimir Sementsov-Ogievskiy  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2156e2f1d8SVladimir Sementsov-Ogievskiy  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2256e2f1d8SVladimir Sementsov-Ogievskiy  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2356e2f1d8SVladimir Sementsov-Ogievskiy  * THE SOFTWARE.
2456e2f1d8SVladimir Sementsov-Ogievskiy  */
2556e2f1d8SVladimir Sementsov-Ogievskiy 
2656e2f1d8SVladimir Sementsov-Ogievskiy #include "qemu/osdep.h"
2756e2f1d8SVladimir Sementsov-Ogievskiy 
2856e2f1d8SVladimir Sementsov-Ogievskiy #define ZLIB_CONST
2956e2f1d8SVladimir Sementsov-Ogievskiy #include <zlib.h>
3056e2f1d8SVladimir Sementsov-Ogievskiy 
31d298ac10SDenis Plotnikov #ifdef CONFIG_ZSTD
32d298ac10SDenis Plotnikov #include <zstd.h>
33d298ac10SDenis Plotnikov #include <zstd_errors.h>
34d298ac10SDenis Plotnikov #endif
35d298ac10SDenis Plotnikov 
3656e2f1d8SVladimir Sementsov-Ogievskiy #include "qcow2.h"
37e2c1c34fSMarkus Armbruster #include "block/block-io.h"
3856e2f1d8SVladimir Sementsov-Ogievskiy #include "block/thread-pool.h"
398ac0f15fSVladimir Sementsov-Ogievskiy #include "crypto.h"
406f13a316SVladimir Sementsov-Ogievskiy 
416f13a316SVladimir Sementsov-Ogievskiy static int coroutine_fn
qcow2_co_process(BlockDriverState * bs,ThreadPoolFunc * func,void * arg)426f13a316SVladimir Sementsov-Ogievskiy qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
436f13a316SVladimir Sementsov-Ogievskiy {
446f13a316SVladimir Sementsov-Ogievskiy     int ret;
456f13a316SVladimir Sementsov-Ogievskiy     BDRVQcow2State *s = bs->opaque;
466f13a316SVladimir Sementsov-Ogievskiy 
476f13a316SVladimir Sementsov-Ogievskiy     qemu_co_mutex_lock(&s->lock);
486f13a316SVladimir Sementsov-Ogievskiy     while (s->nb_threads >= QCOW2_MAX_THREADS) {
496f13a316SVladimir Sementsov-Ogievskiy         qemu_co_queue_wait(&s->thread_task_queue, &s->lock);
506f13a316SVladimir Sementsov-Ogievskiy     }
516f13a316SVladimir Sementsov-Ogievskiy     s->nb_threads++;
526f13a316SVladimir Sementsov-Ogievskiy     qemu_co_mutex_unlock(&s->lock);
536f13a316SVladimir Sementsov-Ogievskiy 
54aef04fc7SEmanuele Giuseppe Esposito     ret = thread_pool_submit_co(func, arg);
556f13a316SVladimir Sementsov-Ogievskiy 
566f13a316SVladimir Sementsov-Ogievskiy     qemu_co_mutex_lock(&s->lock);
576f13a316SVladimir Sementsov-Ogievskiy     s->nb_threads--;
586f13a316SVladimir Sementsov-Ogievskiy     qemu_co_queue_next(&s->thread_task_queue);
596f13a316SVladimir Sementsov-Ogievskiy     qemu_co_mutex_unlock(&s->lock);
606f13a316SVladimir Sementsov-Ogievskiy 
616f13a316SVladimir Sementsov-Ogievskiy     return ret;
626f13a316SVladimir Sementsov-Ogievskiy }
636f13a316SVladimir Sementsov-Ogievskiy 
646f13a316SVladimir Sementsov-Ogievskiy 
656f13a316SVladimir Sementsov-Ogievskiy /*
666f13a316SVladimir Sementsov-Ogievskiy  * Compression
676f13a316SVladimir Sementsov-Ogievskiy  */
6856e2f1d8SVladimir Sementsov-Ogievskiy 
6956e2f1d8SVladimir Sementsov-Ogievskiy typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
7056e2f1d8SVladimir Sementsov-Ogievskiy                                      const void *src, size_t src_size);
7156e2f1d8SVladimir Sementsov-Ogievskiy typedef struct Qcow2CompressData {
7256e2f1d8SVladimir Sementsov-Ogievskiy     void *dest;
7356e2f1d8SVladimir Sementsov-Ogievskiy     size_t dest_size;
7456e2f1d8SVladimir Sementsov-Ogievskiy     const void *src;
7556e2f1d8SVladimir Sementsov-Ogievskiy     size_t src_size;
7656e2f1d8SVladimir Sementsov-Ogievskiy     ssize_t ret;
7756e2f1d8SVladimir Sementsov-Ogievskiy 
7856e2f1d8SVladimir Sementsov-Ogievskiy     Qcow2CompressFunc func;
7956e2f1d8SVladimir Sementsov-Ogievskiy } Qcow2CompressData;
8056e2f1d8SVladimir Sementsov-Ogievskiy 
8156e2f1d8SVladimir Sementsov-Ogievskiy /*
8225dd077dSDenis Plotnikov  * qcow2_zlib_compress()
8325dd077dSDenis Plotnikov  *
8425dd077dSDenis Plotnikov  * Compress @src_size bytes of data using zlib compression method
8556e2f1d8SVladimir Sementsov-Ogievskiy  *
8656e2f1d8SVladimir Sementsov-Ogievskiy  * @dest - destination buffer, @dest_size bytes
8756e2f1d8SVladimir Sementsov-Ogievskiy  * @src - source buffer, @src_size bytes
8856e2f1d8SVladimir Sementsov-Ogievskiy  *
8956e2f1d8SVladimir Sementsov-Ogievskiy  * Returns: compressed size on success
9056e2f1d8SVladimir Sementsov-Ogievskiy  *          -ENOMEM destination buffer is not enough to store compressed data
9156e2f1d8SVladimir Sementsov-Ogievskiy  *          -EIO    on any other error
9256e2f1d8SVladimir Sementsov-Ogievskiy  */
qcow2_zlib_compress(void * dest,size_t dest_size,const void * src,size_t src_size)9325dd077dSDenis Plotnikov static ssize_t qcow2_zlib_compress(void *dest, size_t dest_size,
9456e2f1d8SVladimir Sementsov-Ogievskiy                                    const void *src, size_t src_size)
9556e2f1d8SVladimir Sementsov-Ogievskiy {
9656e2f1d8SVladimir Sementsov-Ogievskiy     ssize_t ret;
9756e2f1d8SVladimir Sementsov-Ogievskiy     z_stream strm;
9856e2f1d8SVladimir Sementsov-Ogievskiy 
9956e2f1d8SVladimir Sementsov-Ogievskiy     /* best compression, small window, no zlib header */
10056e2f1d8SVladimir Sementsov-Ogievskiy     memset(&strm, 0, sizeof(strm));
10156e2f1d8SVladimir Sementsov-Ogievskiy     ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
10256e2f1d8SVladimir Sementsov-Ogievskiy                        -12, 9, Z_DEFAULT_STRATEGY);
10356e2f1d8SVladimir Sementsov-Ogievskiy     if (ret != Z_OK) {
10456e2f1d8SVladimir Sementsov-Ogievskiy         return -EIO;
10556e2f1d8SVladimir Sementsov-Ogievskiy     }
10656e2f1d8SVladimir Sementsov-Ogievskiy 
10756e2f1d8SVladimir Sementsov-Ogievskiy     /*
10856e2f1d8SVladimir Sementsov-Ogievskiy      * strm.next_in is not const in old zlib versions, such as those used on
10956e2f1d8SVladimir Sementsov-Ogievskiy      * OpenBSD/NetBSD, so cast the const away
11056e2f1d8SVladimir Sementsov-Ogievskiy      */
11156e2f1d8SVladimir Sementsov-Ogievskiy     strm.avail_in = src_size;
11256e2f1d8SVladimir Sementsov-Ogievskiy     strm.next_in = (void *) src;
11356e2f1d8SVladimir Sementsov-Ogievskiy     strm.avail_out = dest_size;
11456e2f1d8SVladimir Sementsov-Ogievskiy     strm.next_out = dest;
11556e2f1d8SVladimir Sementsov-Ogievskiy 
11656e2f1d8SVladimir Sementsov-Ogievskiy     ret = deflate(&strm, Z_FINISH);
11756e2f1d8SVladimir Sementsov-Ogievskiy     if (ret == Z_STREAM_END) {
11856e2f1d8SVladimir Sementsov-Ogievskiy         ret = dest_size - strm.avail_out;
11956e2f1d8SVladimir Sementsov-Ogievskiy     } else {
12056e2f1d8SVladimir Sementsov-Ogievskiy         ret = (ret == Z_OK ? -ENOMEM : -EIO);
12156e2f1d8SVladimir Sementsov-Ogievskiy     }
12256e2f1d8SVladimir Sementsov-Ogievskiy 
12356e2f1d8SVladimir Sementsov-Ogievskiy     deflateEnd(&strm);
12456e2f1d8SVladimir Sementsov-Ogievskiy 
12556e2f1d8SVladimir Sementsov-Ogievskiy     return ret;
12656e2f1d8SVladimir Sementsov-Ogievskiy }
12756e2f1d8SVladimir Sementsov-Ogievskiy 
12856e2f1d8SVladimir Sementsov-Ogievskiy /*
12925dd077dSDenis Plotnikov  * qcow2_zlib_decompress()
13056e2f1d8SVladimir Sementsov-Ogievskiy  *
13156e2f1d8SVladimir Sementsov-Ogievskiy  * Decompress some data (not more than @src_size bytes) to produce exactly
13225dd077dSDenis Plotnikov  * @dest_size bytes using zlib compression method
13356e2f1d8SVladimir Sementsov-Ogievskiy  *
13456e2f1d8SVladimir Sementsov-Ogievskiy  * @dest - destination buffer, @dest_size bytes
13556e2f1d8SVladimir Sementsov-Ogievskiy  * @src - source buffer, @src_size bytes
13656e2f1d8SVladimir Sementsov-Ogievskiy  *
13756e2f1d8SVladimir Sementsov-Ogievskiy  * Returns: 0 on success
138e7266570SVladimir Sementsov-Ogievskiy  *          -EIO on fail
13956e2f1d8SVladimir Sementsov-Ogievskiy  */
qcow2_zlib_decompress(void * dest,size_t dest_size,const void * src,size_t src_size)14025dd077dSDenis Plotnikov static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size,
14156e2f1d8SVladimir Sementsov-Ogievskiy                                      const void *src, size_t src_size)
14256e2f1d8SVladimir Sementsov-Ogievskiy {
143e7266570SVladimir Sementsov-Ogievskiy     int ret;
14456e2f1d8SVladimir Sementsov-Ogievskiy     z_stream strm;
14556e2f1d8SVladimir Sementsov-Ogievskiy 
14656e2f1d8SVladimir Sementsov-Ogievskiy     memset(&strm, 0, sizeof(strm));
14756e2f1d8SVladimir Sementsov-Ogievskiy     strm.avail_in = src_size;
14856e2f1d8SVladimir Sementsov-Ogievskiy     strm.next_in = (void *) src;
14956e2f1d8SVladimir Sementsov-Ogievskiy     strm.avail_out = dest_size;
15056e2f1d8SVladimir Sementsov-Ogievskiy     strm.next_out = dest;
15156e2f1d8SVladimir Sementsov-Ogievskiy 
15256e2f1d8SVladimir Sementsov-Ogievskiy     ret = inflateInit2(&strm, -12);
15356e2f1d8SVladimir Sementsov-Ogievskiy     if (ret != Z_OK) {
154e7266570SVladimir Sementsov-Ogievskiy         return -EIO;
15556e2f1d8SVladimir Sementsov-Ogievskiy     }
15656e2f1d8SVladimir Sementsov-Ogievskiy 
15756e2f1d8SVladimir Sementsov-Ogievskiy     ret = inflate(&strm, Z_FINISH);
158e7266570SVladimir Sementsov-Ogievskiy     if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
15956e2f1d8SVladimir Sementsov-Ogievskiy         /*
16056e2f1d8SVladimir Sementsov-Ogievskiy          * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
16156e2f1d8SVladimir Sementsov-Ogievskiy          * @src buffer may be processed partly (because in qcow2 we know size of
16256e2f1d8SVladimir Sementsov-Ogievskiy          * compressed data with precision of one sector)
16356e2f1d8SVladimir Sementsov-Ogievskiy          */
164e7266570SVladimir Sementsov-Ogievskiy         ret = 0;
165e7266570SVladimir Sementsov-Ogievskiy     } else {
166e7266570SVladimir Sementsov-Ogievskiy         ret = -EIO;
16756e2f1d8SVladimir Sementsov-Ogievskiy     }
16856e2f1d8SVladimir Sementsov-Ogievskiy 
16956e2f1d8SVladimir Sementsov-Ogievskiy     inflateEnd(&strm);
17056e2f1d8SVladimir Sementsov-Ogievskiy 
17156e2f1d8SVladimir Sementsov-Ogievskiy     return ret;
17256e2f1d8SVladimir Sementsov-Ogievskiy }
17356e2f1d8SVladimir Sementsov-Ogievskiy 
174d298ac10SDenis Plotnikov #ifdef CONFIG_ZSTD
175d298ac10SDenis Plotnikov 
176d298ac10SDenis Plotnikov /*
177d298ac10SDenis Plotnikov  * qcow2_zstd_compress()
178d298ac10SDenis Plotnikov  *
179d298ac10SDenis Plotnikov  * Compress @src_size bytes of data using zstd compression method
180d298ac10SDenis Plotnikov  *
181d298ac10SDenis Plotnikov  * @dest - destination buffer, @dest_size bytes
182d298ac10SDenis Plotnikov  * @src - source buffer, @src_size bytes
183d298ac10SDenis Plotnikov  *
184d298ac10SDenis Plotnikov  * Returns: compressed size on success
185d298ac10SDenis Plotnikov  *          -ENOMEM destination buffer is not enough to store compressed data
186d298ac10SDenis Plotnikov  *          -EIO    on any other error
187d298ac10SDenis Plotnikov  */
qcow2_zstd_compress(void * dest,size_t dest_size,const void * src,size_t src_size)188d298ac10SDenis Plotnikov static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size,
189d298ac10SDenis Plotnikov                                    const void *src, size_t src_size)
190d298ac10SDenis Plotnikov {
191d298ac10SDenis Plotnikov     ssize_t ret;
192d298ac10SDenis Plotnikov     size_t zstd_ret;
193d298ac10SDenis Plotnikov     ZSTD_outBuffer output = {
194d298ac10SDenis Plotnikov         .dst = dest,
195d298ac10SDenis Plotnikov         .size = dest_size,
196d298ac10SDenis Plotnikov         .pos = 0
197d298ac10SDenis Plotnikov     };
198d298ac10SDenis Plotnikov     ZSTD_inBuffer input = {
199d298ac10SDenis Plotnikov         .src = src,
200d298ac10SDenis Plotnikov         .size = src_size,
201d298ac10SDenis Plotnikov         .pos = 0
202d298ac10SDenis Plotnikov     };
203d298ac10SDenis Plotnikov     ZSTD_CCtx *cctx = ZSTD_createCCtx();
204d298ac10SDenis Plotnikov 
205d298ac10SDenis Plotnikov     if (!cctx) {
206d298ac10SDenis Plotnikov         return -EIO;
207d298ac10SDenis Plotnikov     }
208d298ac10SDenis Plotnikov     /*
209d298ac10SDenis Plotnikov      * Use the zstd streamed interface for symmetry with decompression,
210d298ac10SDenis Plotnikov      * where streaming is essential since we don't record the exact
211d298ac10SDenis Plotnikov      * compressed size.
212d298ac10SDenis Plotnikov      *
213d298ac10SDenis Plotnikov      * ZSTD_compressStream2() tries to compress everything it could
214d298ac10SDenis Plotnikov      * with a single call. Although, ZSTD docs says that:
215d298ac10SDenis Plotnikov      * "You must continue calling ZSTD_compressStream2() with ZSTD_e_end
216d298ac10SDenis Plotnikov      * until it returns 0, at which point you are free to start a new frame",
217d298ac10SDenis Plotnikov      * in out tests we saw the only case when it returned with >0 -
218d298ac10SDenis Plotnikov      * when the output buffer was too small. In that case,
219d298ac10SDenis Plotnikov      * ZSTD_compressStream2() expects a bigger buffer on the next call.
220d298ac10SDenis Plotnikov      * We can't provide a bigger buffer because we are limited with dest_size
221d298ac10SDenis Plotnikov      * which we pass to the ZSTD_compressStream2() at once.
222d298ac10SDenis Plotnikov      * So, we don't need any loops and just abort the compression when we
223d298ac10SDenis Plotnikov      * don't get 0 result on the first call.
224d298ac10SDenis Plotnikov      */
225d298ac10SDenis Plotnikov     zstd_ret = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
226d298ac10SDenis Plotnikov 
227d298ac10SDenis Plotnikov     if (zstd_ret) {
228d298ac10SDenis Plotnikov         if (zstd_ret > output.size - output.pos) {
229d298ac10SDenis Plotnikov             ret = -ENOMEM;
230d298ac10SDenis Plotnikov         } else {
231d298ac10SDenis Plotnikov             ret = -EIO;
232d298ac10SDenis Plotnikov         }
233d298ac10SDenis Plotnikov         goto out;
234d298ac10SDenis Plotnikov     }
235d298ac10SDenis Plotnikov 
236d298ac10SDenis Plotnikov     /* make sure that zstd didn't overflow the dest buffer */
237d298ac10SDenis Plotnikov     assert(output.pos <= dest_size);
238d298ac10SDenis Plotnikov     ret = output.pos;
239d298ac10SDenis Plotnikov out:
240d298ac10SDenis Plotnikov     ZSTD_freeCCtx(cctx);
241d298ac10SDenis Plotnikov     return ret;
242d298ac10SDenis Plotnikov }
243d298ac10SDenis Plotnikov 
244d298ac10SDenis Plotnikov /*
245d298ac10SDenis Plotnikov  * qcow2_zstd_decompress()
246d298ac10SDenis Plotnikov  *
247d298ac10SDenis Plotnikov  * Decompress some data (not more than @src_size bytes) to produce exactly
248d298ac10SDenis Plotnikov  * @dest_size bytes using zstd compression method
249d298ac10SDenis Plotnikov  *
250d298ac10SDenis Plotnikov  * @dest - destination buffer, @dest_size bytes
251d298ac10SDenis Plotnikov  * @src - source buffer, @src_size bytes
252d298ac10SDenis Plotnikov  *
253d298ac10SDenis Plotnikov  * Returns: 0 on success
254d298ac10SDenis Plotnikov  *          -EIO on any error
255d298ac10SDenis Plotnikov  */
qcow2_zstd_decompress(void * dest,size_t dest_size,const void * src,size_t src_size)256d298ac10SDenis Plotnikov static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size,
257d298ac10SDenis Plotnikov                                      const void *src, size_t src_size)
258d298ac10SDenis Plotnikov {
259d298ac10SDenis Plotnikov     size_t zstd_ret = 0;
260d298ac10SDenis Plotnikov     ssize_t ret = 0;
261d298ac10SDenis Plotnikov     ZSTD_outBuffer output = {
262d298ac10SDenis Plotnikov         .dst = dest,
263d298ac10SDenis Plotnikov         .size = dest_size,
264d298ac10SDenis Plotnikov         .pos = 0
265d298ac10SDenis Plotnikov     };
266d298ac10SDenis Plotnikov     ZSTD_inBuffer input = {
267d298ac10SDenis Plotnikov         .src = src,
268d298ac10SDenis Plotnikov         .size = src_size,
269d298ac10SDenis Plotnikov         .pos = 0
270d298ac10SDenis Plotnikov     };
271d298ac10SDenis Plotnikov     ZSTD_DCtx *dctx = ZSTD_createDCtx();
272d298ac10SDenis Plotnikov 
273d298ac10SDenis Plotnikov     if (!dctx) {
274d298ac10SDenis Plotnikov         return -EIO;
275d298ac10SDenis Plotnikov     }
276d298ac10SDenis Plotnikov 
277d298ac10SDenis Plotnikov     /*
278d298ac10SDenis Plotnikov      * The compressed stream from the input buffer may consist of more
279d298ac10SDenis Plotnikov      * than one zstd frame. So we iterate until we get a fully
280d298ac10SDenis Plotnikov      * uncompressed cluster.
281d298ac10SDenis Plotnikov      * From zstd docs related to ZSTD_decompressStream:
282d298ac10SDenis Plotnikov      * "return : 0 when a frame is completely decoded and fully flushed"
283d298ac10SDenis Plotnikov      * We suppose that this means: each time ZSTD_decompressStream reads
284d298ac10SDenis Plotnikov      * only ONE full frame and returns 0 if and only if that frame
285d298ac10SDenis Plotnikov      * is completely decoded and flushed. Only after returning 0,
286d298ac10SDenis Plotnikov      * ZSTD_decompressStream reads another ONE full frame.
287d298ac10SDenis Plotnikov      */
288d298ac10SDenis Plotnikov     while (output.pos < output.size) {
289d298ac10SDenis Plotnikov         size_t last_in_pos = input.pos;
290d298ac10SDenis Plotnikov         size_t last_out_pos = output.pos;
291d298ac10SDenis Plotnikov         zstd_ret = ZSTD_decompressStream(dctx, &output, &input);
292d298ac10SDenis Plotnikov 
293d298ac10SDenis Plotnikov         if (ZSTD_isError(zstd_ret)) {
294d298ac10SDenis Plotnikov             ret = -EIO;
295d298ac10SDenis Plotnikov             break;
296d298ac10SDenis Plotnikov         }
297d298ac10SDenis Plotnikov 
298d298ac10SDenis Plotnikov         /*
299d298ac10SDenis Plotnikov          * The ZSTD manual is vague about what to do if it reads
300d298ac10SDenis Plotnikov          * the buffer partially, and we don't want to get stuck
301d298ac10SDenis Plotnikov          * in an infinite loop where ZSTD_decompressStream
302d298ac10SDenis Plotnikov          * returns > 0 waiting for another input chunk. So, we add
303d298ac10SDenis Plotnikov          * a check which ensures that the loop makes some progress
304d298ac10SDenis Plotnikov          * on each step.
305d298ac10SDenis Plotnikov          */
306d298ac10SDenis Plotnikov         if (last_in_pos >= input.pos &&
307d298ac10SDenis Plotnikov             last_out_pos >= output.pos) {
308d298ac10SDenis Plotnikov             ret = -EIO;
309d298ac10SDenis Plotnikov             break;
310d298ac10SDenis Plotnikov         }
311d298ac10SDenis Plotnikov     }
312d298ac10SDenis Plotnikov     /*
313d298ac10SDenis Plotnikov      * Make sure that we have the frame fully flushed here
314d298ac10SDenis Plotnikov      * if not, we somehow managed to get uncompressed cluster
315d298ac10SDenis Plotnikov      * greater then the cluster size, possibly because of its
316d298ac10SDenis Plotnikov      * damage.
317d298ac10SDenis Plotnikov      */
318d298ac10SDenis Plotnikov     if (zstd_ret > 0) {
319d298ac10SDenis Plotnikov         ret = -EIO;
320d298ac10SDenis Plotnikov     }
321d298ac10SDenis Plotnikov 
322d298ac10SDenis Plotnikov     ZSTD_freeDCtx(dctx);
323d298ac10SDenis Plotnikov     assert(ret == 0 || ret == -EIO);
324d298ac10SDenis Plotnikov     return ret;
325d298ac10SDenis Plotnikov }
326d298ac10SDenis Plotnikov #endif
327d298ac10SDenis Plotnikov 
qcow2_compress_pool_func(void * opaque)32856e2f1d8SVladimir Sementsov-Ogievskiy static int qcow2_compress_pool_func(void *opaque)
32956e2f1d8SVladimir Sementsov-Ogievskiy {
33056e2f1d8SVladimir Sementsov-Ogievskiy     Qcow2CompressData *data = opaque;
33156e2f1d8SVladimir Sementsov-Ogievskiy 
33256e2f1d8SVladimir Sementsov-Ogievskiy     data->ret = data->func(data->dest, data->dest_size,
33356e2f1d8SVladimir Sementsov-Ogievskiy                            data->src, data->src_size);
33456e2f1d8SVladimir Sementsov-Ogievskiy 
33556e2f1d8SVladimir Sementsov-Ogievskiy     return 0;
33656e2f1d8SVladimir Sementsov-Ogievskiy }
33756e2f1d8SVladimir Sementsov-Ogievskiy 
33856e2f1d8SVladimir Sementsov-Ogievskiy static ssize_t coroutine_fn
qcow2_co_do_compress(BlockDriverState * bs,void * dest,size_t dest_size,const void * src,size_t src_size,Qcow2CompressFunc func)33956e2f1d8SVladimir Sementsov-Ogievskiy qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
34056e2f1d8SVladimir Sementsov-Ogievskiy                      const void *src, size_t src_size, Qcow2CompressFunc func)
34156e2f1d8SVladimir Sementsov-Ogievskiy {
34256e2f1d8SVladimir Sementsov-Ogievskiy     Qcow2CompressData arg = {
34356e2f1d8SVladimir Sementsov-Ogievskiy         .dest = dest,
34456e2f1d8SVladimir Sementsov-Ogievskiy         .dest_size = dest_size,
34556e2f1d8SVladimir Sementsov-Ogievskiy         .src = src,
34656e2f1d8SVladimir Sementsov-Ogievskiy         .src_size = src_size,
34756e2f1d8SVladimir Sementsov-Ogievskiy         .func = func,
34856e2f1d8SVladimir Sementsov-Ogievskiy     };
34956e2f1d8SVladimir Sementsov-Ogievskiy 
3506f13a316SVladimir Sementsov-Ogievskiy     qcow2_co_process(bs, qcow2_compress_pool_func, &arg);
35156e2f1d8SVladimir Sementsov-Ogievskiy 
35256e2f1d8SVladimir Sementsov-Ogievskiy     return arg.ret;
35356e2f1d8SVladimir Sementsov-Ogievskiy }
35456e2f1d8SVladimir Sementsov-Ogievskiy 
35525dd077dSDenis Plotnikov /*
35625dd077dSDenis Plotnikov  * qcow2_co_compress()
35725dd077dSDenis Plotnikov  *
35825dd077dSDenis Plotnikov  * Compress @src_size bytes of data using the compression
35925dd077dSDenis Plotnikov  * method defined by the image compression type
36025dd077dSDenis Plotnikov  *
36125dd077dSDenis Plotnikov  * @dest - destination buffer, @dest_size bytes
36225dd077dSDenis Plotnikov  * @src - source buffer, @src_size bytes
36325dd077dSDenis Plotnikov  *
36425dd077dSDenis Plotnikov  * Returns: compressed size on success
36525dd077dSDenis Plotnikov  *          a negative error code on failure
36625dd077dSDenis Plotnikov  */
36756e2f1d8SVladimir Sementsov-Ogievskiy ssize_t coroutine_fn
qcow2_co_compress(BlockDriverState * bs,void * dest,size_t dest_size,const void * src,size_t src_size)36856e2f1d8SVladimir Sementsov-Ogievskiy qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
36956e2f1d8SVladimir Sementsov-Ogievskiy                   const void *src, size_t src_size)
37056e2f1d8SVladimir Sementsov-Ogievskiy {
37125dd077dSDenis Plotnikov     BDRVQcow2State *s = bs->opaque;
37225dd077dSDenis Plotnikov     Qcow2CompressFunc fn;
37325dd077dSDenis Plotnikov 
37425dd077dSDenis Plotnikov     switch (s->compression_type) {
37525dd077dSDenis Plotnikov     case QCOW2_COMPRESSION_TYPE_ZLIB:
37625dd077dSDenis Plotnikov         fn = qcow2_zlib_compress;
37725dd077dSDenis Plotnikov         break;
37825dd077dSDenis Plotnikov 
379d298ac10SDenis Plotnikov #ifdef CONFIG_ZSTD
380d298ac10SDenis Plotnikov     case QCOW2_COMPRESSION_TYPE_ZSTD:
381d298ac10SDenis Plotnikov         fn = qcow2_zstd_compress;
382d298ac10SDenis Plotnikov         break;
383d298ac10SDenis Plotnikov #endif
38425dd077dSDenis Plotnikov     default:
38525dd077dSDenis Plotnikov         abort();
38656e2f1d8SVladimir Sementsov-Ogievskiy     }
38756e2f1d8SVladimir Sementsov-Ogievskiy 
38825dd077dSDenis Plotnikov     return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
38925dd077dSDenis Plotnikov }
39025dd077dSDenis Plotnikov 
39125dd077dSDenis Plotnikov /*
39225dd077dSDenis Plotnikov  * qcow2_co_decompress()
39325dd077dSDenis Plotnikov  *
39425dd077dSDenis Plotnikov  * Decompress some data (not more than @src_size bytes) to produce exactly
39525dd077dSDenis Plotnikov  * @dest_size bytes using the compression method defined by the image
39625dd077dSDenis Plotnikov  * compression type
39725dd077dSDenis Plotnikov  *
39825dd077dSDenis Plotnikov  * @dest - destination buffer, @dest_size bytes
39925dd077dSDenis Plotnikov  * @src - source buffer, @src_size bytes
40025dd077dSDenis Plotnikov  *
40125dd077dSDenis Plotnikov  * Returns: 0 on success
40225dd077dSDenis Plotnikov  *          a negative error code on failure
40325dd077dSDenis Plotnikov  */
40456e2f1d8SVladimir Sementsov-Ogievskiy ssize_t coroutine_fn
qcow2_co_decompress(BlockDriverState * bs,void * dest,size_t dest_size,const void * src,size_t src_size)40556e2f1d8SVladimir Sementsov-Ogievskiy qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
40656e2f1d8SVladimir Sementsov-Ogievskiy                     const void *src, size_t src_size)
40756e2f1d8SVladimir Sementsov-Ogievskiy {
40825dd077dSDenis Plotnikov     BDRVQcow2State *s = bs->opaque;
40925dd077dSDenis Plotnikov     Qcow2CompressFunc fn;
41025dd077dSDenis Plotnikov 
41125dd077dSDenis Plotnikov     switch (s->compression_type) {
41225dd077dSDenis Plotnikov     case QCOW2_COMPRESSION_TYPE_ZLIB:
41325dd077dSDenis Plotnikov         fn = qcow2_zlib_decompress;
41425dd077dSDenis Plotnikov         break;
41525dd077dSDenis Plotnikov 
416d298ac10SDenis Plotnikov #ifdef CONFIG_ZSTD
417d298ac10SDenis Plotnikov     case QCOW2_COMPRESSION_TYPE_ZSTD:
418d298ac10SDenis Plotnikov         fn = qcow2_zstd_decompress;
419d298ac10SDenis Plotnikov         break;
420d298ac10SDenis Plotnikov #endif
42125dd077dSDenis Plotnikov     default:
42225dd077dSDenis Plotnikov         abort();
42325dd077dSDenis Plotnikov     }
42425dd077dSDenis Plotnikov 
42525dd077dSDenis Plotnikov     return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, fn);
42656e2f1d8SVladimir Sementsov-Ogievskiy }
4278ac0f15fSVladimir Sementsov-Ogievskiy 
4288ac0f15fSVladimir Sementsov-Ogievskiy 
4298ac0f15fSVladimir Sementsov-Ogievskiy /*
4308ac0f15fSVladimir Sementsov-Ogievskiy  * Cryptography
4318ac0f15fSVladimir Sementsov-Ogievskiy  */
4328ac0f15fSVladimir Sementsov-Ogievskiy 
4338ac0f15fSVladimir Sementsov-Ogievskiy /*
4348ac0f15fSVladimir Sementsov-Ogievskiy  * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
4358ac0f15fSVladimir Sementsov-Ogievskiy  * qcrypto_block_decrypt() functions.
4368ac0f15fSVladimir Sementsov-Ogievskiy  */
4378ac0f15fSVladimir Sementsov-Ogievskiy typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
4388ac0f15fSVladimir Sementsov-Ogievskiy                                uint8_t *buf, size_t len, Error **errp);
4398ac0f15fSVladimir Sementsov-Ogievskiy 
4408ac0f15fSVladimir Sementsov-Ogievskiy typedef struct Qcow2EncDecData {
4418ac0f15fSVladimir Sementsov-Ogievskiy     QCryptoBlock *block;
4428ac0f15fSVladimir Sementsov-Ogievskiy     uint64_t offset;
4438ac0f15fSVladimir Sementsov-Ogievskiy     uint8_t *buf;
4448ac0f15fSVladimir Sementsov-Ogievskiy     size_t len;
4458ac0f15fSVladimir Sementsov-Ogievskiy 
4468ac0f15fSVladimir Sementsov-Ogievskiy     Qcow2EncDecFunc func;
4478ac0f15fSVladimir Sementsov-Ogievskiy } Qcow2EncDecData;
4488ac0f15fSVladimir Sementsov-Ogievskiy 
qcow2_encdec_pool_func(void * opaque)4498ac0f15fSVladimir Sementsov-Ogievskiy static int qcow2_encdec_pool_func(void *opaque)
4508ac0f15fSVladimir Sementsov-Ogievskiy {
4518ac0f15fSVladimir Sementsov-Ogievskiy     Qcow2EncDecData *data = opaque;
4528ac0f15fSVladimir Sementsov-Ogievskiy 
4538ac0f15fSVladimir Sementsov-Ogievskiy     return data->func(data->block, data->offset, data->buf, data->len, NULL);
4548ac0f15fSVladimir Sementsov-Ogievskiy }
4558ac0f15fSVladimir Sementsov-Ogievskiy 
4568ac0f15fSVladimir Sementsov-Ogievskiy static int coroutine_fn
qcow2_co_encdec(BlockDriverState * bs,uint64_t host_offset,uint64_t guest_offset,void * buf,size_t len,Qcow2EncDecFunc func)457603fbd07SMaxim Levitsky qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
458603fbd07SMaxim Levitsky                 uint64_t guest_offset, void *buf, size_t len,
459603fbd07SMaxim Levitsky                 Qcow2EncDecFunc func)
4608ac0f15fSVladimir Sementsov-Ogievskiy {
4618ac0f15fSVladimir Sementsov-Ogievskiy     BDRVQcow2State *s = bs->opaque;
4628ac0f15fSVladimir Sementsov-Ogievskiy     Qcow2EncDecData arg = {
4638ac0f15fSVladimir Sementsov-Ogievskiy         .block = s->crypto,
464603fbd07SMaxim Levitsky         .offset = s->crypt_physical_offset ? host_offset : guest_offset,
4658ac0f15fSVladimir Sementsov-Ogievskiy         .buf = buf,
4668ac0f15fSVladimir Sementsov-Ogievskiy         .len = len,
4678ac0f15fSVladimir Sementsov-Ogievskiy         .func = func,
4688ac0f15fSVladimir Sementsov-Ogievskiy     };
4692d4b5256SAlberto Garcia     uint64_t sector_size;
4708ac0f15fSVladimir Sementsov-Ogievskiy 
471603fbd07SMaxim Levitsky     assert(s->crypto);
472603fbd07SMaxim Levitsky 
4732d4b5256SAlberto Garcia     sector_size = qcrypto_block_get_sector_size(s->crypto);
4742d4b5256SAlberto Garcia     assert(QEMU_IS_ALIGNED(guest_offset, sector_size));
4752d4b5256SAlberto Garcia     assert(QEMU_IS_ALIGNED(host_offset, sector_size));
4762d4b5256SAlberto Garcia     assert(QEMU_IS_ALIGNED(len, sector_size));
4772d4b5256SAlberto Garcia 
478603fbd07SMaxim Levitsky     return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
4798ac0f15fSVladimir Sementsov-Ogievskiy }
4808ac0f15fSVladimir Sementsov-Ogievskiy 
481603fbd07SMaxim Levitsky /*
482603fbd07SMaxim Levitsky  * qcow2_co_encrypt()
483603fbd07SMaxim Levitsky  *
484603fbd07SMaxim Levitsky  * Encrypts one or more contiguous aligned sectors
485603fbd07SMaxim Levitsky  *
486603fbd07SMaxim Levitsky  * @host_offset - underlying storage offset of the first sector of the
487603fbd07SMaxim Levitsky  * data to be encrypted
488603fbd07SMaxim Levitsky  *
489603fbd07SMaxim Levitsky  * @guest_offset - guest (virtual) offset of the first sector of the
490603fbd07SMaxim Levitsky  * data to be encrypted
491603fbd07SMaxim Levitsky  *
492603fbd07SMaxim Levitsky  * @buf - buffer with the data to encrypt, that after encryption
493603fbd07SMaxim Levitsky  *        will be written to the underlying storage device at
494603fbd07SMaxim Levitsky  *        @host_offset
495603fbd07SMaxim Levitsky  *
4962d4b5256SAlberto Garcia  * @len - length of the buffer (must be a multiple of the encryption
4972d4b5256SAlberto Garcia  *        sector size)
498603fbd07SMaxim Levitsky  *
499603fbd07SMaxim Levitsky  * Depending on the encryption method, @host_offset and/or @guest_offset
500603fbd07SMaxim Levitsky  * may be used for generating the initialization vector for
501603fbd07SMaxim Levitsky  * encryption.
502603fbd07SMaxim Levitsky  *
503603fbd07SMaxim Levitsky  * Note that while the whole range must be aligned on sectors, it
504603fbd07SMaxim Levitsky  * does not have to be aligned on clusters and can also cross cluster
505603fbd07SMaxim Levitsky  * boundaries
506603fbd07SMaxim Levitsky  */
5078ac0f15fSVladimir Sementsov-Ogievskiy int coroutine_fn
qcow2_co_encrypt(BlockDriverState * bs,uint64_t host_offset,uint64_t guest_offset,void * buf,size_t len)508603fbd07SMaxim Levitsky qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset,
509603fbd07SMaxim Levitsky                  uint64_t guest_offset, void *buf, size_t len)
5108ac0f15fSVladimir Sementsov-Ogievskiy {
511603fbd07SMaxim Levitsky     return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
5128ac0f15fSVladimir Sementsov-Ogievskiy                            qcrypto_block_encrypt);
5138ac0f15fSVladimir Sementsov-Ogievskiy }
5148ac0f15fSVladimir Sementsov-Ogievskiy 
515603fbd07SMaxim Levitsky /*
516603fbd07SMaxim Levitsky  * qcow2_co_decrypt()
517603fbd07SMaxim Levitsky  *
518603fbd07SMaxim Levitsky  * Decrypts one or more contiguous aligned sectors
519603fbd07SMaxim Levitsky  * Similar to qcow2_co_encrypt
520603fbd07SMaxim Levitsky  */
5218ac0f15fSVladimir Sementsov-Ogievskiy int coroutine_fn
qcow2_co_decrypt(BlockDriverState * bs,uint64_t host_offset,uint64_t guest_offset,void * buf,size_t len)522603fbd07SMaxim Levitsky qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset,
523603fbd07SMaxim Levitsky                  uint64_t guest_offset, void *buf, size_t len)
5248ac0f15fSVladimir Sementsov-Ogievskiy {
525603fbd07SMaxim Levitsky     return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
5268ac0f15fSVladimir Sementsov-Ogievskiy                            qcrypto_block_decrypt);
5278ac0f15fSVladimir Sementsov-Ogievskiy }
528