Revision 917703c1 block/vmdk.c
b/block/vmdk.c | ||
---|---|---|
1452 | 1452 |
} |
1453 | 1453 |
|
1454 | 1454 |
static int vmdk_create_extent(const char *filename, int64_t filesize, |
1455 |
bool flat, bool compress, bool zeroed_grain) |
|
1455 |
bool flat, bool compress, bool zeroed_grain, |
|
1456 |
Error **errp) |
|
1456 | 1457 |
{ |
1457 | 1458 |
int ret, i; |
1458 |
int fd = 0;
|
|
1459 |
BlockDriverState *bs = NULL;
|
|
1459 | 1460 |
VMDK4Header header; |
1460 |
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count; |
|
1461 |
Error *local_err; |
|
1462 |
uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; |
|
1463 |
uint32_t *gd_buf = NULL; |
|
1464 |
int gd_buf_size; |
|
1461 | 1465 |
|
1462 |
fd = qemu_open(filename, |
|
1463 |
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, |
|
1464 |
0644); |
|
1465 |
if (fd < 0) { |
|
1466 |
return -errno; |
|
1466 |
ret = bdrv_create_file(filename, NULL, &local_err); |
|
1467 |
if (ret < 0) { |
|
1468 |
error_propagate(errp, local_err); |
|
1469 |
goto exit; |
|
1467 | 1470 |
} |
1471 |
|
|
1472 |
ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, &local_err); |
|
1473 |
if (ret < 0) { |
|
1474 |
error_propagate(errp, local_err); |
|
1475 |
goto exit; |
|
1476 |
} |
|
1477 |
|
|
1468 | 1478 |
if (flat) { |
1469 |
ret = ftruncate(fd, filesize);
|
|
1479 |
ret = bdrv_truncate(bs, filesize);
|
|
1470 | 1480 |
if (ret < 0) { |
1471 |
ret = -errno;
|
|
1481 |
error_setg(errp, "Could not truncate file");
|
|
1472 | 1482 |
} |
1473 | 1483 |
goto exit; |
1474 | 1484 |
} |
... | ... | |
1479 | 1489 |
| (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) |
1480 | 1490 |
| (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); |
1481 | 1491 |
header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; |
1482 |
header.capacity = filesize / 512;
|
|
1492 |
header.capacity = filesize / BDRV_SECTOR_SIZE;
|
|
1483 | 1493 |
header.granularity = 128; |
1484 |
header.num_gtes_per_gt = 512;
|
|
1494 |
header.num_gtes_per_gt = BDRV_SECTOR_SIZE;
|
|
1485 | 1495 |
|
1486 |
grains = (filesize / 512 + header.granularity - 1) / header.granularity;
|
|
1487 |
gt_size = ((header.num_gtes_per_gt * sizeof(uint32_t)) + 511) >> 9;
|
|
1488 |
gt_count =
|
|
1489 |
(grains + header.num_gtes_per_gt - 1) / header.num_gtes_per_gt;
|
|
1490 |
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
|
|
1496 |
grains = DIV_ROUND_UP(filesize / BDRV_SECTOR_SIZE, header.granularity);
|
|
1497 |
gt_size = DIV_ROUND_UP(header.num_gtes_per_gt * sizeof(uint32_t),
|
|
1498 |
BDRV_SECTOR_SIZE);
|
|
1499 |
gt_count = DIV_ROUND_UP(grains, header.num_gtes_per_gt);
|
|
1500 |
gd_sectors = DIV_ROUND_UP(gt_count * sizeof(uint32_t), BDRV_SECTOR_SIZE);
|
|
1491 | 1501 |
|
1492 | 1502 |
header.desc_offset = 1; |
1493 | 1503 |
header.desc_size = 20; |
1494 | 1504 |
header.rgd_offset = header.desc_offset + header.desc_size; |
1495 |
header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
|
|
1505 |
header.gd_offset = header.rgd_offset + gd_sectors + (gt_size * gt_count);
|
|
1496 | 1506 |
header.grain_offset = |
1497 |
((header.gd_offset + gd_size + (gt_size * gt_count) + |
|
1498 |
header.granularity - 1) / header.granularity) * |
|
1499 |
header.granularity; |
|
1507 |
ROUND_UP(header.gd_offset + gd_sectors + (gt_size * gt_count), |
|
1508 |
header.granularity); |
|
1500 | 1509 |
/* swap endianness for all header fields */ |
1501 | 1510 |
header.version = cpu_to_le32(header.version); |
1502 | 1511 |
header.flags = cpu_to_le32(header.flags); |
... | ... | |
1516 | 1525 |
header.check_bytes[3] = 0xa; |
1517 | 1526 |
|
1518 | 1527 |
/* write all the data */ |
1519 |
ret = qemu_write_full(fd, &magic, sizeof(magic));
|
|
1520 |
if (ret != sizeof(magic)) {
|
|
1521 |
ret = -errno;
|
|
1528 |
ret = bdrv_pwrite(bs, 0, &magic, sizeof(magic));
|
|
1529 |
if (ret < 0) {
|
|
1530 |
error_set(errp, QERR_IO_ERROR);
|
|
1522 | 1531 |
goto exit; |
1523 | 1532 |
} |
1524 |
ret = qemu_write_full(fd, &header, sizeof(header));
|
|
1525 |
if (ret != sizeof(header)) {
|
|
1526 |
ret = -errno;
|
|
1533 |
ret = bdrv_pwrite(bs, sizeof(magic), &header, sizeof(header));
|
|
1534 |
if (ret < 0) {
|
|
1535 |
error_set(errp, QERR_IO_ERROR);
|
|
1527 | 1536 |
goto exit; |
1528 | 1537 |
} |
1529 | 1538 |
|
1530 |
ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
|
|
1539 |
ret = bdrv_truncate(bs, le64_to_cpu(header.grain_offset) << 9);
|
|
1531 | 1540 |
if (ret < 0) { |
1532 |
ret = -errno;
|
|
1541 |
error_setg(errp, "Could not truncate file");
|
|
1533 | 1542 |
goto exit; |
1534 | 1543 |
} |
1535 | 1544 |
|
1536 | 1545 |
/* write grain directory */ |
1537 |
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET); |
|
1538 |
for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size; |
|
1546 |
gd_buf_size = gd_sectors * BDRV_SECTOR_SIZE; |
|
1547 |
gd_buf = g_malloc0(gd_buf_size); |
|
1548 |
for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; |
|
1539 | 1549 |
i < gt_count; i++, tmp += gt_size) { |
1540 |
ret = qemu_write_full(fd, &tmp, sizeof(tmp)); |
|
1541 |
if (ret != sizeof(tmp)) { |
|
1542 |
ret = -errno; |
|
1543 |
goto exit; |
|
1544 |
} |
|
1550 |
gd_buf[i] = cpu_to_le32(tmp); |
|
1551 |
} |
|
1552 |
ret = bdrv_pwrite(bs, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, |
|
1553 |
gd_buf, gd_buf_size); |
|
1554 |
if (ret < 0) { |
|
1555 |
error_set(errp, QERR_IO_ERROR); |
|
1556 |
goto exit; |
|
1545 | 1557 |
} |
1546 | 1558 |
|
1547 | 1559 |
/* write backup grain directory */ |
1548 |
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET); |
|
1549 |
for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size; |
|
1560 |
for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_sectors; |
|
1550 | 1561 |
i < gt_count; i++, tmp += gt_size) { |
1551 |
ret = qemu_write_full(fd, &tmp, sizeof(tmp)); |
|
1552 |
if (ret != sizeof(tmp)) { |
|
1553 |
ret = -errno; |
|
1554 |
goto exit; |
|
1555 |
} |
|
1562 |
gd_buf[i] = cpu_to_le32(tmp); |
|
1563 |
} |
|
1564 |
ret = bdrv_pwrite(bs, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, |
|
1565 |
gd_buf, gd_buf_size); |
|
1566 |
if (ret < 0) { |
|
1567 |
error_set(errp, QERR_IO_ERROR); |
|
1568 |
goto exit; |
|
1556 | 1569 |
} |
1557 | 1570 |
|
1558 | 1571 |
ret = 0; |
1559 |
exit: |
|
1560 |
qemu_close(fd); |
|
1572 |
exit: |
|
1573 |
if (bs) { |
|
1574 |
bdrv_unref(bs); |
|
1575 |
} |
|
1576 |
g_free(gd_buf); |
|
1561 | 1577 |
return ret; |
1562 | 1578 |
} |
1563 | 1579 |
|
... | ... | |
1604 | 1620 |
static int vmdk_create(const char *filename, QEMUOptionParameter *options, |
1605 | 1621 |
Error **errp) |
1606 | 1622 |
{ |
1607 |
int fd, idx = 0; |
|
1623 |
int idx = 0; |
|
1624 |
BlockDriverState *new_bs = NULL; |
|
1625 |
Error *local_err; |
|
1608 | 1626 |
char *desc = NULL; |
1609 | 1627 |
int64_t total_size = 0, filesize; |
1610 | 1628 |
const char *adapter_type = NULL; |
... | ... | |
1621 | 1639 |
uint32_t parent_cid = 0xffffffff; |
1622 | 1640 |
uint32_t number_heads = 16; |
1623 | 1641 |
bool zeroed_grain = false; |
1642 |
uint32_t desc_offset = 0, desc_len; |
|
1624 | 1643 |
const char desc_template[] = |
1625 | 1644 |
"# Disk DescriptorFile\n" |
1626 | 1645 |
"version=1\n" |
... | ... | |
1754 | 1773 |
path, desc_filename); |
1755 | 1774 |
|
1756 | 1775 |
if (vmdk_create_extent(ext_filename, size, |
1757 |
flat, compress, zeroed_grain)) { |
|
1776 |
flat, compress, zeroed_grain, errp)) {
|
|
1758 | 1777 |
ret = -EINVAL; |
1759 | 1778 |
goto exit; |
1760 | 1779 |
} |
... | ... | |
1762 | 1781 |
|
1763 | 1782 |
/* Format description line */ |
1764 | 1783 |
snprintf(desc_line, sizeof(desc_line), |
1765 |
desc_extent_line, size / 512, desc_filename);
|
|
1784 |
desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename);
|
|
1766 | 1785 |
g_string_append(ext_desc_lines, desc_line); |
1767 | 1786 |
} |
1768 | 1787 |
/* generate descriptor file */ |
... | ... | |
1773 | 1792 |
parent_desc_line, |
1774 | 1793 |
ext_desc_lines->str, |
1775 | 1794 |
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), |
1776 |
total_size / (int64_t)(63 * number_heads * 512), |
|
1795 |
total_size / |
|
1796 |
(int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), |
|
1777 | 1797 |
number_heads, |
1778 | 1798 |
adapter_type); |
1779 |
if (split || flat) {
|
|
1780 |
fd = qemu_open(filename,
|
|
1781 |
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
|
1782 |
0644);
|
|
1799 |
desc_len = strlen(desc);
|
|
1800 |
/* the descriptor offset = 0x200 */
|
|
1801 |
if (!split && !flat) {
|
|
1802 |
desc_offset = 0x200;
|
|
1783 | 1803 |
} else { |
1784 |
fd = qemu_open(filename, |
|
1785 |
O_WRONLY | O_BINARY | O_LARGEFILE, |
|
1786 |
0644); |
|
1804 |
ret = bdrv_create_file(filename, options, &local_err); |
|
1805 |
if (ret < 0) { |
|
1806 |
error_setg_errno(errp, -ret, "Could not create image file"); |
|
1807 |
goto exit; |
|
1808 |
} |
|
1787 | 1809 |
} |
1788 |
if (fd < 0) { |
|
1789 |
ret = -errno; |
|
1810 |
ret = bdrv_file_open(&new_bs, filename, NULL, BDRV_O_RDWR, &local_err); |
|
1811 |
if (ret < 0) { |
|
1812 |
error_setg_errno(errp, -ret, "Could not write description"); |
|
1790 | 1813 |
goto exit; |
1791 | 1814 |
} |
1792 |
/* the descriptor offset = 0x200 */
|
|
1793 |
if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
|
|
1794 |
ret = -errno;
|
|
1795 |
goto close_exit;
|
|
1815 |
ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len);
|
|
1816 |
if (ret < 0) {
|
|
1817 |
error_setg_errno(errp, -ret, "Could not write description");
|
|
1818 |
goto exit; |
|
1796 | 1819 |
} |
1797 |
ret = qemu_write_full(fd, desc, strlen(desc)); |
|
1798 |
if (ret != strlen(desc)) { |
|
1799 |
ret = -errno; |
|
1800 |
goto close_exit; |
|
1820 |
/* bdrv_pwrite write padding zeros to align to sector, we don't need that |
|
1821 |
* for description file */ |
|
1822 |
if (desc_offset == 0) { |
|
1823 |
ret = bdrv_truncate(new_bs, desc_len); |
|
1824 |
if (ret < 0) { |
|
1825 |
error_setg(errp, "Could not truncate file"); |
|
1826 |
} |
|
1801 | 1827 |
} |
1802 |
ret = 0; |
|
1803 |
close_exit: |
|
1804 |
qemu_close(fd); |
|
1805 | 1828 |
exit: |
1829 |
if (new_bs) { |
|
1830 |
bdrv_unref(new_bs); |
|
1831 |
} |
|
1806 | 1832 |
g_free(desc); |
1807 | 1833 |
g_string_free(ext_desc_lines, true); |
1808 | 1834 |
return ret; |
Also available in: Unified diff