]> git.proxmox.com Git - mirror_qemu.git/blame - block/qcow2-threads.c
Merge branch 'exec_rw_const_v4' of https://github.com/philmd/qemu into HEAD
[mirror_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/*
77 * qcow2_compress()
78 *
79 * @dest - destination buffer, @dest_size bytes
80 * @src - source buffer, @src_size bytes
81 *
82 * Returns: compressed size on success
83 * -ENOMEM destination buffer is not enough to store compressed data
84 * -EIO on any other error
85 */
86static ssize_t qcow2_compress(void *dest, size_t dest_size,
87 const void *src, size_t src_size)
88{
89 ssize_t ret;
90 z_stream strm;
91
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);
96 if (ret != Z_OK) {
97 return -EIO;
98 }
99
100 /*
101 * strm.next_in is not const in old zlib versions, such as those used on
102 * OpenBSD/NetBSD, so cast the const away
103 */
104 strm.avail_in = src_size;
105 strm.next_in = (void *) src;
106 strm.avail_out = dest_size;
107 strm.next_out = dest;
108
109 ret = deflate(&strm, Z_FINISH);
110 if (ret == Z_STREAM_END) {
111 ret = dest_size - strm.avail_out;
112 } else {
113 ret = (ret == Z_OK ? -ENOMEM : -EIO);
114 }
115
116 deflateEnd(&strm);
117
118 return ret;
119}
120
121/*
122 * qcow2_decompress()
123 *
124 * Decompress some data (not more than @src_size bytes) to produce exactly
125 * @dest_size bytes.
126 *
127 * @dest - destination buffer, @dest_size bytes
128 * @src - source buffer, @src_size bytes
129 *
130 * Returns: 0 on success
131 * -1 on fail
132 */
133static ssize_t qcow2_decompress(void *dest, size_t dest_size,
134 const void *src, size_t src_size)
135{
136 int ret = 0;
137 z_stream strm;
138
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;
144
145 ret = inflateInit2(&strm, -12);
146 if (ret != Z_OK) {
147 return -1;
148 }
149
150 ret = inflate(&strm, Z_FINISH);
151 if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
152 /*
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)
156 */
157 ret = -1;
158 }
159
160 inflateEnd(&strm);
161
162 return ret;
163}
164
165static int qcow2_compress_pool_func(void *opaque)
166{
167 Qcow2CompressData *data = opaque;
168
169 data->ret = data->func(data->dest, data->dest_size,
170 data->src, data->src_size);
171
172 return 0;
173}
174
56e2f1d8
VSO
175static ssize_t coroutine_fn
176qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
177 const void *src, size_t src_size, Qcow2CompressFunc func)
178{
56e2f1d8
VSO
179 Qcow2CompressData arg = {
180 .dest = dest,
181 .dest_size = dest_size,
182 .src = src,
183 .src_size = src_size,
184 .func = func,
185 };
186
6f13a316 187 qcow2_co_process(bs, qcow2_compress_pool_func, &arg);
56e2f1d8
VSO
188
189 return arg.ret;
190}
191
192ssize_t coroutine_fn
193qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
194 const void *src, size_t src_size)
195{
196 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
197 qcow2_compress);
198}
199
200ssize_t coroutine_fn
201qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
202 const void *src, size_t src_size)
203{
204 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
205 qcow2_decompress);
206}
8ac0f15f
VSO
207
208
209/*
210 * Cryptography
211 */
212
213/*
214 * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
215 * qcrypto_block_decrypt() functions.
216 */
217typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
218 uint8_t *buf, size_t len, Error **errp);
219
220typedef struct Qcow2EncDecData {
221 QCryptoBlock *block;
222 uint64_t offset;
223 uint8_t *buf;
224 size_t len;
225
226 Qcow2EncDecFunc func;
227} Qcow2EncDecData;
228
229static int qcow2_encdec_pool_func(void *opaque)
230{
231 Qcow2EncDecData *data = opaque;
232
233 return data->func(data->block, data->offset, data->buf, data->len, NULL);
234}
235
236static int coroutine_fn
603fbd07
ML
237qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
238 uint64_t guest_offset, void *buf, size_t len,
239 Qcow2EncDecFunc func)
8ac0f15f
VSO
240{
241 BDRVQcow2State *s = bs->opaque;
242 Qcow2EncDecData arg = {
243 .block = s->crypto,
603fbd07 244 .offset = s->crypt_physical_offset ? host_offset : guest_offset,
8ac0f15f
VSO
245 .buf = buf,
246 .len = len,
247 .func = func,
248 };
2d4b5256 249 uint64_t sector_size;
8ac0f15f 250
603fbd07
ML
251 assert(s->crypto);
252
2d4b5256
AG
253 sector_size = qcrypto_block_get_sector_size(s->crypto);
254 assert(QEMU_IS_ALIGNED(guest_offset, sector_size));
255 assert(QEMU_IS_ALIGNED(host_offset, sector_size));
256 assert(QEMU_IS_ALIGNED(len, sector_size));
257
603fbd07 258 return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
8ac0f15f
VSO
259}
260
603fbd07
ML
261/*
262 * qcow2_co_encrypt()
263 *
264 * Encrypts one or more contiguous aligned sectors
265 *
266 * @host_offset - underlying storage offset of the first sector of the
267 * data to be encrypted
268 *
269 * @guest_offset - guest (virtual) offset of the first sector of the
270 * data to be encrypted
271 *
272 * @buf - buffer with the data to encrypt, that after encryption
273 * will be written to the underlying storage device at
274 * @host_offset
275 *
2d4b5256
AG
276 * @len - length of the buffer (must be a multiple of the encryption
277 * sector size)
603fbd07
ML
278 *
279 * Depending on the encryption method, @host_offset and/or @guest_offset
280 * may be used for generating the initialization vector for
281 * encryption.
282 *
283 * Note that while the whole range must be aligned on sectors, it
284 * does not have to be aligned on clusters and can also cross cluster
285 * boundaries
286 */
8ac0f15f 287int coroutine_fn
603fbd07
ML
288qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset,
289 uint64_t guest_offset, void *buf, size_t len)
8ac0f15f 290{
603fbd07
ML
291 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
292 qcrypto_block_encrypt);
8ac0f15f
VSO
293}
294
603fbd07
ML
295/*
296 * qcow2_co_decrypt()
297 *
298 * Decrypts one or more contiguous aligned sectors
299 * Similar to qcow2_co_encrypt
300 */
8ac0f15f 301int coroutine_fn
603fbd07
ML
302qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset,
303 uint64_t guest_offset, void *buf, size_t len)
8ac0f15f 304{
603fbd07
ML
305 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
306 qcrypto_block_decrypt);
8ac0f15f 307}