[libvirt] [PATCH 02/10] Support leases in guest XML and lock manager

Daniel Veillard veillard at redhat.com
Fri May 27 08:31:36 UTC 2011


On Thu, May 19, 2011 at 07:24:17AM -0400, Daniel P. Berrange wrote:
> 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                      |   39 +++++++
>  docs/schemas/domain.rng                        |   24 ++++
>  src/conf/domain_conf.c                         |  134 ++++++++++++++++++++++++
>  src/conf/domain_conf.h                         |   14 +++
>  tests/qemuxml2argvdata/qemuxml2argv-lease.args |    4 +
>  tests/qemuxml2argvdata/qemuxml2argv-lease.xml  |   36 +++++++
>  tests/qemuxml2xmltest.c                        |    1 +
>  7 files changed, 252 insertions(+), 0 deletions(-)
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-lease.args
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-lease.xml
> 
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index facdaf2..d59779d 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -1071,6 +1071,45 @@
>        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>
> +  ...
> +  <devices>
> +    ...
> +    <lease>
> +      <lockspace>somearea</lockspace>
> +      <key>somekey</key>
> +      <target path='/some/lease/path' offset='1024'/>
> +    </lease>
> +    ...
> +  </devices>
> +  ...</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>
>  
> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
> index b252547..43c811f 100644
> --- a/docs/schemas/domain.rng
> +++ b/docs/schemas/domain.rng
> @@ -586,6 +586,29 @@
>        <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/>

  This should use <ref name="absFilePath"/> instead of <text/> for added
checking

> +          </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
> @@ -1940,6 +1963,7 @@
>            <choice>
>              <ref name="disk"/>
>              <ref name="controller"/>
> +            <ref name="lease"/>
>              <ref name="filesystem"/>
>              <ref name="interface"/>
>              <ref name="input"/>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 420d104..b6f7740 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -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",
> @@ -638,6 +639,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;
> @@ -900,6 +913,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;
> @@ -974,6 +990,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);
> @@ -1880,6 +1900,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
>   */
> @@ -4966,6 +5059,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)))
> @@ -5838,6 +5935,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;
> @@ -7012,6 +7126,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,
>                         int flags)
> @@ -8415,6 +8545,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;
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 8560076..b0771aa 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -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 {
> @@ -816,6 +825,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,
> @@ -836,6 +846,7 @@ struct _virDomainDeviceDef {
>      union {
>          virDomainDiskDefPtr disk;
>          virDomainControllerDefPtr controller;
> +        virDomainLeaseDefPtr lease;
>          virDomainFSDefPtr fs;
>          virDomainNetDefPtr net;
>          virDomainInputDefPtr input;
> @@ -1171,6 +1182,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
> index 0000000..63f9bef
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-lease.args
> @@ -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

  Hum is it really useful to add the test case yet while the driver code
isn't applied, but minor, I assume the test get expanded with the
driver addition later on

> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-lease.xml b/tests/qemuxml2argvdata/qemuxml2argv-lease.xml
> new file mode 100644
> index 0000000..7efe1ef
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-lease.xml
> @@ -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>
> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
> index 5bfbcab..e74c337 100644
> --- a/tests/qemuxml2xmltest.c
> +++ b/tests/qemuxml2xmltest.c
> @@ -179,6 +179,7 @@ mymain(void)
>      DO_TEST("cputune");
>  
>      DO_TEST("smp");
> +    DO_TEST("lease");
>  
>      /* These tests generate different XML */
>      DO_TEST_DIFFERENT("balloon-device-auto");

  ACK, with the small improvement to the RNG

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list