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#include "qcow2.h"
32#include "block/thread-pool.h"
33#include "crypto.h"
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
62
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
78
79
80
81
82
83
84
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
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
102
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
123
124
125
126
127
128
129
130
131
132
133static ssize_t qcow2_decompress(void *dest, size_t dest_size,
134 const void *src, size_t src_size)
135{
136 int ret;
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 -EIO;
148 }
149
150 ret = inflate(&strm, Z_FINISH);
151 if ((ret == Z_STREAM_END || ret == Z_BUF_ERROR) && strm.avail_out == 0) {
152
153
154
155
156
157 ret = 0;
158 } else {
159 ret = -EIO;
160 }
161
162 inflateEnd(&strm);
163
164 return ret;
165}
166
167static int qcow2_compress_pool_func(void *opaque)
168{
169 Qcow2CompressData *data = opaque;
170
171 data->ret = data->func(data->dest, data->dest_size,
172 data->src, data->src_size);
173
174 return 0;
175}
176
177static ssize_t coroutine_fn
178qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
179 const void *src, size_t src_size, Qcow2CompressFunc func)
180{
181 Qcow2CompressData arg = {
182 .dest = dest,
183 .dest_size = dest_size,
184 .src = src,
185 .src_size = src_size,
186 .func = func,
187 };
188
189 qcow2_co_process(bs, qcow2_compress_pool_func, &arg);
190
191 return arg.ret;
192}
193
194ssize_t coroutine_fn
195qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
196 const void *src, size_t src_size)
197{
198 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
199 qcow2_compress);
200}
201
202ssize_t coroutine_fn
203qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
204 const void *src, size_t src_size)
205{
206 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
207 qcow2_decompress);
208}
209
210
211
212
213
214
215
216
217
218
219typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
220 uint8_t *buf, size_t len, Error **errp);
221
222typedef struct Qcow2EncDecData {
223 QCryptoBlock *block;
224 uint64_t offset;
225 uint8_t *buf;
226 size_t len;
227
228 Qcow2EncDecFunc func;
229} Qcow2EncDecData;
230
231static int qcow2_encdec_pool_func(void *opaque)
232{
233 Qcow2EncDecData *data = opaque;
234
235 return data->func(data->block, data->offset, data->buf, data->len, NULL);
236}
237
238static int coroutine_fn
239qcow2_co_encdec(BlockDriverState *bs, uint64_t host_offset,
240 uint64_t guest_offset, void *buf, size_t len,
241 Qcow2EncDecFunc func)
242{
243 BDRVQcow2State *s = bs->opaque;
244 Qcow2EncDecData arg = {
245 .block = s->crypto,
246 .offset = s->crypt_physical_offset ? host_offset : guest_offset,
247 .buf = buf,
248 .len = len,
249 .func = func,
250 };
251 uint64_t sector_size;
252
253 assert(s->crypto);
254
255 sector_size = qcrypto_block_get_sector_size(s->crypto);
256 assert(QEMU_IS_ALIGNED(guest_offset, sector_size));
257 assert(QEMU_IS_ALIGNED(host_offset, sector_size));
258 assert(QEMU_IS_ALIGNED(len, sector_size));
259
260 return len == 0 ? 0 : qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
261}
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289int coroutine_fn
290qcow2_co_encrypt(BlockDriverState *bs, uint64_t host_offset,
291 uint64_t guest_offset, void *buf, size_t len)
292{
293 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
294 qcrypto_block_encrypt);
295}
296
297
298
299
300
301
302
303int coroutine_fn
304qcow2_co_decrypt(BlockDriverState *bs, uint64_t host_offset,
305 uint64_t guest_offset, void *buf, size_t len)
306{
307 return qcow2_co_encdec(bs, host_offset, guest_offset, buf, len,
308 qcrypto_block_decrypt);
309}
310