[PATCH v3 01/12] virstoragefile: Introduce virStoragePRDef

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a definition that holds information on SCSI persistent
reservation settings. The XML part looks like this:

  <reservations enabled='yes' managed='no'>
    <source type='unix' path='/path/to/qemu-pr-helper.sock' mode='client'/>
  </reservations>

If @managed is set to 'yes' then the <source/> is not parsed.
This design was agreed on here:

https://www.redhat.com/archives/libvir-list/2017-November/msg01005.html

Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx>
---
 docs/formatdomain.html.in                          |  25 +++-
 docs/schemas/domaincommon.rng                      |  34 +----
 docs/schemas/storagecommon.rng                     |  50 +++++++
 src/conf/domain_conf.c                             |  36 +++++
 src/libvirt_private.syms                           |   3 +
 src/util/virstoragefile.c                          | 148 +++++++++++++++++++++
 src/util/virstoragefile.h                          |  15 +++
 .../disk-virtio-scsi-reservations-not-managed.xml  |  41 ++++++
 .../disk-virtio-scsi-reservations.xml              |  39 ++++++
 .../disk-virtio-scsi-reservations-not-managed.xml  |   1 +
 .../disk-virtio-scsi-reservations.xml              |   1 +
 tests/qemuxml2xmltest.c                            |   4 +
 12 files changed, 366 insertions(+), 31 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/disk-virtio-scsi-reservations-not-managed.xml
 create mode 100644 tests/qemuxml2argvdata/disk-virtio-scsi-reservations.xml
 create mode 120000 tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations-not-managed.xml
 create mode 120000 tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 6fd2189cd..cbdc887a0 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2563,7 +2563,10 @@
   &lt;/disk&gt;
   &lt;disk type='block' device='lun'&gt;
     &lt;driver name='qemu' type='raw'/&gt;
-    &lt;source dev='/dev/sda'/&gt;
+    &lt;source dev='/dev/sda'&gt;
+      &lt;reservations enabled='yes' managed='no'&gt;
+        &lt;source type='unix' path='/path/to/qemu-pr-helper' mode='client'/&gt;
+      &lt;/reservations&gt;
     &lt;target dev='sda' bus='scsi'/&gt;
     &lt;address type='drive' controller='0' bus='0' target='3' unit='0'/&gt;
   &lt;/disk&gt;
@@ -2926,6 +2929,26 @@
             <a href="formatstorageencryption.html">Storage Encryption</a>
             page for more information.
           </dd>
+          <dt><code>reservations</code></dt>
+          <dd><span class="since">Since libvirt 4.1.0</span>, the
+            <code>reservations</code> can be a sub-element of the
+            <code>source</code> element for storage sources (QEMU driver only).
+            If present (and enabled) it enabled persistent reservations for
+            SCSI based disks. The element has one mandatory attribute
+            <code>enabled</code> with accepted values <code>yes</code> and
+            <code>no</code>. If the feature is enabled, then there's another
+            mandatory attribute <code>managed</code> (accepted values are the
+            same as for <code>enabled</code>) that enables or disables libvirt
+            spawning any helper process (should one be needed). However, if
+            libvirt is not enabled spawning helper process (i.e. hypervisor
+            should just use one which is already running), path to its socket
+            must be provided in child element <code>source</code>, which
+            currently accepts only the following attributes: <code>type</code>
+            with one value <code>unix</code>, <code>path</code> with path the
+            socket, and finally <code>mode</code> which accepts either
+            <code>server</code> or <code>client</code> and specifies the role
+            of hypervisor.
+          </dd>
         </dl>
 
         <p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 8165e699d..198d4400b 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1530,6 +1530,9 @@
         <optional>
           <ref name="encryption"/>
         </optional>
+        <optional>
+          <ref name="reservations"/>
+        </optional>
         <zeroOrMore>
           <ref name='devSeclabel'/>
         </zeroOrMore>
@@ -2431,18 +2434,6 @@
       </attribute>
     </optional>
   </define>
-  <define name="reconnect">
-    <element name="reconnect">
-      <attribute name="enabled">
-        <ref name="virYesNo"/>
-      </attribute>
-      <optional>
-        <attribute name="timeout">
-          <ref name="unsignedInt"/>
-        </attribute>
-      </optional>
-    </element>
-  </define>
 
   <!--
       An interface description can either be of type bridge in which case
@@ -2491,24 +2482,7 @@
             <value>vhostuser</value>
           </attribute>
           <interleave>
-            <element name="source">
-              <attribute name="type">
-                <value>unix</value>
-              </attribute>
-              <attribute name="path">
-                <ref name="absFilePath"/>
-              </attribute>
-              <attribute name="mode">
-                <choice>
-                  <value>server</value>
-                  <value>client</value>
-                </choice>
-              </attribute>
-              <optional>
-                 <ref name="reconnect"/>
-              </optional>
-              <empty/>
-            </element>
+            <ref name="unixSocketSource"/>
             <ref name="interface-options"/>
           </interleave>
         </group>
diff --git a/docs/schemas/storagecommon.rng b/docs/schemas/storagecommon.rng
index edee1b084..eed0b3334 100644
--- a/docs/schemas/storagecommon.rng
+++ b/docs/schemas/storagecommon.rng
@@ -39,6 +39,56 @@
     </element>
   </define>
 
+  <define name="reconnect">
+    <element name="reconnect">
+      <attribute name="enabled">
+        <ref name="virYesNo"/>
+      </attribute>
+      <optional>
+        <attribute name="timeout">
+          <ref name="unsignedInt"/>
+        </attribute>
+      </optional>
+    </element>
+  </define>
+
+  <define name='unixSocketSource'>
+    <element name="source">
+      <attribute name="type">
+        <value>unix</value>
+      </attribute>
+      <attribute name="path">
+        <ref name="absFilePath"/>
+      </attribute>
+      <attribute name="mode">
+        <choice>
+          <value>server</value>
+          <value>client</value>
+        </choice>
+      </attribute>
+      <optional>
+         <ref name="reconnect"/>
+      </optional>
+      <empty/>
+    </element>
+  </define>
+
+  <define name='reservations'>
+    <element name='reservations'>
+      <attribute name='enabled'>
+        <ref name='virYesNo'/>
+      </attribute>
+      <optional>
+        <attribute name='managed'>
+          <ref name='virYesNo'/>
+        </attribute>
+      </optional>
+      <optional>
+        <ref name='unixSocketSource'/>
+      </optional>
+    </element>
+  </define>
+
   <define name='secret'>
     <element name='secret'>
       <attribute name='type'>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 86fc27511..00b729fc2 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -5201,6 +5201,13 @@ virDomainDiskDefValidate(const virDomainDiskDef *disk)
         }
     }
 
+    if (disk->src->pr &&
+        disk->device != VIR_DOMAIN_DISK_DEVICE_LUN) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("<reservations/> allowed only for lun disks"));
+        return -1;
+    }
+
     /* Reject disks with a bus type that is not compatible with the
      * given address type. The function considers only buses that are
      * handled in common code. For other bus types it's not possible
@@ -8586,6 +8593,29 @@ virDomainDiskSourcePrivateDataParse(xmlNodePtr node,
 }
 
 
+static int
+virDomainDiskSourcePRParse(xmlNodePtr node,
+                           virStoragePRDefPtr *prsrc)
+{
+    xmlNodePtr child;
+    virStoragePRDefPtr pr = NULL;
+
+    for (child = node->children; child; child = child->next) {
+        if (child->type == XML_ELEMENT_NODE &&
+            virXMLNodeNameEqual(child, "reservations")) {
+
+            if (!(pr = virStoragePRDefParseNode(node->doc, child)))
+                return -1;
+
+            *prsrc = pr;
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+
 static int
 virDomainStorageSourceParse(xmlNodePtr node,
                             xmlXPathContextPtr ctxt,
@@ -8632,6 +8662,9 @@ virDomainStorageSourceParse(xmlNodePtr node,
         !(src->encryption = virStorageEncryptionParseNode(tmp, ctxt)))
         goto cleanup;
 
+    if (virDomainDiskSourcePRParse(node, &src->pr) < 0)
+        goto cleanup;
+
     if (virSecurityDeviceLabelDefParseXML(&src->seclabels, &src->nseclabels,
                                           ctxt, flags) < 0)
         goto cleanup;
@@ -22892,6 +22925,9 @@ virDomainStorageSourceFormat(virBufferPtr attrBuf,
         virStorageEncryptionFormat(childBuf, src->encryption) < 0)
         return -1;
 
+    if (src->pr)
+        virStoragePRDefFormat(childBuf, src->pr);
+
     return 0;
 }
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c67bce738..dd33895f9 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2782,6 +2782,9 @@ virStorageNetHostDefFree;
 virStorageNetHostTransportTypeFromString;
 virStorageNetHostTransportTypeToString;
 virStorageNetProtocolTypeToString;
+virStoragePRDefFormat;
+virStoragePRDefFree;
+virStoragePRDefParseNode;
 virStorageSourceBackingStoreClear;
 virStorageSourceClear;
 virStorageSourceCopy;
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index 67b9ec71a..2b5b48f00 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -1892,6 +1892,153 @@ virStorageAuthDefFormat(virBufferPtr buf,
 }
 
 
+void
+virStoragePRDefFree(virStoragePRDefPtr prd)
+{
+    if (!prd)
+        return;
+
+    VIR_FREE(prd->path);
+    VIR_FREE(prd);
+}
+
+
+static virStoragePRDefPtr
+virStoragePRDefParseXML(xmlXPathContextPtr ctxt)
+{
+    virStoragePRDefPtr prd, ret = NULL;
+    char *enabled = NULL;
+    char *managed = NULL;
+    char *type = NULL;
+    char *path = NULL;
+    char *mode = NULL;
+
+    if (VIR_ALLOC(prd) < 0)
+        return NULL;
+
+    if (!(enabled = virXPathString("string(./@enabled)", ctxt))) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("missing @enabled attribute for <reservations/>"));
+        goto cleanup;
+    }
+
+    if ((prd->enabled = virTristateBoolTypeFromString(enabled)) <= 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("invalid value for 'enabled': %s"), NULLSTR(enabled));
+        goto cleanup;
+    }
+
+    if (prd->enabled == VIR_TRISTATE_BOOL_YES) {
+        managed = virXPathString("string(./@managed)", ctxt);
+        if ((prd->managed = virTristateBoolTypeFromString(managed)) <= 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("invalid value for 'managed': %s"), NULLSTR(managed));
+            goto cleanup;
+        }
+
+        if (prd->managed == VIR_TRISTATE_BOOL_NO) {
+            type = virXPathString("string(./source[1]/@type)", ctxt);
+            path = virXPathString("string(./source[1]/@path)", ctxt);
+            mode = virXPathString("string(./source[1]/@mode)", ctxt);
+
+            if (!type) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("missing connection type"));
+                goto cleanup;
+            }
+
+            if (!path) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("missing path"));
+                goto cleanup;
+            }
+
+            if (!mode) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("missing connection mode"));
+                goto cleanup;
+            }
+
+            if (STRNEQ(type, "unix")) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("unsupported type: %s"), type);
+                goto cleanup;
+            }
+
+            if (STRNEQ(mode, "client")) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("unsupported mode: %s"),  mode);
+                goto cleanup;
+            }
+
+            prd->path = path;
+            path = NULL;
+
+        }
+    }
+
+    ret = prd;
+    prd = NULL;
+
+ cleanup:
+    VIR_FREE(mode);
+    VIR_FREE(path);
+    VIR_FREE(type);
+    VIR_FREE(managed);
+    VIR_FREE(enabled);
+    virStoragePRDefFree(prd);
+    return ret;
+}
+
+
+virStoragePRDefPtr
+virStoragePRDefParseNode(xmlDocPtr xml,
+                         xmlNodePtr root)
+{
+    xmlXPathContextPtr ctxt = NULL;
+    virStoragePRDefPtr prd = NULL;
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    ctxt->node = root;
+    prd = virStoragePRDefParseXML(ctxt);
+
+ cleanup:
+    xmlXPathFreeContext(ctxt);
+    return prd;
+}
+
+
+void
+virStoragePRDefFormat(virBufferPtr buf,
+                      virStoragePRDefPtr prd)
+{
+    virBufferAsprintf(buf, "<reservations enabled='%s'",
+                      virTristateBoolTypeToString(prd->enabled));
+    if (prd->enabled == VIR_TRISTATE_BOOL_YES) {
+        virBufferAsprintf(buf, " managed='%s'",
+                          virTristateBoolTypeToString(prd->managed));
+        if (prd->managed == VIR_TRISTATE_BOOL_NO) {
+            virBufferAddLit(buf, ">\n");
+            virBufferAdjustIndent(buf, 2);
+            virBufferAddLit(buf, "<source type='unix'");
+            virBufferEscapeString(buf, " path='%s'", prd->path);
+            virBufferAddLit(buf, " mode='client'/>\n");
+            virBufferAdjustIndent(buf, -2);
+            virBufferAddLit(buf, "</reservations>\n");
+        } else {
+            virBufferAddLit(buf, "/>\n");
+        }
+    } else {
+        virBufferAddLit(buf, "/>\n");
+    }
+}
+
+
 virSecurityDeviceLabelDefPtr
 virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
                                     const char *model)
@@ -2270,6 +2417,7 @@ virStorageSourceClear(virStorageSourcePtr def)
     virBitmapFree(def->features);
     VIR_FREE(def->compat);
     virStorageEncryptionFree(def->encryption);
+    virStoragePRDefFree(def->pr);
     virStorageSourceSeclabelsClear(def);
     virStoragePermsFree(def->perms);
     VIR_FREE(def->timestamps);
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 596746ccb..69fea34bc 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -216,6 +216,14 @@ struct _virStorageAuthDef {
     virSecretLookupTypeDef seclookupdef;
 };
 
+typedef struct _virStoragePRDef virStoragePRDef;
+typedef virStoragePRDef *virStoragePRDefPtr;
+struct _virStoragePRDef {
+    int enabled; /* enum virTristateBool */
+    int managed; /* enum virTristateBool */
+    char *path;
+};
+
 typedef struct _virStorageDriverData virStorageDriverData;
 typedef virStorageDriverData *virStorageDriverDataPtr;
 
@@ -243,6 +251,7 @@ struct _virStorageSource {
     bool authInherited;
     virStorageEncryptionPtr encryption;
     bool encryptionInherited;
+    virStoragePRDefPtr pr;
 
     virObjectPtr privateData;
 
@@ -370,6 +379,12 @@ virStorageAuthDefPtr virStorageAuthDefParse(xmlNodePtr node,
                                             xmlXPathContextPtr ctxt);
 void virStorageAuthDefFormat(virBufferPtr buf, virStorageAuthDefPtr authdef);
 
+void virStoragePRDefFree(virStoragePRDefPtr prd);
+virStoragePRDefPtr virStoragePRDefParseNode(xmlDocPtr xml,
+                                            xmlNodePtr root);
+void virStoragePRDefFormat(virBufferPtr buf,
+                           virStoragePRDefPtr prd);
+
 virSecurityDeviceLabelDefPtr
 virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
                                     const char *model);
diff --git a/tests/qemuxml2argvdata/disk-virtio-scsi-reservations-not-managed.xml b/tests/qemuxml2argvdata/disk-virtio-scsi-reservations-not-managed.xml
new file mode 100644
index 000000000..f4e4f1ee5
--- /dev/null
+++ b/tests/qemuxml2argvdata/disk-virtio-scsi-reservations-not-managed.xml
@@ -0,0 +1,41 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>8</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-i686</emulator>
+    <disk type='block' device='lun'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'>
+        <reservations enabled='yes' managed='no'>
+          <source type='unix' path='/path/to/qemu-pr-helper.sock' mode='client'/>
+        </reservations>
+      </source>
+      <target dev='sdb' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <driver queues='8'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/disk-virtio-scsi-reservations.xml b/tests/qemuxml2argvdata/disk-virtio-scsi-reservations.xml
new file mode 100644
index 000000000..92225a5b0
--- /dev/null
+++ b/tests/qemuxml2argvdata/disk-virtio-scsi-reservations.xml
@@ -0,0 +1,39 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>8</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-i686</emulator>
+    <disk type='block' device='lun'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'>
+        <reservations enabled='yes' managed='yes'/>
+      </source>
+      <target dev='sdb' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <driver queues='8'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations-not-managed.xml b/tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations-not-managed.xml
new file mode 120000
index 000000000..f96d62cb6
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations-not-managed.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/disk-virtio-scsi-reservations-not-managed.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations.xml b/tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations.xml
new file mode 120000
index 000000000..dde52fd1d
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/disk-virtio-scsi-reservations.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/disk-virtio-scsi-reservations.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 28ba46efb..670303898 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -387,6 +387,10 @@ mymain(void)
             QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
     DO_TEST("disk-virtio-scsi-num_queues",
             QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
+    DO_TEST("disk-virtio-scsi-reservations",
+            QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
+    DO_TEST("disk-virtio-scsi-reservations-not-managed",
+            QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
     DO_TEST("disk-virtio-scsi-cmd_per_lun",
             QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_VIRTIO_SCSI);
     DO_TEST("disk-virtio-scsi-max_sectors",
-- 
2.16.1

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux