Commit 73c632edc4e28d0a8cae3b34abf7ae46fa33bf1e

Authored by Kevin Wolf
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);
... ...