wok annotate qemu/stuff/cloop.u @ rev 23680

qemu: partial cloop v4 support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Apr 26 15:17:58 2020 +0000 (2020-04-26)
parents 74ce1799eee7
children f29529667ea4
rev   line source
pascal@23680 1 --- source/qemu-2.0.2/block/cloop.c 2014-08-18 18:03:24.000000000 +0200
pascal@23680 2 +++ cloop.c 2020-04-26 16:58:23.306636715 +0200
pascal@23680 3 @@ -25,33 +25,206 @@
pascal@23680 4 #include "block/block_int.h"
pascal@23680 5 #include "qemu/module.h"
pascal@23680 6 #include <zlib.h>
pascal@23680 7 +#include <lzma.h>
pascal@23680 8 +
pascal@23680 9 +#define CLOOP_COMPRESSOR_ZLIB 0x0
pascal@23680 10 +#define CLOOP_COMPRESSOR_NONE 0x1
pascal@23680 11 +#define CLOOP_COMPRESSOR_XZ 0x2
pascal@23680 12 +#define CLOOP_COMPRESSOR_LZ4 0x3
pascal@23680 13 +#define CLOOP_COMPRESSOR_LZO 0x4
pascal@23680 14 +#define CLOOP_COMPRESSOR_ZSTD 0x5
pascal@23680 15 +#define CLOOP_COMPRESSOR_LINK 0xF
pascal@23680 16 +
pascal@23680 17 +#define CLOOP_BLOCK_FLAGS(x) ((unsigned int)(((x) & 0xf000000000000000LLU) >> 60))
pascal@23680 18 +#define CLOOP_BLOCK_OFFSET(x) ((x) & 0x0fffffffffffffffLLU)
pascal@23680 19
pascal@17989 20 /* Maximum compressed block size */
pascal@17989 21 #define MAX_BLOCK_SIZE (64 * 1024 * 1024)
pascal@17266 22
pascal@17266 23 +typedef struct cloop_tail {
pascal@17266 24 + uint32_t table_size;
pascal@17266 25 + uint32_t index_size;
pascal@17266 26 + uint32_t num_blocks;
pascal@17266 27 +} cloop_tail;
pascal@17266 28 +
pascal@23680 29 +#define CLOOP3_INDEX_SIZE(x) ((unsigned int)((x) & 0xF))
pascal@23680 30 +#define CLOOP3_BLOCKS_FLAGS(x) ((unsigned int)((x) & 0x70) >> 4)
pascal@23680 31 +
pascal@17266 32 +typedef struct block_info {
pascal@17266 33 + uint64_t offset; /* 64-bit offsets of compressed block */
pascal@17266 34 + uint32_t size; /* 32-bit compressed block size */
pascal@23680 35 + uint32_t flags; /* 32-bit compression flags */
pascal@17266 36 +} block_info;
pascal@17266 37 +
pascal@23680 38 +static inline int build_index(struct block_info *offsets, unsigned long n,
pascal@23680 39 + unsigned long block_size, unsigned global_flags)
pascal@17266 40 +{
pascal@17266 41 + uint32_t *ofs32 = (uint32_t *) offsets;
pascal@23680 42 + loff_t *ofs64 = (loff_t *) offsets;
pascal@23680 43 +
pascal@23680 44 + /* v3 64bits bug: v1 assumed */
pascal@23680 45 + unsigned long v3_64;
pascal@23680 46 + loff_t prev;
pascal@23680 47 +
pascal@23680 48 + if (ofs32[0] != 0 && ofs32[1] == 0) {
pascal@23680 49 + for (v3_64=(n+1)/2, prev=le64_to_cpu(ofs64[v3_64]);
pascal@23680 50 + v3_64 > 0 && le64_to_cpu(ofs64[--v3_64]) < prev;
pascal@23680 51 + prev=le64_to_cpu(ofs64[v3_64]));
pascal@23680 52 + }
pascal@23680 53 +
pascal@17266 54 + if (ofs32[0] == 0) {
pascal@17266 55 + if (ofs32[2]) { /* ACCELERATED KNOPPIX V1.0 */
pascal@17266 56 + while (n--) {
pascal@17266 57 + offsets[n].offset = be64_to_cpu(offsets[n].offset);
pascal@17266 58 + offsets[n].size = ntohl(offsets[n].size);
pascal@23680 59 + offsets[n].flags = 0;
pascal@17989 60 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
pascal@17989 61 + return n+1;
pascal@17266 62 + }
pascal@17266 63 + }
pascal@23680 64 + else { /* V2.0/V4.0 */
pascal@23680 65 + loff_t last = CLOOP_BLOCK_OFFSET(be64_to_cpu(ofs64[n]));
pascal@23680 66 + uint32_t flags;
pascal@23680 67 + unsigned long i = n;
pascal@23680 68 +
pascal@23680 69 + for (flags = 0; n-- ;) {
pascal@23680 70 + loff_t data = be64_to_cpu(ofs64[n]);
pascal@23680 71 +
pascal@17266 72 + offsets[n].size = last -
pascal@23680 73 + (offsets[n].offset = CLOOP_BLOCK_OFFSET(data));
pascal@17989 74 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
pascal@17989 75 + return n+1;
pascal@17266 76 + last = offsets[n].offset;
pascal@23680 77 + offsets[n].flags = CLOOP_BLOCK_FLAGS(data);
pascal@23680 78 + flags |= 1 << offsets[n].flags;
pascal@23680 79 + }
pascal@23680 80 + if (flags > 1) {
pascal@23680 81 + while (i--) {
pascal@23680 82 + if (offsets[i].flags == CLOOP_COMPRESSOR_LINK) {
pascal@23680 83 + offsets[i] = offsets[offsets[i].offset];
pascal@23680 84 + }
pascal@23680 85 + }
pascal@17266 86 + }
pascal@17266 87 + }
pascal@17266 88 + }
pascal@23680 89 + else if (ofs32[1] == 0 && v3_64 == 0) { /* V1.0 */
pascal@23680 90 + loff_t last = le64_to_cpu(ofs64[n]);
pascal@17266 91 + while (n--) {
pascal@17266 92 + offsets[n].size = last -
pascal@17266 93 + (offsets[n].offset = le64_to_cpu(ofs64[n]));
pascal@17989 94 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
pascal@17989 95 + return n+1;
pascal@17266 96 + last = offsets[n].offset;
pascal@23680 97 + offsets[n].flags = 0;
pascal@17266 98 + }
pascal@17266 99 + }
pascal@17266 100 + else if (ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */
pascal@23680 101 + loff_t last = ntohl(ofs32[n]);
pascal@17266 102 + while (n--) {
pascal@17266 103 + offsets[n].size = last -
pascal@17266 104 + (offsets[n].offset = ntohl(ofs32[n]));
pascal@17989 105 + if (offsets[n].size > 2 * MAX_BLOCK_SIZE)
pascal@17989 106 + return n+1;
pascal@17266 107 + last = offsets[n].offset;
pascal@23680 108 + offsets[n].flags = 0;
pascal@17266 109 + }
pascal@17266 110 + }
pascal@17266 111 + else { /* V3.0 */
pascal@17266 112 + unsigned long i;
pascal@23680 113 + loff_t j;
pascal@17266 114 +
pascal@23680 115 + v3_64 = (ofs32[1] == 0) ? 2 : 1;
pascal@17989 116 + for (i = n; i-- > 0; ) {
pascal@23680 117 + offsets[i].size = ntohl(ofs32[i*v3_64]);
pascal@23680 118 + if ((offsets[i].size & 0x80000000) == 0 &&
pascal@23680 119 + offsets[i].size > 2 * MAX_BLOCK_SIZE)
pascal@17989 120 + return i+1;
pascal@17989 121 + }
pascal@17266 122 + for (i = 0, j = 128 + 4 + 4; i < n; i++) {
pascal@17266 123 + offsets[i].offset = j;
pascal@23680 124 + offsets[i].flags = global_flags;
pascal@23680 125 + if (offsets[i].size == 0xFFFFFFFF) {
pascal@23680 126 + offsets[i].flags = CLOOP_COMPRESSOR_NONE;
pascal@23680 127 + offsets[i].size = block_size;
pascal@23680 128 + }
pascal@23680 129 + if ((offsets[i].size & 0x80000000) == 0) {
pascal@23680 130 + j += offsets[i].size;
pascal@23680 131 + }
pascal@23680 132 + }
pascal@23680 133 + for (i = 0; i < n; i++) {
pascal@18828 134 + if (offsets[i].size & 0x80000000) {
pascal@23680 135 + offsets[i] = offsets[offsets[i].size & 0x7FFFFFFF];
pascal@18828 136 + }
pascal@17266 137 + }
pascal@17266 138 + }
pascal@17989 139 + return 0;
pascal@17266 140 +}
pascal@17266 141 +
pascal@17266 142 typedef struct BDRVCloopState {
pascal@17266 143 CoMutex lock;
pascal@17266 144 uint32_t block_size;
pascal@17266 145 uint32_t n_blocks;
pascal@17266 146 - uint64_t *offsets;
pascal@17266 147 + block_info *offsets;
pascal@17266 148 uint32_t sectors_per_block;
pascal@17266 149 uint32_t current_block;
pascal@17266 150 uint8_t *compressed_block;
pascal@23680 151 uint8_t *uncompressed_block;
pascal@23680 152 z_stream zstream;
pascal@23680 153 + int global_flags;
pascal@23680 154 } BDRVCloopState;
pascal@17266 155
pascal@17266 156 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
pascal@17266 157 {
pascal@17266 158 - const char *magic_version_2_0 = "#!/bin/sh\n"
pascal@17266 159 - "#V2.0 Format\n"
pascal@17266 160 + static const uint8_t magic[] =
pascal@17266 161 "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
pascal@17266 162 - int length = strlen(magic_version_2_0);
pascal@17266 163 - if (length > buf_size) {
pascal@17266 164 - length = buf_size;
pascal@17266 165 + int i, ret = 0, length = buf_size;
pascal@17266 166 + uint8_t c;
pascal@17266 167 +
pascal@17266 168 + if (length > 127) {
pascal@17266 169 + length = 127;
pascal@23680 170 + }
pascal@17266 171 + for (i = 0; i < length - sizeof(magic) + 1; i++) {
pascal@17266 172 + if (buf[i] != magic[0]) continue;
pascal@17266 173 + if (strncmp(buf + i, magic, sizeof(magic) - 1)) continue;
pascal@17266 174 + ret = 2;
pascal@17266 175 + break;
pascal@17266 176 }
pascal@23680 177 - if (!memcmp(magic_version_2_0, buf, length)) {
pascal@23680 178 - return 2;
pascal@17266 179 + return ret;
pascal@23680 180 +}
pascal@23680 181 +
pascal@23680 182 +static uint32_t cloop_upack(BDRVCloopState *s, int flag)
pascal@23680 183 +{
pascal@23680 184 + int ret;
pascal@23680 185 + size_t src_pos;
pascal@23680 186 + size_t dest_pos;
pascal@23680 187 + uint64_t memlimit;
pascal@23680 188 + uint32_t outlen = s->zstream.total_out;
pascal@23680 189 +
pascal@23680 190 + switch (flag) {
pascal@23680 191 + case CLOOP_COMPRESSOR_ZLIB:
pascal@23680 192 + ret = inflateReset(&s->zstream);
pascal@23680 193 + if (ret != Z_OK) {
pascal@23680 194 + return 0;
pascal@23680 195 + }
pascal@23680 196 + ret = inflate(&s->zstream, Z_FINISH);
pascal@23680 197 + if (ret != Z_STREAM_END || s->zstream.total_out != outlen) {
pascal@23680 198 + return 0;
pascal@23680 199 + }
pascal@23680 200 + return outlen;
pascal@23680 201 + case CLOOP_COMPRESSOR_NONE:
pascal@23680 202 + memcpy(s->zstream.next_out, s->zstream.next_in, s->zstream.avail_in);
pascal@23680 203 + return s->zstream.avail_in;
pascal@23680 204 + case CLOOP_COMPRESSOR_XZ:
pascal@23680 205 + src_pos = 0;
pascal@23680 206 + dest_pos = 0;
pascal@23680 207 + memlimit = 32*1024*1024;
pascal@23680 208 + ret = lzma_stream_buffer_decode(&memlimit, 0, NULL, s->zstream.next_in, &src_pos,
pascal@23680 209 + s->zstream.avail_in, s->zstream.next_out, &dest_pos, s->zstream.total_out);
pascal@23680 210 +
pascal@23680 211 + if(ret != LZMA_OK || s->zstream.avail_in != (int) src_pos) {
pascal@23680 212 + return 0;
pascal@23680 213 + }
pascal@23680 214 + return dest_pos;
pascal@23680 215 }
pascal@23680 216 return 0;
pascal@17266 217 }
pascal@23680 218 @@ -91,79 +264,92 @@
pascal@17989 219 MAX_BLOCK_SIZE / (1024 * 1024));
pascal@17989 220 return -EINVAL;
pascal@17989 221 }
pascal@17989 222 -
pascal@17989 223 ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
pascal@17989 224 if (ret < 0) {
pascal@17989 225 return ret;
pascal@17266 226 }
pascal@17266 227 s->n_blocks = be32_to_cpu(s->n_blocks);
pascal@17266 228
pascal@17990 229 - /* read offsets */
pascal@17989 230 - if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
pascal@17990 231 - /* Prevent integer overflow */
pascal@17990 232 - error_setg(errp, "n_blocks %u must be %zu or less",
pascal@17990 233 - s->n_blocks,
pascal@17989 234 - (UINT32_MAX - 1) / sizeof(uint64_t));
pascal@17990 235 - return -EINVAL;
pascal@17990 236 - }
pascal@17989 237 - offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
pascal@17989 238 - if (offsets_size > 512 * 1024 * 1024) {
pascal@17989 239 - /* Prevent ridiculous offsets_size which causes memory allocation to
pascal@17989 240 - * fail or overflows bdrv_pread() size. In practice the 512 MB
pascal@17989 241 - * offsets[] limit supports 16 TB images at 256 KB block size.
pascal@17989 242 - */
pascal@17989 243 - error_setg(errp, "image requires too many offsets, "
pascal@17989 244 - "try increasing block size");
pascal@17989 245 - return -EINVAL;
pascal@17989 246 - }
pascal@17989 247 - s->offsets = g_malloc(offsets_size);
pascal@17990 248 + /* initialize zlib engine */
pascal@17990 249 + max_compressed_block_size = s->block_size + s->block_size/1000 + 12 + 4;
pascal@17990 250 + s->compressed_block = g_malloc(max_compressed_block_size + 1);
pascal@17990 251 + s->uncompressed_block = g_malloc(s->block_size);
pascal@17990 252
pascal@17990 253 - ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
pascal@17990 254 - if (ret < 0) {
pascal@17990 255 + if (inflateInit(&s->zstream) != Z_OK) {
pascal@17990 256 + ret = -EINVAL;
pascal@17990 257 goto fail;
pascal@17990 258 }
pascal@17990 259
pascal@17990 260 - for (i = 0; i < s->n_blocks + 1; i++) {
pascal@17990 261 - uint64_t size;
pascal@17990 262 + /* read offsets */
pascal@17266 263 + if (s->n_blocks + 1 == 0) {
pascal@17266 264 + cloop_tail tail;
pascal@17266 265 + int64_t end = bdrv_getlength(bs->file);
pascal@17266 266 + void *p;
pascal@17266 267 + uint32_t toclen, len;
pascal@17989 268
pascal@17990 269 - s->offsets[i] = be64_to_cpu(s->offsets[i]);
pascal@17990 270 - if (i == 0) {
pascal@17990 271 - continue;
pascal@17266 272 + ret = bdrv_pread(bs->file, end - sizeof(tail), &tail, sizeof(tail));
pascal@17266 273 + if (ret < 0) {
pascal@17266 274 + goto fail;
pascal@17990 275 }
pascal@17989 276
pascal@17990 277 - if (s->offsets[i] < s->offsets[i - 1]) {
pascal@17990 278 - error_setg(errp, "offsets not monotonically increasing at "
pascal@17990 279 - "index %u, image file is corrupt", i);
pascal@17990 280 - ret = -EINVAL;
pascal@17990 281 - goto fail;
pascal@17266 282 + s->n_blocks = be32_to_cpu(tail.num_blocks);
pascal@17266 283 + offsets_size = s->n_blocks * sizeof(block_info);
pascal@17989 284 + if (offsets_size > 512 * 1024 * 1024) {
pascal@17989 285 + /* Prevent ridiculous offsets_size which causes memory allocation to
pascal@17989 286 + * fail or overflows bdrv_pread() size. In practice the 512 MB
pascal@17989 287 + * offsets[] limit supports 16 TB images at 256 KB block size.
pascal@17989 288 + */
pascal@17989 289 + error_setg(errp, "image requires too many offsets, "
pascal@17989 290 + "try increasing block size");
pascal@17989 291 + return -EINVAL;
pascal@17989 292 }
pascal@17266 293 + len = be32_to_cpu(tail.table_size);
pascal@23680 294 + toclen = CLOOP3_INDEX_SIZE(be32_to_cpu(tail.index_size)) * s->n_blocks;
pascal@23680 295 + s->global_flags = CLOOP3_BLOCKS_FLAGS(be32_to_cpu(tail.index_size));
pascal@17989 296
pascal@17990 297 - size = s->offsets[i] - s->offsets[i - 1];
pascal@17266 298 + s->offsets = g_malloc(offsets_size);
pascal@17266 299 + p = g_malloc(len);
pascal@17990 300
pascal@17990 301 - /* Compressed blocks should be smaller than the uncompressed block size
pascal@17990 302 - * but maybe compression performed poorly so the compressed block is
pascal@17990 303 - * actually bigger. Clamp down on unrealistic values to prevent
pascal@17990 304 - * ridiculous s->compressed_block allocation.
pascal@17990 305 - */
pascal@17990 306 - if (size > 2 * MAX_BLOCK_SIZE) {
pascal@17990 307 - error_setg(errp, "invalid compressed block size at index %u, "
pascal@17990 308 - "image file is corrupt", i);
pascal@17266 309 + ret = bdrv_pread(bs->file, end - sizeof(tail) - len, p, len);
pascal@17266 310 + if (ret < 0) {
pascal@17266 311 + goto fail;
pascal@17266 312 + }
pascal@17266 313 + s->zstream.next_in = p;
pascal@17266 314 + s->zstream.avail_in = len;
pascal@17266 315 + s->zstream.next_out = s->offsets;
pascal@17266 316 + s->zstream.avail_out = toclen;
pascal@23680 317 + if (cloop_unpack(s, s->global_flags) == 0) {
pascal@17989 318 ret = -EINVAL;
pascal@17989 319 goto fail;
pascal@17989 320 }
pascal@17266 321 + g_free(p);
pascal@23680 322 + }
pascal@17266 323 + else {
pascal@17266 324 + offsets_size = s->n_blocks * sizeof(block_info);
pascal@17989 325 + if (offsets_size > 512 * 1024 * 1024) {
pascal@17989 326 + /* Prevent ridiculous offsets_size which causes memory allocation to
pascal@17989 327 + * fail or overflows bdrv_pread() size. In practice the 512 MB
pascal@17989 328 + * offsets[] limit supports 16 TB images at 256 KB block size.
pascal@17989 329 + */
pascal@17989 330 + error_setg(errp, "image requires too many offsets, "
pascal@17989 331 + "try increasing block size");
pascal@17989 332 + return -EINVAL;
pascal@17989 333 + }
pascal@17266 334 + s->offsets = g_malloc(offsets_size);
pascal@17266 335
pascal@23680 336 - if (size > max_compressed_block_size) {
pascal@23680 337 - max_compressed_block_size = size;
pascal@23680 338 + ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
pascal@23680 339 + if (ret < 0) {
pascal@23680 340 + goto fail;
pascal@23680 341 }
pascal@23680 342 }
pascal@23680 343 -
pascal@17266 344 - /* initialize zlib engine */
pascal@17266 345 - s->compressed_block = g_malloc(max_compressed_block_size + 1);
pascal@17266 346 - s->uncompressed_block = g_malloc(s->block_size);
pascal@17266 347 - if (inflateInit(&s->zstream) != Z_OK) {
pascal@23680 348 + ret = build_index(s->offsets, s->n_blocks, s->block_size, s->global_flags);
pascal@17989 349 + if (ret) {
pascal@17989 350 + error_setg(errp, "invalid compressed block size at index %u, "
pascal@17989 351 + "image file is corrupt", ret-1);
pascal@17989 352 ret = -EINVAL;
pascal@17989 353 goto fail;
pascal@17266 354 }
pascal@17266 355 +
pascal@17266 356 s->current_block = s->n_blocks;
pascal@17266 357
pascal@17266 358 s->sectors_per_block = s->block_size/512;
pascal@23680 359 @@ -184,10 +370,10 @@
pascal@17266 360
pascal@17266 361 if (s->current_block != block_num) {
pascal@17266 362 int ret;
pascal@17266 363 - uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
pascal@17266 364 + uint32_t bytes = s->offsets[block_num].size;
pascal@17266 365
pascal@17266 366 - ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
pascal@17266 367 - bytes);
pascal@17266 368 + ret = bdrv_pread(bs->file, s->offsets[block_num].offset,
pascal@17266 369 + s->compressed_block, bytes);
pascal@17266 370 if (ret != bytes) {
pascal@17266 371 return -1;
pascal@17266 372 }
pascal@23680 373 @@ -196,12 +382,7 @@
pascal@23680 374 s->zstream.avail_in = bytes;
pascal@23680 375 s->zstream.next_out = s->uncompressed_block;
pascal@23680 376 s->zstream.avail_out = s->block_size;
pascal@23680 377 - ret = inflateReset(&s->zstream);
pascal@23680 378 - if (ret != Z_OK) {
pascal@23680 379 - return -1;
pascal@23680 380 - }
pascal@23680 381 - ret = inflate(&s->zstream, Z_FINISH);
pascal@23680 382 - if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) {
pascal@23680 383 + if (cloop_unpack(s, s->offsets[block_num].flags) == 0) {
pascal@23680 384 return -1;
pascal@23680 385 }
pascal@23680 386
pascal@23680 387 --- source/qemu-2.0.2/block/Makefile.objs 2014-08-18 18:03:24.000000000 +0200
pascal@23680 388 +++ Makefile.objs 2020-04-26 16:32:51.010232389 +0200
pascal@23680 389 @@ -35,5 +35,5 @@
pascal@23680 390 gluster.o-libs := $(GLUSTERFS_LIBS)
pascal@23680 391 ssh.o-cflags := $(LIBSSH2_CFLAGS)
pascal@23680 392 ssh.o-libs := $(LIBSSH2_LIBS)
pascal@23680 393 -qcow.o-libs := -lz
pascal@23680 394 +qcow.o-libs := -lz -llzma
pascal@23680 395 linux-aio.o-libs := -laio