xref: /openbmc/qemu/block/qcow2-threads.c (revision ed5abf46)
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"
33 #include "crypto.h"
34 
35 static int coroutine_fn
36 qcow2_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  */
63 
64 typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
65                                      const void *src, size_t src_size);
66 typedef 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  */
86 static 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  *          -EIO on fail
132  */
133 static 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          * 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 = 0;
158     } else {
159         ret = -EIO;
160     }
161 
162     inflateEnd(&strm);
163 
164     return ret;
165 }
166 
167 static 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 
177 static ssize_t coroutine_fn
178 qcow2_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 
194 ssize_t coroutine_fn
195 qcow2_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 
202 ssize_t coroutine_fn
203 qcow2_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  * Cryptography
213  */
214 
215 /*
216  * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
217  * qcrypto_block_decrypt() functions.
218  */
219 typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
220                                uint8_t *buf, size_t len, Error **errp);
221 
222 typedef struct Qcow2EncDecData {
223     QCryptoBlock *block;
224     uint64_t offset;
225     uint8_t *buf;
226     size_t len;
227 
228     Qcow2EncDecFunc func;
229 } Qcow2EncDecData;
230 
231 static 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 
238 static int coroutine_fn
239 qcow2_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  * qcow2_co_encrypt()
265  *
266  * Encrypts one or more contiguous aligned sectors
267  *
268  * @host_offset - underlying storage offset of the first sector of the
269  * data to be encrypted
270  *
271  * @guest_offset - guest (virtual) offset of the first sector of the
272  * data to be encrypted
273  *
274  * @buf - buffer with the data to encrypt, that after encryption
275  *        will be written to the underlying storage device at
276  *        @host_offset
277  *
278  * @len - length of the buffer (must be a multiple of the encryption
279  *        sector size)
280  *
281  * Depending on the encryption method, @host_offset and/or @guest_offset
282  * may be used for generating the initialization vector for
283  * encryption.
284  *
285  * Note that while the whole range must be aligned on sectors, it
286  * does not have to be aligned on clusters and can also cross cluster
287  * boundaries
288  */
289 int coroutine_fn
290 qcow2_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  * qcow2_co_decrypt()
299  *
300  * Decrypts one or more contiguous aligned sectors
301  * Similar to qcow2_co_encrypt
302  */
303 int coroutine_fn
304 qcow2_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