]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Support leases in guest XML and lock manager
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 9 Dec 2010 18:25:11 +0000 (18:25 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 2 Jun 2011 09:54:00 +0000 (10:54 +0100)
A lock manager may operate in various modes. The direct mode of
operation is to obtain locks based on the resources associated
with devices in the XML. The indirect mode is where the app
creating the domain provides explicit leases for each resource
that needs to be locked. This XML extension allows for listing
resources in the XML

  <devices>
     ...
     <lease>
       <lockspace>somearea</lockspace>
       <key>thequickbrownfoxjumpsoverthelazydog</key>
       <target path='/some/lease/path' offset='23432'/>
     </lease>
     ...
  </devices>

The 'lockspace' is a unique identifier for the lockspace which
the lease is associated

The 'key' is a unique identifier for the resource associated
with the lease.

The 'target' is the file on disk where the leases are held.

* docs/schemas/domain.rng: Add lease schema
* src/conf/domain_conf.c, src/conf/domain_conf.h: parsing and
  formatting for leases
* tests/qemuxml2argvdata/qemuxml2argv-lease.args,
  tests/qemuxml2argvdata/qemuxml2argv-lease.xml,
  tests/qemuxml2xmltest.c: Test XML handling for leases

docs/formatdomain.html.in
docs/schemas/domain.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
tests/qemuxml2argvdata/qemuxml2argv-lease.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-lease.xml [new file with mode: 0644]
tests/qemuxml2xmltest.c

index f8baffd66bc28704405f4f0ac36bcbe74ed0d353..05171199cf13e520cadcf37fccba00f591835266 100644 (file)
       sub-element.
     </p>
 
+    <h4><a name="elementsLease">Device leases</a></h4>
+
+    <p>
+      When using a lock manager, it may be desirable to record device leases
+      against a VM. The lock manager will ensure the VM won't start unless
+      the leases can be acquired.
+    </p>
+
+<pre>
+  ...
+  &lt;devices&gt;
+    ...
+    &lt;lease&gt;
+      &lt;lockspace&gt;somearea&lt;/lockspace&gt;
+      &lt;key&gt;somekey&lt;/key&gt;
+      &lt;target path='/some/lease/path' offset='1024'/&gt;
+    &lt;/lease&gt;
+    ...
+  &lt;/devices&gt;
+  ...</pre>
+
+    <dl>
+      <dt>lockspace</dt>
+      <dd>This is an arbitrary string, identifying the lockspace
+        within which the key is held. Lock managers may impose
+        extra restrictions on the format, or length of the lockspace
+        name.</dd>
+      <dt>key</dt>
+      <dd>This is an arbitrary string, uniquely identifying the
+        lease to be acquired. Lock managers may impose extra
+        restrictions on the format, or length of the key.
+      </dd>
+      <dt>target</dt>
+      <dd>This is the fully qualified path of the file associated
+        with the lockspace. The offset specifies where the lease
+        is stored within the file. If the lock manager does not
+        require a offset, just pass 0.
+      </dd>
+    </dl>
 
     <h4><a name="elementsUSB">USB and PCI devices</a></h4>
 
index c2708152912db630170471318957650db1b36796..0be03711a4bb537a029e7180b643ef8f8a6a8f9f 100644 (file)
       <ref name="address"/>
     </optional>
   </define>
+
+  <define name="lease">
+    <element name="lease">
+      <interleave>
+        <element name="lockspace">
+          <text/>
+        </element>
+        <element name="key">
+          <text/>
+        </element>
+        <element name="target">
+          <attribute name="path">
+            <text/>
+          </attribute>
+          <optional>
+            <attribute name="offset">
+              <ref name="unsignedInt"/>
+            </attribute>
+          </optional>
+        </element>
+      </interleave>
+    </element>
+  </define>
   <!--
       A disk description can be either of type file or block
       The name of the attribute on the source element depends on the type
           <choice>
             <ref name="disk"/>
             <ref name="controller"/>
+            <ref name="lease"/>
             <ref name="filesystem"/>
             <ref name="interface"/>
             <ref name="input"/>
index 48ed7ebe4ae14a023998c14bac6eadbb2aaa9ca8..41455edc71f2c3cd922b758aeb3ba34fbbb494d2 100644 (file)
@@ -102,6 +102,7 @@ VIR_ENUM_IMPL(virDomainLifecycleCrash, VIR_DOMAIN_LIFECYCLE_CRASH_LAST,
 
 VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "disk",
+              "lease",
               "filesystem",
               "interface",
               "input",
@@ -642,6 +643,18 @@ void virDomainInputDefFree(virDomainInputDefPtr def)
     VIR_FREE(def);
 }
 
+static void virDomainLeaseDefFree(virDomainLeaseDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->lockspace);
+    VIR_FREE(def->key);
+    VIR_FREE(def->path);
+
+    VIR_FREE(def);
+}
+
 void virDomainDiskDefFree(virDomainDiskDefPtr def)
 {
     unsigned int i;
@@ -903,6 +916,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_DISK:
         virDomainDiskDefFree(def->data.disk);
         break;
+    case VIR_DOMAIN_DEVICE_LEASE:
+        virDomainLeaseDefFree(def->data.lease);
+        break;
     case VIR_DOMAIN_DEVICE_NET:
         virDomainNetDefFree(def->data.net);
         break;
@@ -977,6 +993,10 @@ void virDomainDefFree(virDomainDefPtr def)
     if (!def)
         return;
 
+    for (i = 0 ; i < def->nleases ; i++)
+        virDomainLeaseDefFree(def->leases[i]);
+    VIR_FREE(def->leases);
+
     for (i = 0 ; i < def->ngraphics ; i++)
         virDomainGraphicsDefFree(def->graphics[i]);
     VIR_FREE(def->graphics);
@@ -1881,6 +1901,79 @@ virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def)
     return 0;
 }
 
+/* Parse the XML definition for a lease
+ */
+static virDomainLeaseDefPtr
+virDomainLeaseDefParseXML(xmlNodePtr node)
+{
+    virDomainLeaseDefPtr def;
+    xmlNodePtr cur;
+    char *lockspace = NULL;
+    char *key = NULL;
+    char *path = NULL;
+    char *offset = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if ((key == NULL) &&
+                (xmlStrEqual(cur->name, BAD_CAST "key"))) {
+                key = (char *)xmlNodeGetContent(cur);
+            } else if ((lockspace == NULL) &&
+                (xmlStrEqual(cur->name, BAD_CAST "lockspace"))) {
+                lockspace = (char *)xmlNodeGetContent(cur);
+            } else if ((path == NULL) &&
+                       (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+                path = virXMLPropString(cur, "path");
+                offset = virXMLPropString(cur, "offset");
+            }
+        }
+        cur = cur->next;
+    }
+
+    if (!key) {
+        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                             _("Missing 'key' element for lease"));
+        goto error;
+    }
+    if (!path) {
+        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                             _("Missing 'target' element for lease"));
+        goto error;
+    }
+
+    if (offset &&
+        virStrToLong_ull(offset, NULL, 10, &def->offset) < 0) {
+        virDomainReportError(VIR_ERR_XML_ERROR,
+                             _("Malformed lease target offset %s"), offset);
+        goto error;
+    }
+
+    def->key = key;
+    def->lockspace = lockspace;
+    def->path = path;
+    path = key = lockspace = NULL;
+
+cleanup:
+    VIR_FREE(lockspace);
+    VIR_FREE(key);
+    VIR_FREE(path);
+    VIR_FREE(offset);
+
+    return def;
+
+ error:
+    virDomainLeaseDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
+
 /* Parse the XML definition for a disk
  * @param node XML nodeset to parse for disk definition
  */
@@ -4986,6 +5079,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
         if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
                                                         NULL, flags)))
             goto error;
+    } else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
+        dev->type = VIR_DOMAIN_DEVICE_LEASE;
+        if (!(dev->data.lease = virDomainLeaseDefParseXML(node)))
+            goto error;
     } else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
         dev->type = VIR_DOMAIN_DEVICE_FS;
         if (!(dev->data.fs = virDomainFSDefParseXML(node, flags)))
@@ -5903,6 +6000,23 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     }
     VIR_FREE(nodes);
 
+    /* analysis of the resource leases */
+    if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract device leases"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->leases, n) < 0)
+        goto no_memory;
+    for (i = 0 ; i < n ; i++) {
+        virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
+        if (!lease)
+            goto error;
+
+        def->leases[def->nleases++] = lease;
+    }
+    VIR_FREE(nodes);
+
     /* analysis of the filesystems */
     if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
         goto error;
@@ -7952,6 +8066,22 @@ virDomainLifecycleDefFormat(virBufferPtr buf,
 }
 
 
+static int
+virDomainLeaseDefFormat(virBufferPtr buf,
+                        virDomainLeaseDefPtr def)
+{
+    virBufferAddLit(buf, "    <lease>\n");
+    virBufferEscapeString(buf, "      <lockspace>%s</lockspace>\n", def->lockspace);
+    virBufferEscapeString(buf, "      <key>%s</key>\n", def->key);
+    virBufferEscapeString(buf, "      <target path='%s'", def->path);
+    if (def->offset)
+        virBufferAsprintf(buf, " offset='%llu'", def->offset);
+    virBufferAddLit(buf, "/>\n");
+    virBufferAddLit(buf, "    </lease>\n");
+
+    return 0;
+}
+
 static int
 virDomainDiskDefFormat(virBufferPtr buf,
                        virDomainDiskDefPtr def,
@@ -9365,6 +9495,10 @@ char *virDomainDefFormat(virDomainDefPtr def,
         if (virDomainControllerDefFormat(&buf, def->controllers[n], flags) < 0)
             goto cleanup;
 
+    for (n = 0 ; n < def->nleases ; n++)
+        if (virDomainLeaseDefFormat(&buf, def->leases[n]) < 0)
+            goto cleanup;
+
     for (n = 0 ; n < def->nfss ; n++)
         if (virDomainFSDefFormat(&buf, def->fss[n], flags) < 0)
             goto cleanup;
index 4d21cdb69e2baa662c2089778af753c7f7b92006..7545e0a84d2554ffe7f94aa3fb1a53dd56bd8bc0 100644 (file)
@@ -123,6 +123,15 @@ struct _virDomainDeviceInfo {
     } addr;
 };
 
+typedef struct _virDomainLeaseDef virDomainLeaseDef;
+typedef virDomainLeaseDef *virDomainLeaseDefPtr;
+struct _virDomainLeaseDef {
+    char *lockspace;
+    char *key;
+    char *path;
+    unsigned long long offset;
+};
+
 
 /* Two types of disk backends */
 enum virDomainDiskType {
@@ -825,6 +834,7 @@ enum virDomainSmbiosMode {
 /* Flags for the 'type' field in next struct */
 enum virDomainDeviceType {
     VIR_DOMAIN_DEVICE_DISK,
+    VIR_DOMAIN_DEVICE_LEASE,
     VIR_DOMAIN_DEVICE_FS,
     VIR_DOMAIN_DEVICE_NET,
     VIR_DOMAIN_DEVICE_INPUT,
@@ -845,6 +855,7 @@ struct _virDomainDeviceDef {
     union {
         virDomainDiskDefPtr disk;
         virDomainControllerDefPtr controller;
+        virDomainLeaseDefPtr lease;
         virDomainFSDefPtr fs;
         virDomainNetDefPtr net;
         virDomainInputDefPtr input;
@@ -1185,6 +1196,9 @@ struct _virDomainDef {
     int nchannels;
     virDomainChrDefPtr *channels;
 
+    int nleases;
+    virDomainLeaseDefPtr *leases;
+
     /* Only 1 */
     virDomainChrDefPtr console;
     virSecurityLabelDef seclabel;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-lease.args b/tests/qemuxml2argvdata/qemuxml2argv-lease.args
new file mode 100644 (file)
index 0000000..63f9bef
--- /dev/null
@@ -0,0 +1,4 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S \
+-M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -cdrom /root/boot.iso -net none \
+-serial none -parallel none -usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-lease.xml b/tests/qemuxml2argvdata/qemuxml2argv-lease.xml
new file mode 100644 (file)
index 0000000..7efe1ef
--- /dev/null
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</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</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' unit='0'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <source file='/root/boot.iso'/>
+      <target dev='hdc' bus='ide'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='1' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <lease>
+      <lockspace>somearea</lockspace>
+      <key>thequickbrownfoxjumpedoverthelazydog</key>
+      <target path='/some/lease/path' offset='1024'/>
+    </lease>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
index 64a833f80822163bbfc4d46e4a1c4e84f547c782..2a3e75aecb609b735885f025a1b85acb784dd35e 100644 (file)
@@ -181,6 +181,7 @@ mymain(void)
     DO_TEST("cputune");
 
     DO_TEST("smp");
+    DO_TEST("lease");
 
     /* These tests generate different XML */
     DO_TEST_DIFFERENT("balloon-device-auto");