tools: qemu: Add patches to support adapter_type and monolithicFlat
[openwrt/staging/mkresin.git] / tools / qemu / patches / 0011-VMDK-create-different-subformats.patch
1 From 0d0f2ba577bd05491b5954751787f8b969ca1ec3 Mon Sep 17 00:00:00 2001
2 From: Fam Zheng <famcool@gmail.com>
3 Date: Tue, 19 Jul 2011 08:45:23 +0800
4 Subject: [PATCH 11/12] VMDK: create different subformats
5
6 Add create option 'format', with enums:
7 monolithicSparse
8 monolithicFlat
9 twoGbMaxExtentSparse
10 twoGbMaxExtentFlat
11 Each creates a subformat image file. The default is monolithicSparse.
12
13 Signed-off-by: Fam Zheng <famcool@gmail.com>
14 Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
15 Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16 ---
17 block/vmdk.c | 503 ++++++++++++++++++++++++++++++++---------------------------
18 block_int.h | 1 +
19 2 files changed, 275 insertions(+), 229 deletions(-)
20
21 --- a/block/vmdk.c
22 +++ b/block/vmdk.c
23 @@ -156,8 +156,9 @@ static int vmdk_probe(const uint8_t *buf
24 #define CHECK_CID 1
25
26 #define SECTOR_SIZE 512
27 -#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each
28 -#define HEADER_SIZE 512 // first sector of 512 bytes
29 +#define DESC_SIZE (20 * SECTOR_SIZE) /* 20 sectors of 512 bytes each */
30 +#define BUF_SIZE 4096
31 +#define HEADER_SIZE 512 /* first sector of 512 bytes */
32
33 static void vmdk_free_extents(BlockDriverState *bs)
34 {
35 @@ -243,168 +244,6 @@ static int vmdk_is_cid_valid(BlockDriver
36 return 1;
37 }
38
39 -static int vmdk_snapshot_create(const char *filename, const char *backing_file)
40 -{
41 - int snp_fd, p_fd;
42 - int ret;
43 - uint32_t p_cid;
44 - char *p_name, *gd_buf, *rgd_buf;
45 - const char *real_filename, *temp_str;
46 - VMDK4Header header;
47 - uint32_t gde_entries, gd_size;
48 - int64_t gd_offset, rgd_offset, capacity, gt_size;
49 - char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
50 - static const char desc_template[] =
51 - "# Disk DescriptorFile\n"
52 - "version=1\n"
53 - "CID=%x\n"
54 - "parentCID=%x\n"
55 - "createType=\"monolithicSparse\"\n"
56 - "parentFileNameHint=\"%s\"\n"
57 - "\n"
58 - "# Extent description\n"
59 - "RW %u SPARSE \"%s\"\n"
60 - "\n"
61 - "# The Disk Data Base \n"
62 - "#DDB\n"
63 - "\n";
64 -
65 - snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
66 - if (snp_fd < 0)
67 - return -errno;
68 - p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
69 - if (p_fd < 0) {
70 - close(snp_fd);
71 - return -errno;
72 - }
73 -
74 - /* read the header */
75 - if (lseek(p_fd, 0x0, SEEK_SET) == -1) {
76 - ret = -errno;
77 - goto fail;
78 - }
79 - if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) {
80 - ret = -errno;
81 - goto fail;
82 - }
83 -
84 - /* write the header */
85 - if (lseek(snp_fd, 0x0, SEEK_SET) == -1) {
86 - ret = -errno;
87 - goto fail;
88 - }
89 - if (write(snp_fd, hdr, HEADER_SIZE) == -1) {
90 - ret = -errno;
91 - goto fail;
92 - }
93 -
94 - memset(&header, 0, sizeof(header));
95 - memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
96 -
97 - if (ftruncate(snp_fd, header.grain_offset << 9)) {
98 - ret = -errno;
99 - goto fail;
100 - }
101 - /* the descriptor offset = 0x200 */
102 - if (lseek(p_fd, 0x200, SEEK_SET) == -1) {
103 - ret = -errno;
104 - goto fail;
105 - }
106 - if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) {
107 - ret = -errno;
108 - goto fail;
109 - }
110 -
111 - if ((p_name = strstr(p_desc,"CID")) != NULL) {
112 - p_name += sizeof("CID");
113 - sscanf(p_name,"%x",&p_cid);
114 - }
115 -
116 - real_filename = filename;
117 - if ((temp_str = strrchr(real_filename, '\\')) != NULL)
118 - real_filename = temp_str + 1;
119 - if ((temp_str = strrchr(real_filename, '/')) != NULL)
120 - real_filename = temp_str + 1;
121 - if ((temp_str = strrchr(real_filename, ':')) != NULL)
122 - real_filename = temp_str + 1;
123 -
124 - snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file,
125 - (uint32_t)header.capacity, real_filename);
126 -
127 - /* write the descriptor */
128 - if (lseek(snp_fd, 0x200, SEEK_SET) == -1) {
129 - ret = -errno;
130 - goto fail;
131 - }
132 - if (write(snp_fd, s_desc, strlen(s_desc)) == -1) {
133 - ret = -errno;
134 - goto fail;
135 - }
136 -
137 - gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table
138 - rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table
139 - capacity = header.capacity * SECTOR_SIZE; // Extent size
140 - /*
141 - * Each GDE span 32M disk, means:
142 - * 512 GTE per GT, each GTE points to grain
143 - */
144 - gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
145 - if (!gt_size) {
146 - ret = -EINVAL;
147 - goto fail;
148 - }
149 - gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde
150 - gd_size = gde_entries * sizeof(uint32_t);
151 -
152 - /* write RGD */
153 - rgd_buf = qemu_malloc(gd_size);
154 - if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) {
155 - ret = -errno;
156 - goto fail_rgd;
157 - }
158 - if (read(p_fd, rgd_buf, gd_size) != gd_size) {
159 - ret = -errno;
160 - goto fail_rgd;
161 - }
162 - if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) {
163 - ret = -errno;
164 - goto fail_rgd;
165 - }
166 - if (write(snp_fd, rgd_buf, gd_size) == -1) {
167 - ret = -errno;
168 - goto fail_rgd;
169 - }
170 -
171 - /* write GD */
172 - gd_buf = qemu_malloc(gd_size);
173 - if (lseek(p_fd, gd_offset, SEEK_SET) == -1) {
174 - ret = -errno;
175 - goto fail_gd;
176 - }
177 - if (read(p_fd, gd_buf, gd_size) != gd_size) {
178 - ret = -errno;
179 - goto fail_gd;
180 - }
181 - if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) {
182 - ret = -errno;
183 - goto fail_gd;
184 - }
185 - if (write(snp_fd, gd_buf, gd_size) == -1) {
186 - ret = -errno;
187 - goto fail_gd;
188 - }
189 - ret = 0;
190 -
191 -fail_gd:
192 - qemu_free(gd_buf);
193 -fail_rgd:
194 - qemu_free(rgd_buf);
195 -fail:
196 - close(p_fd);
197 - close(snp_fd);
198 - return ret;
199 -}
200 -
201 static int vmdk_parent_open(BlockDriverState *bs)
202 {
203 char *p_name;
204 @@ -1058,68 +897,40 @@ static int vmdk_write(BlockDriverState *
205 return 0;
206 }
207
208 -static int vmdk_create(const char *filename, QEMUOptionParameter *options)
209 +
210 +static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
211 {
212 - int fd, i;
213 + int ret, i;
214 + int fd = 0;
215 VMDK4Header header;
216 uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
217 - static const char desc_template[] =
218 - "# Disk DescriptorFile\n"
219 - "version=1\n"
220 - "CID=%x\n"
221 - "parentCID=ffffffff\n"
222 - "createType=\"monolithicSparse\"\n"
223 - "\n"
224 - "# Extent description\n"
225 - "RW %" PRId64 " SPARSE \"%s\"\n"
226 - "\n"
227 - "# The Disk Data Base \n"
228 - "#DDB\n"
229 - "\n"
230 - "ddb.virtualHWVersion = \"%d\"\n"
231 - "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
232 - "ddb.geometry.heads = \"16\"\n"
233 - "ddb.geometry.sectors = \"63\"\n"
234 - "ddb.adapterType = \"ide\"\n";
235 - char desc[1024];
236 - const char *real_filename, *temp_str;
237 - int64_t total_size = 0;
238 - const char *backing_file = NULL;
239 - int flags = 0;
240 - int ret;
241
242 - // Read out options
243 - while (options && options->name) {
244 - if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
245 - total_size = options->value.n / 512;
246 - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
247 - backing_file = options->value.s;
248 - } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
249 - flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
250 - }
251 - options++;
252 + fd = open(
253 + filename,
254 + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
255 + 0644);
256 + if (fd < 0) {
257 + return -errno;
258 }
259 -
260 - /* XXX: add support for backing file */
261 - if (backing_file) {
262 - return vmdk_snapshot_create(filename, backing_file);
263 + if (flat) {
264 + ret = ftruncate(fd, filesize);
265 + if (ret < 0) {
266 + ret = -errno;
267 + }
268 + goto exit;
269 }
270 -
271 - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
272 - 0644);
273 - if (fd < 0)
274 - return -errno;
275 magic = cpu_to_be32(VMDK4_MAGIC);
276 memset(&header, 0, sizeof(header));
277 header.version = 1;
278 header.flags = 3; /* ?? */
279 - header.capacity = total_size;
280 + header.capacity = filesize / 512;
281 header.granularity = 128;
282 header.num_gtes_per_gte = 512;
283
284 - grains = (total_size + header.granularity - 1) / header.granularity;
285 + grains = (filesize / 512 + header.granularity - 1) / header.granularity;
286 gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
287 - gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
288 + gt_count =
289 + (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
290 gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
291
292 header.desc_offset = 1;
293 @@ -1130,7 +941,6 @@ static int vmdk_create(const char *filen
294 ((header.gd_offset + gd_size + (gt_size * gt_count) +
295 header.granularity - 1) / header.granularity) *
296 header.granularity;
297 -
298 /* swap endianness for all header fields */
299 header.version = cpu_to_le32(header.version);
300 header.flags = cpu_to_le32(header.flags);
301 @@ -1188,27 +998,255 @@ static int vmdk_create(const char *filen
302 }
303 }
304
305 - /* compose the descriptor */
306 - real_filename = filename;
307 - if ((temp_str = strrchr(real_filename, '\\')) != NULL)
308 - real_filename = temp_str + 1;
309 - if ((temp_str = strrchr(real_filename, '/')) != NULL)
310 - real_filename = temp_str + 1;
311 - if ((temp_str = strrchr(real_filename, ':')) != NULL)
312 - real_filename = temp_str + 1;
313 - snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
314 - total_size, real_filename,
315 - (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
316 - total_size / (int64_t)(63 * 16));
317 + ret = 0;
318 + exit:
319 + close(fd);
320 + return ret;
321 +}
322
323 - /* write the descriptor */
324 - lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
325 +static int filename_decompose(const char *filename, char *path, char *prefix,
326 + char *postfix, size_t buf_len)
327 +{
328 + const char *p, *q;
329 +
330 + if (filename == NULL || !strlen(filename)) {
331 + fprintf(stderr, "Vmdk: no filename provided.\n");
332 + return -1;
333 + }
334 + p = strrchr(filename, '/');
335 + if (p == NULL) {
336 + p = strrchr(filename, '\\');
337 + }
338 + if (p == NULL) {
339 + p = strrchr(filename, ':');
340 + }
341 + if (p != NULL) {
342 + p++;
343 + if (p - filename >= buf_len) {
344 + return -1;
345 + }
346 + pstrcpy(path, p - filename + 1, filename);
347 + } else {
348 + p = filename;
349 + path[0] = '\0';
350 + }
351 + q = strrchr(p, '.');
352 + if (q == NULL) {
353 + pstrcpy(prefix, buf_len, p);
354 + postfix[0] = '\0';
355 + } else {
356 + if (q - p >= buf_len) {
357 + return -1;
358 + }
359 + pstrcpy(prefix, q - p + 1, p);
360 + pstrcpy(postfix, buf_len, q);
361 + }
362 + return 0;
363 +}
364 +
365 +static int relative_path(char *dest, int dest_size,
366 + const char *base, const char *target)
367 +{
368 + int i = 0;
369 + int n = 0;
370 + const char *p, *q;
371 +#ifdef _WIN32
372 + const char *sep = "\\";
373 +#else
374 + const char *sep = "/";
375 +#endif
376 +
377 + if (!(dest && base && target)) {
378 + return -1;
379 + }
380 + if (path_is_absolute(target)) {
381 + dest[dest_size - 1] = '\0';
382 + strncpy(dest, target, dest_size - 1);
383 + return 0;
384 + }
385 + while (base[i] == target[i]) {
386 + i++;
387 + }
388 + p = &base[i];
389 + q = &target[i];
390 + while (*p) {
391 + if (*p == *sep) {
392 + n++;
393 + }
394 + p++;
395 + }
396 + dest[0] = '\0';
397 + for (; n; n--) {
398 + pstrcat(dest, dest_size, "..");
399 + pstrcat(dest, dest_size, sep);
400 + }
401 + pstrcat(dest, dest_size, q);
402 + return 0;
403 +}
404 +
405 +static int vmdk_create(const char *filename, QEMUOptionParameter *options)
406 +{
407 + int fd, idx = 0;
408 + char desc[BUF_SIZE];
409 + int64_t total_size = 0, filesize;
410 + const char *backing_file = NULL;
411 + const char *fmt = NULL;
412 + int flags = 0;
413 + int ret = 0;
414 + bool flat, split;
415 + char ext_desc_lines[BUF_SIZE] = "";
416 + char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
417 + const int64_t split_size = 0x80000000; /* VMDK has constant split size */
418 + const char *desc_extent_line;
419 + char parent_desc_line[BUF_SIZE] = "";
420 + uint32_t parent_cid = 0xffffffff;
421 + const char desc_template[] =
422 + "# Disk DescriptorFile\n"
423 + "version=1\n"
424 + "CID=%x\n"
425 + "parentCID=%x\n"
426 + "createType=\"%s\"\n"
427 + "%s"
428 + "\n"
429 + "# Extent description\n"
430 + "%s"
431 + "\n"
432 + "# The Disk Data Base\n"
433 + "#DDB\n"
434 + "\n"
435 + "ddb.virtualHWVersion = \"%d\"\n"
436 + "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
437 + "ddb.geometry.heads = \"16\"\n"
438 + "ddb.geometry.sectors = \"63\"\n"
439 + "ddb.adapterType = \"ide\"\n";
440 +
441 + if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
442 + return -EINVAL;
443 + }
444 + /* Read out options */
445 + while (options && options->name) {
446 + if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
447 + total_size = options->value.n;
448 + } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
449 + backing_file = options->value.s;
450 + } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
451 + flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
452 + } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
453 + fmt = options->value.s;
454 + }
455 + options++;
456 + }
457 + if (!fmt) {
458 + /* Default format to monolithicSparse */
459 + fmt = "monolithicSparse";
460 + } else if (strcmp(fmt, "monolithicFlat") &&
461 + strcmp(fmt, "monolithicSparse") &&
462 + strcmp(fmt, "twoGbMaxExtentSparse") &&
463 + strcmp(fmt, "twoGbMaxExtentFlat")) {
464 + fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
465 + return -EINVAL;
466 + }
467 + split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
468 + strcmp(fmt, "twoGbMaxExtentSparse"));
469 + flat = !(strcmp(fmt, "monolithicFlat") &&
470 + strcmp(fmt, "twoGbMaxExtentFlat"));
471 + if (flat) {
472 + desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
473 + } else {
474 + desc_extent_line = "RW %lld SPARSE \"%s\"\n";
475 + }
476 + if (flat && backing_file) {
477 + /* not supporting backing file for flat image */
478 + return -ENOTSUP;
479 + }
480 + if (backing_file) {
481 + char parent_filename[PATH_MAX];
482 + BlockDriverState *bs = bdrv_new("");
483 + ret = bdrv_open(bs, backing_file, 0, NULL);
484 + if (ret != 0) {
485 + bdrv_delete(bs);
486 + return ret;
487 + }
488 + if (strcmp(bs->drv->format_name, "vmdk")) {
489 + bdrv_delete(bs);
490 + return -EINVAL;
491 + }
492 + filesize = bdrv_getlength(bs);
493 + parent_cid = vmdk_read_cid(bs, 0);
494 + bdrv_delete(bs);
495 + relative_path(parent_filename, sizeof(parent_filename),
496 + filename, backing_file);
497 + snprintf(parent_desc_line, sizeof(parent_desc_line),
498 + "parentFileNameHint=\"%s\"", parent_filename);
499 + }
500 +
501 + /* Create extents */
502 + filesize = total_size;
503 + while (filesize > 0) {
504 + char desc_line[BUF_SIZE];
505 + char ext_filename[PATH_MAX];
506 + char desc_filename[PATH_MAX];
507 + int64_t size = filesize;
508 +
509 + if (split && size > split_size) {
510 + size = split_size;
511 + }
512 + if (split) {
513 + snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s",
514 + prefix, flat ? 'f' : 's', ++idx, postfix);
515 + } else if (flat) {
516 + snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s",
517 + prefix, postfix);
518 + } else {
519 + snprintf(desc_filename, sizeof(desc_filename), "%s%s",
520 + prefix, postfix);
521 + }
522 + snprintf(ext_filename, sizeof(ext_filename), "%s%s",
523 + path, desc_filename);
524 +
525 + if (vmdk_create_extent(ext_filename, size, flat)) {
526 + return -EINVAL;
527 + }
528 + filesize -= size;
529 +
530 + /* Format description line */
531 + snprintf(desc_line, sizeof(desc_line),
532 + desc_extent_line, size / 512, desc_filename);
533 + pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
534 + }
535 + /* generate descriptor file */
536 + snprintf(desc, sizeof(desc), desc_template,
537 + (unsigned int)time(NULL),
538 + parent_cid,
539 + fmt,
540 + parent_desc_line,
541 + ext_desc_lines,
542 + (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
543 + total_size / (int64_t)(63 * 16 * 512));
544 + if (split || flat) {
545 + fd = open(
546 + filename,
547 + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
548 + 0644);
549 + } else {
550 + fd = open(
551 + filename,
552 + O_WRONLY | O_BINARY | O_LARGEFILE,
553 + 0644);
554 + }
555 + if (fd < 0) {
556 + return -errno;
557 + }
558 + /* the descriptor offset = 0x200 */
559 + if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
560 + ret = -errno;
561 + goto exit;
562 + }
563 ret = qemu_write_full(fd, desc, strlen(desc));
564 if (ret != strlen(desc)) {
565 ret = -errno;
566 goto exit;
567 }
568 -
569 ret = 0;
570 exit:
571 close(fd);
572 @@ -1252,6 +1290,13 @@ static QEMUOptionParameter vmdk_create_o
573 .type = OPT_FLAG,
574 .help = "VMDK version 6 image"
575 },
576 + {
577 + .name = BLOCK_OPT_SUBFMT,
578 + .type = OPT_STRING,
579 + .help =
580 + "VMDK flat extent format, can be one of "
581 + "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
582 + },
583 { NULL }
584 };
585
586 --- a/block_int.h
587 +++ b/block_int.h
588 @@ -39,6 +39,7 @@
589 #define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
590 #define BLOCK_OPT_TABLE_SIZE "table_size"
591 #define BLOCK_OPT_PREALLOC "preallocation"
592 +#define BLOCK_OPT_SUBFMT "subformat"
593
594 typedef struct AIOPool {
595 void (*cancel)(BlockDriverAIOCB *acb);