[libvirt] [PATCH v5 2/5] conf: add features to volume target XML

Ján Tomko jtomko at redhat.com
Wed Jun 19 15:24:11 UTC 2013


Add <features> and <compat> elements to volume target XML.

<compat> is a string which for qcow2 represents the QEMU version
it should be compatible with. Valid values are 0.10 and 1.1.
1.1 is implicit if the <features> element is present, otherwise
qemu-img default is used. 0.10 can be specified to explicitly
create older images after the qemu-img default changes.

<features> contains optional features, so far
<lazy_refcounts/> is available, which enables caching of reference
counters, improving performance for snapshots.
---
 docs/formatstorage.html.in                    | 20 +++++++
 docs/schemas/Makefile.am                      |  1 +
 docs/schemas/storagefilefeatures.rng          | 24 +++++++++
 docs/schemas/storagevol.rng                   |  7 +++
 libvirt.spec.in                               |  1 +
 mingw-libvirt.spec.in                         |  2 +
 src/conf/storage_conf.c                       | 78 +++++++++++++++++++++++++++
 src/conf/storage_conf.h                       |  7 ++-
 src/libvirt_private.syms                      |  2 +
 src/storage/storage_backend_fs.c              | 10 ++++
 tests/storagevolxml2xmlin/vol-qcow2-1.1.xml   | 32 +++++++++++
 tests/storagevolxml2xmlin/vol-qcow2-lazy.xml  | 35 ++++++++++++
 tests/storagevolxml2xmlout/vol-qcow2-1.1.xml  | 33 ++++++++++++
 tests/storagevolxml2xmlout/vol-qcow2-lazy.xml | 35 ++++++++++++
 tests/storagevolxml2xmltest.c                 |  2 +
 15 files changed, 287 insertions(+), 2 deletions(-)
 create mode 100644 docs/schemas/storagefilefeatures.rng
 create mode 100644 tests/storagevolxml2xmlin/vol-qcow2-1.1.xml
 create mode 100644 tests/storagevolxml2xmlin/vol-qcow2-lazy.xml
 create mode 100644 tests/storagevolxml2xmlout/vol-qcow2-1.1.xml
 create mode 100644 tests/storagevolxml2xmlout/vol-qcow2-lazy.xml

diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in
index 1a45915..c1c1b15 100644
--- a/docs/formatstorage.html.in
+++ b/docs/formatstorage.html.in
@@ -334,6 +334,10 @@
             <mode>0744</mode>
             <label>virt_image_t</label>
           </permissions>
+          <compat>1.1</compat>
+          <features>
+            <lazy_refcounts/>
+          </features>
         </target></pre>
 
     <dl>
@@ -362,6 +366,22 @@
         contains the MAC (eg SELinux) label string.
         <span class="since">Since 0.4.1</span>
       </dd>
+      <dt><code>compat</code></dt>
+      <dd>Specify compatibility level. So far, this is only used for
+        <code>type='qcow2'</code> volumes. Valid values are <code>0.10</code>
+        and <code>1.1</code> so far, specifying QEMU version the images should
+        be compatible with. If the <code>feature</code> element is present,
+        1.1 is used. If omitted, qemu-img default is used.
+        <span class="since">Since 1.0.7</span>
+      </dd>
+      <dt><code>features</code></dt>
+      <dd>Format-specific features. Only used for <code>qcow2</code> now.
+        Valid sub-elements are:
+        <ul>
+          <li><code><lazy_refcounts/></code> - allow delayed reference
+          counter updates. <span class="since">Since 1.0.7</span></li>
+        </ul>
+      </dd>
     </dl>
 
     <h3><a name="StorageVolBacking">Backing store elements</a></h3>
diff --git a/docs/schemas/Makefile.am b/docs/schemas/Makefile.am
index 8da2c67..47d1941 100644
--- a/docs/schemas/Makefile.am
+++ b/docs/schemas/Makefile.am
@@ -28,6 +28,7 @@ schema_DATA = \
 	nwfilter.rng \
 	secret.rng \
 	storageencryption.rng \
+	storagefilefeatures.rng \
 	storagepool.rng \
 	storagevol.rng
 
diff --git a/docs/schemas/storagefilefeatures.rng b/docs/schemas/storagefilefeatures.rng
new file mode 100644
index 0000000..424b4e2
--- /dev/null
+++ b/docs/schemas/storagefilefeatures.rng
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- A Relax NG schema for the libvirt volume features XML format -->
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+    datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+
+  <define name='compat'>
+    <element name='compat'>
+      <data type='string'>
+        <param name='pattern'>[0-9]+\.[0-9]+</param>
+      </data>
+    </element>
+  </define>
+  <define name='fileFormatFeatures'>
+    <element name='features'>
+      <interleave>
+        <optional>
+          <element name='lazy_refcounts'>
+            <empty/>
+          </element>
+        </optional>
+      </interleave>
+    </element>
+  </define>
+</grammar>
diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng
index 4649d91..8bc5907 100644
--- a/docs/schemas/storagevol.rng
+++ b/docs/schemas/storagevol.rng
@@ -8,6 +8,7 @@
   </start>
 
   <include href='storageencryption.rng'/>
+  <include href='storagefilefeatures.rng'/>
 
 
   <define name='vol'>
@@ -113,6 +114,12 @@
       <optional>
         <ref name='encryption'/>
       </optional>
+      <optional>
+        <ref name='compat'/>
+      </optional>
+      <optional>
+        <ref name='fileFormatFeatures'/>
+      </optional>
     </element>
   </define>
 
diff --git a/libvirt.spec.in b/libvirt.spec.in
index e357a3d..a0a390e 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -2006,6 +2006,7 @@ fi
 %{_datadir}/libvirt/schemas/nwfilter.rng
 %{_datadir}/libvirt/schemas/secret.rng
 %{_datadir}/libvirt/schemas/storageencryption.rng
+%{_datadir}/libvirt/schemas/storagefilefeatures.rng
 %{_datadir}/libvirt/schemas/storagepool.rng
 %{_datadir}/libvirt/schemas/storagevol.rng
 
diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in
index 9208329..aa39231 100644
--- a/mingw-libvirt.spec.in
+++ b/mingw-libvirt.spec.in
@@ -213,6 +213,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
 %{mingw32_datadir}/libvirt/schemas/nwfilter.rng
 %{mingw32_datadir}/libvirt/schemas/secret.rng
 %{mingw32_datadir}/libvirt/schemas/storageencryption.rng
+%{mingw32_datadir}/libvirt/schemas/storagefilefeatures.rng
 %{mingw32_datadir}/libvirt/schemas/storagepool.rng
 %{mingw32_datadir}/libvirt/schemas/storagevol.rng
 %dir %{mingw32_datadir}/libvirt/api/
@@ -273,6 +274,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
 %{mingw64_datadir}/libvirt/schemas/nwfilter.rng
 %{mingw64_datadir}/libvirt/schemas/secret.rng
 %{mingw64_datadir}/libvirt/schemas/storageencryption.rng
+%{mingw64_datadir}/libvirt/schemas/storagefilefeatures.rng
 %{mingw64_datadir}/libvirt/schemas/storagepool.rng
 %{mingw64_datadir}/libvirt/schemas/storagevol.rng
 %dir %{mingw64_datadir}/libvirt/api/
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index c58b728..288e265 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -97,6 +97,8 @@ VIR_ENUM_IMPL(virStoragePoolSourceAdapterType,
 
 typedef const char *(*virStorageVolFormatToString)(int format);
 typedef int (*virStorageVolFormatFromString)(const char *format);
+typedef const char *(*virStorageVolFeatureToString)(int feature);
+typedef int (*virStorageVolFeatureFromString)(const char *feature);
 
 typedef const char *(*virStoragePoolFormatToString)(int format);
 typedef int (*virStoragePoolFormatFromString)(const char *format);
@@ -107,6 +109,8 @@ struct _virStorageVolOptions {
     int defaultFormat;
     virStorageVolFormatToString formatToString;
     virStorageVolFormatFromString formatFromString;
+    virStorageVolFeatureToString featureToString;
+    virStorageVolFeatureFromString featureFromString;
 };
 
 /* Flags to indicate mandatory components in the pool source */
@@ -161,6 +165,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
          .defaultFormat = VIR_STORAGE_FILE_RAW,
          .formatFromString = virStorageVolumeFormatFromString,
          .formatToString = virStorageFileFormatTypeToString,
+         .featureFromString = virStorageFileFeatureTypeFromString,
+         .featureToString = virStorageFileFeatureTypeToString,
      },
     },
     {.poolType = VIR_STORAGE_POOL_FS,
@@ -174,6 +180,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
          .defaultFormat = VIR_STORAGE_FILE_RAW,
          .formatFromString = virStorageVolumeFormatFromString,
          .formatToString = virStorageFileFormatTypeToString,
+         .featureFromString = virStorageFileFeatureTypeFromString,
+         .featureToString = virStorageFileFeatureTypeToString,
       },
     },
     {.poolType = VIR_STORAGE_POOL_NETFS,
@@ -188,6 +196,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
          .defaultFormat = VIR_STORAGE_FILE_RAW,
          .formatFromString = virStorageVolumeFormatFromString,
          .formatToString = virStorageFileFormatTypeToString,
+         .featureFromString = virStorageFileFeatureTypeFromString,
+         .featureToString = virStorageFileFeatureTypeToString,
       },
     },
     {.poolType = VIR_STORAGE_POOL_ISCSI,
@@ -299,6 +309,8 @@ virStorageVolDefFree(virStorageVolDefPtr def)
     }
     VIR_FREE(def->source.extents);
 
+    VIR_FREE(def->target.compat);
+    virBitmapFree(def->target.features);
     VIR_FREE(def->target.path);
     VIR_FREE(def->target.perms.label);
     VIR_FREE(def->target.timestamps);
@@ -1248,6 +1260,8 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool,
     char *capacity = NULL;
     char *unit = NULL;
     xmlNodePtr node;
+    xmlNodePtr *nodes = NULL;
+    int i, n;
 
     options = virStorageVolOptionsForPoolType(pool->type);
     if (options == NULL)
@@ -1335,17 +1349,59 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool,
         VIR_FREE(format);
     }
 
+    ret->target.compat = virXPathString("string(./target/compat)", ctxt);
+    if (ret->target.compat) {
+        char **version = virStringSplit(ret->target.compat, ".", 2);
+        unsigned int result;
+
+        if (!version || !version[1] ||
+            virStrToLong_ui(version[0], NULL, 10, &result) < 0 ||
+            virStrToLong_ui(version[1], NULL, 10, &result) < 0) {
+            virStringFreeList(version);
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("forbidden characters in 'compat' attribute"));
+            goto error;
+        }
+        virStringFreeList(version);
+    }
+
+    if (options->featureFromString && virXPathNode("./target/features", ctxt)) {
+        if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
+            goto error;
+
+        if (!ret->target.compat && VIR_STRDUP(ret->target.compat, "1.1") < 0)
+            goto error;
+
+        if (!(ret->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
+            goto no_memory;
+
+        for (i = 0; i < n; i++) {
+            int f = options->featureFromString((const char*)nodes[i]->name);
+
+            if (f < 0) {
+                virReportError(VIR_ERR_XML_ERROR, _("unsupported feature %s"),
+                               (const char*)nodes[i]->name);
+                goto error;
+            }
+            ignore_value(virBitmapSetBit(ret->target.features, f));
+        }
+        VIR_FREE(nodes);
+    }
+
     if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
                                 "./backingStore/permissions",
                                 DEFAULT_VOL_PERM_MODE) < 0)
         goto error;
 
 cleanup:
+    VIR_FREE(nodes);
     VIR_FREE(allocation);
     VIR_FREE(capacity);
     VIR_FREE(unit);
     return ret;
 
+no_memory:
+    virReportOOMError();
 error:
     virStorageVolDefFree(ret);
     ret = NULL;
@@ -1476,6 +1532,28 @@ virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
         virBufferAdjustIndent(buf, -4);
     }
 
+    virBufferEscapeString(buf, "    <compat>%s</compat>\n", def->compat);
+
+    if (options->featureToString && def->features) {
+        int i;
+        bool b;
+        bool empty = virBitmapIsAllClear(def->features);
+
+        if (empty)
+            virBufferAddLit(buf, "    <features/>\n");
+        else
+            virBufferAddLit(buf, "    <features>\n");
+
+        for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
+            ignore_value(virBitmapGetBit(def->features, i, &b));
+            if (b)
+                virBufferAsprintf(buf, "      <%s/>\n",
+                                  options->featureToString(i));
+        }
+        if (!empty)
+            virBufferAddLit(buf, "    </features>\n");
+    }
+
     virBufferAsprintf(buf, "  </%s>\n", type);
 
     return 0;
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 8e739ff..3af59df 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -26,6 +26,7 @@
 
 # include "internal.h"
 # include "storage_encryption_conf.h"
+# include "virbitmap.h"
 # include "virthread.h"
 
 # include <libxml/tree.h>
@@ -84,9 +85,11 @@ struct _virStorageVolTarget {
     virStoragePerms perms;
     virStorageTimestampsPtr timestamps;
     int type; /* only used by disk backend for partition type */
-
-    /* only used in vol->target, not in vol->backingstore. */
+    /* The next three are currently only used in vol->target,
+     * not in vol->backingStore. */
     virStorageEncryptionPtr encryption;
+    virBitmapPtr features;
+    char *compat;
 };
 
 typedef struct _virStorageVolDef virStorageVolDef;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b449293..7ac6fdc 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1799,6 +1799,8 @@ virSocketAddrSetPort;
 
 # util/virstoragefile.h
 virStorageFileChainLookup;
+virStorageFileFeatureTypeFromString;
+virStorageFileFeatureTypeToString;
 virStorageFileFormatTypeFromString;
 virStorageFileFormatTypeToString;
 virStorageFileFreeMetadata;
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index b1efa50..3598d83 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -150,6 +150,16 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
          */
     }
 
+    virBitmapFree(target->features);
+    target->features = meta->features;
+    meta->features = NULL;
+
+    if (meta->compat) {
+        VIR_FREE(target->compat);
+        target->compat = meta->compat;
+        meta->compat = NULL;
+    }
+
     virStorageFileFreeMetadata(meta);
 
     return ret;
diff --git a/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml b/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml
new file mode 100644
index 0000000..e8df8b3
--- /dev/null
+++ b/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml
@@ -0,0 +1,32 @@
+<volume>
+  <name>OtherDemo.img</name>
+  <key>/var/lib/libvirt/images/OtherDemo.img</key>
+  <source>
+  </source>
+  <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>
+    <encryption format='qcow'>
+      <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709a80f4'/>
+    </encryption>
+    <features/>
+  </target>
+  <backingStore>
+    <path>/var/lib/libvirt/images/BaseDemo.img</path>
+    <format type='raw'/>
+    <permissions>
+      <mode>0644</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
+    </permissions>
+  </backingStore>
+</volume>
diff --git a/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml b/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml
new file mode 100644
index 0000000..336342a
--- /dev/null
+++ b/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml
@@ -0,0 +1,35 @@
+<volume>
+  <name>OtherDemo.img</name>
+  <key>/var/lib/libvirt/images/OtherDemo.img</key>
+  <source>
+  </source>
+  <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>
+    <encryption format='qcow'>
+      <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709a80f4'/>
+    </encryption>
+    <compat>1.1</compat>
+    <features>
+      <lazy_refcounts/>
+    </features>
+  </target>
+  <backingStore>
+    <path>/var/lib/libvirt/images/BaseDemo.img</path>
+    <format type='raw'/>
+    <permissions>
+      <mode>0644</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
+    </permissions>
+  </backingStore>
+</volume>
diff --git a/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml b/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml
new file mode 100644
index 0000000..454ac11
--- /dev/null
+++ b/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml
@@ -0,0 +1,33 @@
+<volume>
+  <name>OtherDemo.img</name>
+  <key>(null)</key>
+  <source>
+  </source>
+  <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>
+    <encryption format='qcow'>
+      <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709a80f4'/>
+    </encryption>
+    <compat>1.1</compat>
+    <features/>
+  </target>
+  <backingStore>
+    <path>/var/lib/libvirt/images/BaseDemo.img</path>
+    <format type='raw'/>
+    <permissions>
+      <mode>0644</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
+    </permissions>
+  </backingStore>
+</volume>
diff --git a/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml b/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml
new file mode 100644
index 0000000..4e30ede
--- /dev/null
+++ b/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml
@@ -0,0 +1,35 @@
+<volume>
+  <name>OtherDemo.img</name>
+  <key>(null)</key>
+  <source>
+  </source>
+  <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>
+    <encryption format='qcow'>
+      <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709a80f4'/>
+    </encryption>
+    <compat>1.1</compat>
+    <features>
+      <lazy_refcounts/>
+    </features>
+  </target>
+  <backingStore>
+    <path>/var/lib/libvirt/images/BaseDemo.img</path>
+    <format type='raw'/>
+    <permissions>
+      <mode>0644</mode>
+      <owner>0</owner>
+      <group>0</group>
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
+    </permissions>
+  </backingStore>
+</volume>
diff --git a/tests/storagevolxml2xmltest.c b/tests/storagevolxml2xmltest.c
index 07c79c1..e87b016 100644
--- a/tests/storagevolxml2xmltest.c
+++ b/tests/storagevolxml2xmltest.c
@@ -110,6 +110,8 @@ mymain(void)
     DO_TEST("pool-dir", "vol-file");
     DO_TEST("pool-dir", "vol-file-backing");
     DO_TEST("pool-dir", "vol-qcow2");
+    DO_TEST("pool-dir", "vol-qcow2-1.1");
+    DO_TEST("pool-dir", "vol-qcow2-lazy");
     DO_TEST("pool-disk", "vol-partition");
     DO_TEST("pool-logical", "vol-logical");
     DO_TEST("pool-logical", "vol-logical-backing");
-- 
1.8.1.5




More information about the libvir-list mailing list