Commit 73c632edc4e28d0a8cae3b34abf7ae46fa33bf1e
Committed by
Anthony Liguori
1 parent
efa84d43
qcow2: Allow different cluster sizes
Add an option to specify the cluster size of a newly created qcow2 image. Default is 4k which is the same value that was hard-coded before. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
2 changed files
with
49 additions
and
5 deletions
block/qcow2.c
... | ... | @@ -62,6 +62,9 @@ |
62 | 62 | |
63 | 63 | #define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */ |
64 | 64 | |
65 | +#define MIN_CLUSTER_BITS 9 | |
66 | +#define MAX_CLUSTER_BITS 16 | |
67 | + | |
65 | 68 | typedef struct QCowHeader { |
66 | 69 | uint32_t magic; |
67 | 70 | uint32_t version; |
... | ... | @@ -300,8 +303,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) |
300 | 303 | if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) |
301 | 304 | goto fail; |
302 | 305 | if (header.size <= 1 || |
303 | - header.cluster_bits < 9 || | |
304 | - header.cluster_bits > 16) | |
306 | + header.cluster_bits < MIN_CLUSTER_BITS || | |
307 | + header.cluster_bits > MAX_CLUSTER_BITS) | |
305 | 308 | goto fail; |
306 | 309 | if (header.crypt_method > QCOW_CRYPT_AES) |
307 | 310 | goto fail; |
... | ... | @@ -1583,9 +1586,30 @@ static void create_refcount_update(QCowCreateState *s, |
1583 | 1586 | } |
1584 | 1587 | } |
1585 | 1588 | |
1589 | +static int get_bits_from_size(size_t size) | |
1590 | +{ | |
1591 | + int res = 0; | |
1592 | + | |
1593 | + if (size == 0) { | |
1594 | + return -1; | |
1595 | + } | |
1596 | + | |
1597 | + while (size != 1) { | |
1598 | + /* Not a power of two */ | |
1599 | + if (size & 1) { | |
1600 | + return -1; | |
1601 | + } | |
1602 | + | |
1603 | + size >>= 1; | |
1604 | + res++; | |
1605 | + } | |
1606 | + | |
1607 | + return res; | |
1608 | +} | |
1609 | + | |
1586 | 1610 | static int qcow_create2(const char *filename, int64_t total_size, |
1587 | 1611 | const char *backing_file, const char *backing_format, |
1588 | - int flags) | |
1612 | + int flags, size_t cluster_size) | |
1589 | 1613 | { |
1590 | 1614 | |
1591 | 1615 | int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; |
... | ... | @@ -1619,8 +1643,20 @@ static int qcow_create2(const char *filename, int64_t total_size, |
1619 | 1643 | header.backing_file_size = cpu_to_be32(backing_filename_len); |
1620 | 1644 | header_size += backing_filename_len; |
1621 | 1645 | } |
1622 | - s->cluster_bits = 12; /* 4 KB clusters */ | |
1646 | + | |
1647 | + /* Cluster size */ | |
1648 | + s->cluster_bits = get_bits_from_size(cluster_size); | |
1649 | + if (s->cluster_bits < MIN_CLUSTER_BITS || | |
1650 | + s->cluster_bits > MAX_CLUSTER_BITS) | |
1651 | + { | |
1652 | + fprintf(stderr, "Cluster size must be a power of two between " | |
1653 | + "%d and %dk\n", | |
1654 | + 1 << MIN_CLUSTER_BITS, | |
1655 | + 1 << (MAX_CLUSTER_BITS - 10)); | |
1656 | + return -EINVAL; | |
1657 | + } | |
1623 | 1658 | s->cluster_size = 1 << s->cluster_bits; |
1659 | + | |
1624 | 1660 | header.cluster_bits = cpu_to_be32(s->cluster_bits); |
1625 | 1661 | header_size = (header_size + 7) & ~7; |
1626 | 1662 | if (flags & BLOCK_FLAG_ENCRYPT) { |
... | ... | @@ -1702,6 +1738,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) |
1702 | 1738 | const char *backing_fmt = NULL; |
1703 | 1739 | uint64_t sectors = 0; |
1704 | 1740 | int flags = 0; |
1741 | + size_t cluster_size = 4096; | |
1705 | 1742 | |
1706 | 1743 | /* Read out options */ |
1707 | 1744 | while (options && options->name) { |
... | ... | @@ -1713,11 +1750,16 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) |
1713 | 1750 | backing_fmt = options->value.s; |
1714 | 1751 | } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) { |
1715 | 1752 | flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0; |
1753 | + } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { | |
1754 | + if (options->value.n) { | |
1755 | + cluster_size = options->value.n; | |
1756 | + } | |
1716 | 1757 | } |
1717 | 1758 | options++; |
1718 | 1759 | } |
1719 | 1760 | |
1720 | - return qcow_create2(filename, sectors, backing_file, backing_fmt, flags); | |
1761 | + return qcow_create2(filename, sectors, backing_file, backing_fmt, flags, | |
1762 | + cluster_size); | |
1721 | 1763 | } |
1722 | 1764 | |
1723 | 1765 | static int qcow_make_empty(BlockDriverState *bs) |
... | ... | @@ -2920,6 +2962,7 @@ static QEMUOptionParameter qcow_create_options[] = { |
2920 | 2962 | { BLOCK_OPT_BACKING_FILE, OPT_STRING }, |
2921 | 2963 | { BLOCK_OPT_BACKING_FMT, OPT_STRING }, |
2922 | 2964 | { BLOCK_OPT_ENCRYPT, OPT_FLAG }, |
2965 | + { BLOCK_OPT_CLUSTER_SIZE, OPT_SIZE }, | |
2923 | 2966 | { NULL } |
2924 | 2967 | }; |
2925 | 2968 | ... | ... |
block_int.h
... | ... | @@ -36,6 +36,7 @@ |
36 | 36 | #define BLOCK_OPT_COMPAT6 "compat6" |
37 | 37 | #define BLOCK_OPT_BACKING_FILE "backing_file" |
38 | 38 | #define BLOCK_OPT_BACKING_FMT "backing_fmt" |
39 | +#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" | |
39 | 40 | |
40 | 41 | typedef struct AIOPool { |
41 | 42 | void (*cancel)(BlockDriverAIOCB *acb); | ... | ... |