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,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);