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 34 #define MAX_COMPRESS_THREADS 4 35 36 typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size, 37 const void *src, size_t src_size); 38 typedef struct Qcow2CompressData { 39 void *dest; 40 size_t dest_size; 41 const void *src; 42 size_t src_size; 43 ssize_t ret; 44 45 Qcow2CompressFunc func; 46 } Qcow2CompressData; 47 48 /* 49 * qcow2_compress() 50 * 51 * @dest - destination buffer, @dest_size bytes 52 * @src - source buffer, @src_size bytes 53 * 54 * Returns: compressed size on success 55 * -ENOMEM destination buffer is not enough to store compressed data 56 * -EIO on any other error 57 */ 58 static ssize_t qcow2_compress(void *dest, size_t dest_size, 59 const void *src, size_t src_size) 60 { 61 ssize_t ret; 62 z_stream strm; 63 64 /* best compression, small window, no zlib header */ 65 memset(&strm, 0, sizeof(strm)); 66 ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 67 -12, 9, Z_DEFAULT_STRATEGY); 68 if (ret != Z_OK) { 69 return -EIO; 70 } 71 72 /* 73 * strm.next_in is not const in old zlib versions, such as those used on 74 * OpenBSD/NetBSD, so cast the const away 75 */ 76 strm.avail_in = src_size; 77 strm.next_in = (void *) src; 78 strm.avail_out = dest_size; 79 strm.next_out = dest; 80 81 ret = deflate(&strm, Z_FINISH); 82 if (ret == Z_STREAM_END) { 83 ret = dest_size - strm.avail_out; 84 } else { 85 ret = (ret == Z_OK ? -ENOMEM : -EIO); 86 } 87 88 deflateEnd(&strm); 89 90 return ret; 91 } 92 93 /* 94 * qcow2_decompress() 95 * 96 * Decompress some data (not more than @src_size bytes) to produce exactly 97 * @dest_size bytes. 98 * 99 * @dest - destination buffer, @dest_size bytes 100 * @src - source buffer, @src_size bytes 101 * 102 * Returns: 0 on success 103 * -1 on fail 104 */ 105 static ssize_t qcow2_decompress(void *dest, size_t dest_size, 106 const void *src, size_t src_size) 107 { 108 int ret = 0; 109 z_stream strm; 110 111 memset(&strm, 0, sizeof(strm)); 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 = inflateInit2(&strm, -12); 118 if (ret != Z_OK) { 119 return -1; 120 } 121 122 ret = inflate(&strm, Z_FINISH); 123 if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) { 124 /* 125 * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but 126 * @src buffer may be processed partly (because in qcow2 we know size of 127 * compressed data with precision of one sector) 128 */ 129 ret = -1; 130 } 131 132 inflateEnd(&strm); 133 134 return ret; 135 } 136 137 static int qcow2_compress_pool_func(void *opaque) 138 { 139 Qcow2CompressData *data = opaque; 140 141 data->ret = data->func(data->dest, data->dest_size, 142 data->src, data->src_size); 143 144 return 0; 145 } 146 147 static ssize_t coroutine_fn 148 qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size, 149 const void *src, size_t src_size, Qcow2CompressFunc func) 150 { 151 BDRVQcow2State *s = bs->opaque; 152 ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); 153 Qcow2CompressData arg = { 154 .dest = dest, 155 .dest_size = dest_size, 156 .src = src, 157 .src_size = src_size, 158 .func = func, 159 }; 160 161 qemu_co_mutex_lock(&s->lock); 162 while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) { 163 qemu_co_queue_wait(&s->compress_wait_queue, &s->lock); 164 } 165 s->nb_compress_threads++; 166 qemu_co_mutex_unlock(&s->lock); 167 168 thread_pool_submit_co(pool, qcow2_compress_pool_func, &arg); 169 170 qemu_co_mutex_lock(&s->lock); 171 s->nb_compress_threads--; 172 qemu_co_queue_next(&s->compress_wait_queue); 173 qemu_co_mutex_unlock(&s->lock); 174 175 return arg.ret; 176 } 177 178 ssize_t coroutine_fn 179 qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size, 180 const void *src, size_t src_size) 181 { 182 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, 183 qcow2_compress); 184 } 185 186 ssize_t coroutine_fn 187 qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size, 188 const void *src, size_t src_size) 189 { 190 return qcow2_co_do_compress(bs, dest, dest_size, src, src_size, 191 qcow2_decompress); 192 } 193