]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
storage: add support for QCOW2 cluster_size option
authorPavel Hrdina <phrdina@redhat.com>
Wed, 12 May 2021 15:43:36 +0000 (17:43 +0200)
committerPavel Hrdina <phrdina@redhat.com>
Fri, 21 May 2021 12:00:43 +0000 (14:00 +0200)
The default value hard-coded in QEMU (64KiB) is not always the ideal.
Having a possibility to set the cluster_size by user may in specific
use-cases improve performance for QCOW2 images.

QEMU internally has some limits, the value has to be between 512B and
2048KiB and must by power of two, except when the image has Extended L2
Entries the minimal value has to be 16KiB.

Since qemu-img ensures the value is correct and the limit is not always
the same libvirt will not duplicate any of these checks as the error
message from qemu-img is good enough:

    Cluster size must be a power of two between 512 and 2048k

Resolves: https://gitlab.com/libvirt/libvirt/-/issues/154

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
docs/formatstorage.html.in
docs/schemas/storagecommon.rng
docs/schemas/storagevol.rng
src/conf/storage_conf.c
src/storage/storage_util.c
tests/storagevolxml2argvdata/qcow2-clusterSize.argv [new file with mode: 0644]
tests/storagevolxml2argvtest.c
tests/storagevolxml2xmlin/vol-qcow2-clusterSize.xml [new file with mode: 0644]
tests/storagevolxml2xmlout/vol-qcow2-clusterSize.xml [new file with mode: 0644]
tests/storagevolxml2xmltest.c

index cac44503da4a1b844e0fb62a52575f02556e50e2..9ee5b89ee6eb19b8c83d0e77a004d8ee87aaced9 100644 (file)
   &lt;/encryption&gt;
   &lt;compat&gt;1.1&lt;/compat&gt;
   &lt;nocow/&gt;
+  &lt;clusterSize unit='KiB'&gt;64&lt;/clusterSize&gt;
   &lt;features&gt;
     &lt;lazy_refcounts/&gt;
   &lt;/features&gt;
         the file image is used in VM. To create non-raw file images, it
         requires QEMU version since 2.1. <span class="since">Since 1.2.7</span>
       </dd>
+      <dt><code>clusterSize</code></dt>
+      <dd>Changes the qcow2 cluster size which can affect image file size
+        and performance.
+        <span class="since">Since 7.4.0</span>
+      </dd>
       <dt><code>features</code></dt>
       <dd>Format-specific features. Only used for <code>qcow2</code> now.
         Valid sub-elements are:
index e3d08a8410f9c27c65b54d5694dd09b0a78fa083..9ebb27700d5c75792d1cdf8d5827949830d21f91 100644 (file)
       </data>
     </element>
   </define>
+
+  <define name="clusterSize">
+    <element name="clusterSize">
+      <ref name="scaledInteger"/>
+    </element>
+  </define>
+
   <define name="fileFormatFeatures">
     <element name="features">
       <interleave>
index 22ce5eaa8d0b4a28e171fe91ed7df3b233551e45..3e0f482007f6af0e3c62dbee4e83e89806bcbb6a 100644 (file)
             <empty/>
           </element>
         </optional>
+        <optional>
+          <ref name="clusterSize"/>
+        </optional>
         <optional>
           <ref name="fileFormatFeatures"/>
         </optional>
index e481cac75c07b73a13675b1f1fbb63c363f61c0e..0ecdb0969a3a8ece89754e681bfec441e10d9f09 100644 (file)
@@ -1416,6 +1416,13 @@ virStorageVolDefParseXML(virStoragePoolDef *pool,
     if (virXPathNode("./target/nocow", ctxt))
         def->target.nocow = true;
 
+    if (virParseScaledValue("./target/clusterSize",
+                            "./target/clusterSize/@unit",
+                            ctxt, &def->target.clusterSize,
+                            1, ULLONG_MAX, false) < 0) {
+        return NULL;
+    }
+
     if (virXPathNode("./target/features", ctxt)) {
         if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
             return NULL;
@@ -1580,6 +1587,11 @@ virStorageVolTargetDefFormat(virStorageVolOptions *options,
 
     virBufferEscapeString(buf, "<compat>%s</compat>\n", def->compat);
 
+    if (def->clusterSize > 0) {
+        virBufferAsprintf(buf, "<clusterSize unit='B'>%llu</clusterSize>\n",
+                          def->clusterSize);
+    }
+
     if (def->features) {
         size_t i;
         bool empty = virBitmapIsAllClear(def->features);
index 2b0d08c65d7f74b78daf69129326384be9665fdf..c8299852a33447778bf26a547db0683abc8967b0 100644 (file)
@@ -664,6 +664,7 @@ struct _virStorageBackendQemuImgInfo {
     const char *path;
     unsigned long long size_arg;
     unsigned long long allocation;
+    unsigned long long clusterSize;
     bool encryption;
     bool preallocate;
     const char *compat;
@@ -780,6 +781,9 @@ storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDef *encinfo,
     else if (info->format == VIR_STORAGE_FILE_QCOW2)
         virBufferAddLit(&buf, "compat=0.10,");
 
+    if (info->clusterSize > 0)
+        virBufferAsprintf(&buf, "cluster_size=%llu,", info->clusterSize);
+
     if (info->features && info->format == VIR_STORAGE_FILE_QCOW2) {
         if (virBitmapIsBitSet(info->features,
                               VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS)) {
@@ -1130,6 +1134,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObj *pool,
         .compat = vol->target.compat,
         .features = vol->target.features,
         .nocow = vol->target.nocow,
+        .clusterSize = vol->target.clusterSize,
         .secretAlias = NULL,
     };
     virStorageEncryption *enc = vol->target.encryption;
diff --git a/tests/storagevolxml2argvdata/qcow2-clusterSize.argv b/tests/storagevolxml2argvdata/qcow2-clusterSize.argv
new file mode 100644 (file)
index 0000000..8878a26
--- /dev/null
@@ -0,0 +1,6 @@
+qemu-img \
+create \
+-f qcow2 \
+-o compat=0.10,cluster_size=131072 \
+/var/lib/libvirt/images/OtherDemo.img \
+5242880K
index 6058d2b689209317c9e149ebb842271a86667100..9597509f000d554afba4d6b89e9d8c6156453212 100644 (file)
@@ -238,6 +238,10 @@ mymain(void)
                  "pool-dir", "vol-qcow2-nocapacity-backing", NULL, NULL,
                  "qcow2-nocapacity", 0);
 
+    DO_TEST("pool-dir", "vol-qcow2-clusterSize",
+            NULL, NULL,
+            "qcow2-clusterSize", 0);
+
     DO_TEST("pool-dir", "vol-file-iso",
             NULL, NULL,
             "iso", 0);
diff --git a/tests/storagevolxml2xmlin/vol-qcow2-clusterSize.xml b/tests/storagevolxml2xmlin/vol-qcow2-clusterSize.xml
new file mode 100644 (file)
index 0000000..2253498
--- /dev/null
@@ -0,0 +1,17 @@
+<volume>
+  <name>OtherDemo.img</name>
+  <key>/var/lib/libvirt/images/OtherDemo.img</key>
+  <capacity unit="G">5</capacity>
+  <allocation>294912</allocation>
+  <target>
+    <path>/var/lib/libvirt/images/OtherDemo.img</path>
+    <format type='qcow2'/>
+    <permissions>
+      <mode>0644</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
+    </permissions>
+    <clusterSize unit='KiB'>128</clusterSize>
+  </target>
+</volume>
diff --git a/tests/storagevolxml2xmlout/vol-qcow2-clusterSize.xml b/tests/storagevolxml2xmlout/vol-qcow2-clusterSize.xml
new file mode 100644 (file)
index 0000000..393a492
--- /dev/null
@@ -0,0 +1,17 @@
+<volume type='file'>
+  <name>OtherDemo.img</name>
+  <key>/var/lib/libvirt/images/OtherDemo.img</key>
+  <capacity unit='bytes'>5368709120</capacity>
+  <allocation unit='bytes'>294912</allocation>
+  <target>
+    <path>/var/lib/libvirt/images/OtherDemo.img</path>
+    <format type='qcow2'/>
+    <permissions>
+      <mode>0644</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
+    </permissions>
+    <clusterSize unit='B'>131072</clusterSize>
+  </target>
+</volume>
index ed24d98426165302574dcc97ec4c9d1d4aecb11d..be38f50a511b19b9ffb9e7cbd22542d3e17b2f1f 100644 (file)
@@ -88,6 +88,7 @@ mymain(void)
     DO_TEST("pool-dir", "vol-qcow2-nobacking");
     DO_TEST("pool-dir", "vol-qcow2-encryption");
     DO_TEST("pool-dir", "vol-qcow2-luks");
+    DO_TEST("pool-dir", "vol-qcow2-clusterSize");
     DO_TEST("pool-dir", "vol-luks");
     DO_TEST("pool-dir", "vol-luks-cipher");
     DO_TEST("pool-disk", "vol-partition");