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,6 +62,9 @@ | ||
62 | 62 | ||
63 | #define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */ | 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 | typedef struct QCowHeader { | 68 | typedef struct QCowHeader { |
66 | uint32_t magic; | 69 | uint32_t magic; |
67 | uint32_t version; | 70 | uint32_t version; |
@@ -300,8 +303,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) | @@ -300,8 +303,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) | ||
300 | if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) | 303 | if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) |
301 | goto fail; | 304 | goto fail; |
302 | if (header.size <= 1 || | 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 | goto fail; | 308 | goto fail; |
306 | if (header.crypt_method > QCOW_CRYPT_AES) | 309 | if (header.crypt_method > QCOW_CRYPT_AES) |
307 | goto fail; | 310 | goto fail; |
@@ -1583,9 +1586,30 @@ static void create_refcount_update(QCowCreateState *s, | @@ -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 | static int qcow_create2(const char *filename, int64_t total_size, | 1610 | static int qcow_create2(const char *filename, int64_t total_size, |
1587 | const char *backing_file, const char *backing_format, | 1611 | const char *backing_file, const char *backing_format, |
1588 | - int flags) | 1612 | + int flags, size_t cluster_size) |
1589 | { | 1613 | { |
1590 | 1614 | ||
1591 | int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; | 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,8 +1643,20 @@ static int qcow_create2(const char *filename, int64_t total_size, | ||
1619 | header.backing_file_size = cpu_to_be32(backing_filename_len); | 1643 | header.backing_file_size = cpu_to_be32(backing_filename_len); |
1620 | header_size += backing_filename_len; | 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 | s->cluster_size = 1 << s->cluster_bits; | 1658 | s->cluster_size = 1 << s->cluster_bits; |
1659 | + | ||
1624 | header.cluster_bits = cpu_to_be32(s->cluster_bits); | 1660 | header.cluster_bits = cpu_to_be32(s->cluster_bits); |
1625 | header_size = (header_size + 7) & ~7; | 1661 | header_size = (header_size + 7) & ~7; |
1626 | if (flags & BLOCK_FLAG_ENCRYPT) { | 1662 | if (flags & BLOCK_FLAG_ENCRYPT) { |
@@ -1702,6 +1738,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) | @@ -1702,6 +1738,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) | ||
1702 | const char *backing_fmt = NULL; | 1738 | const char *backing_fmt = NULL; |
1703 | uint64_t sectors = 0; | 1739 | uint64_t sectors = 0; |
1704 | int flags = 0; | 1740 | int flags = 0; |
1741 | + size_t cluster_size = 4096; | ||
1705 | 1742 | ||
1706 | /* Read out options */ | 1743 | /* Read out options */ |
1707 | while (options && options->name) { | 1744 | while (options && options->name) { |
@@ -1713,11 +1750,16 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) | @@ -1713,11 +1750,16 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) | ||
1713 | backing_fmt = options->value.s; | 1750 | backing_fmt = options->value.s; |
1714 | } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) { | 1751 | } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) { |
1715 | flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0; | 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 | options++; | 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 | static int qcow_make_empty(BlockDriverState *bs) | 1765 | static int qcow_make_empty(BlockDriverState *bs) |
@@ -2920,6 +2962,7 @@ static QEMUOptionParameter qcow_create_options[] = { | @@ -2920,6 +2962,7 @@ static QEMUOptionParameter qcow_create_options[] = { | ||
2920 | { BLOCK_OPT_BACKING_FILE, OPT_STRING }, | 2962 | { BLOCK_OPT_BACKING_FILE, OPT_STRING }, |
2921 | { BLOCK_OPT_BACKING_FMT, OPT_STRING }, | 2963 | { BLOCK_OPT_BACKING_FMT, OPT_STRING }, |
2922 | { BLOCK_OPT_ENCRYPT, OPT_FLAG }, | 2964 | { BLOCK_OPT_ENCRYPT, OPT_FLAG }, |
2965 | + { BLOCK_OPT_CLUSTER_SIZE, OPT_SIZE }, | ||
2923 | { NULL } | 2966 | { NULL } |
2924 | }; | 2967 | }; |
2925 | 2968 |
block_int.h
@@ -36,6 +36,7 @@ | @@ -36,6 +36,7 @@ | ||
36 | #define BLOCK_OPT_COMPAT6 "compat6" | 36 | #define BLOCK_OPT_COMPAT6 "compat6" |
37 | #define BLOCK_OPT_BACKING_FILE "backing_file" | 37 | #define BLOCK_OPT_BACKING_FILE "backing_file" |
38 | #define BLOCK_OPT_BACKING_FMT "backing_fmt" | 38 | #define BLOCK_OPT_BACKING_FMT "backing_fmt" |
39 | +#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" | ||
39 | 40 | ||
40 | typedef struct AIOPool { | 41 | typedef struct AIOPool { |
41 | void (*cancel)(BlockDriverAIOCB *acb); | 42 | void (*cancel)(BlockDriverAIOCB *acb); |