[libvirt] [PATCH] Allow off-line removal of devices via xend

john.levon at sun.com john.levon at sun.com
Thu Feb 5 04:42:10 UTC 2009


# HG changeset patch
# User john.levon at sun.com
# Date 1233806617 28800
# Node ID 507c2058c5f3c37894c573c4559eab58c5b52d7d
# Parent  0b9d8336e5e089b19ac8381fdc77eadc72ef9eb7
Allow off-line removal of devices via xend

We must avoid xenstore if the domain isn't running. For disks, this
works in all xend versions; for NICs, however, this requires a change in
netif.py to allow matching by MAC address. Preferring the device ID but
falling back to the device ref works best with all versions of xend.

Signed-off-by: John Levon <john.levon at sun.com>

diff --git a/src/xend_internal.c b/src/xend_internal.c
--- a/src/xend_internal.c
+++ b/src/xend_internal.c
@@ -92,11 +92,17 @@ xenDaemonFormatSxprNet(virConnectPtr con
                        int xendConfigVersion,
                        int isAttach);
 static int
-virDomainXMLDevID(virDomainPtr domain,
-                  virDomainDeviceDefPtr dev,
-                  char *class,
-                  char *ref,
-                  int ref_len);
+virDomainDevRef(virDomainPtr domain,
+               virDomainDeviceDefPtr dev,
+               char *class,
+               char *ref,
+               int ref_len);
+static int
+virDomainDevID(virDomainPtr domain,
+               int type,
+               const char *ref,
+               char *devid,
+               int devid_len);
 #endif
 
 #define virXendError(conn, code, fmt...)                                     \
@@ -3858,7 +3864,7 @@ xenDaemonAttachDevice(virDomainPtr domai
     virDomainDeviceDefPtr dev = NULL;
     virDomainDefPtr def = NULL;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
-    char class[8], ref[80];
+    char class[8], ref[80], devid[80];
 
     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
         virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
@@ -3914,15 +3920,24 @@ xenDaemonAttachDevice(virDomainPtr domai
 
     sexpr = virBufferContentAndReset(&buf);
 
-    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
+    devid[0] = '\0';
+
+    if (virDomainDevRef(domain, dev, class, ref, sizeof(ref)) == -1)
+        goto cleanup;
+
+    if (domain->id > 0 &&
+        virDomainDevID(domain, dev->type, ref, devid, sizeof(devid)) != -1) {
+        VIR_DEBUG("device_configure(ref = %s, devid = %s): %s",
+                  ref, devid, sexpr);
+        /* device exists, attempt to modify it */
+        ret = xend_op(domain->conn, domain->name, "op", "device_configure",
+                      "config", sexpr, "dev", devid, NULL);
+    } else {
+        VIR_DEBUG("device_create(ref = %s, devid = %s): %s",
+                  ref, devid, sexpr);
         /* device doesn't exist, define it */
         ret = xend_op(domain->conn, domain->name, "op", "device_create",
                       "config", sexpr, NULL);
-    }
-    else {
-        /* device exists, attempt to modify it */
-        ret = xend_op(domain->conn, domain->name, "op", "device_configure",
-                      "config", sexpr, "dev", ref, NULL);
     }
 
 cleanup:
@@ -3945,7 +3960,7 @@ xenDaemonDetachDevice(virDomainPtr domai
 xenDaemonDetachDevice(virDomainPtr domain, const char *xml)
 {
     xenUnifiedPrivatePtr priv;
-    char class[8], ref[80];
+    char class[8], ref[80], devid[80];
     virDomainDeviceDefPtr dev = NULL;
     virDomainDefPtr def = NULL;
     int ret = -1;
@@ -3976,11 +3991,41 @@ xenDaemonDetachDevice(virDomainPtr domai
                                         def, xml, VIR_DOMAIN_XML_INACTIVE)))
         goto cleanup;
 
-    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref)))
+    if (dev->type != VIR_DOMAIN_DEVICE_NET &&
+        dev->type != VIR_DOMAIN_DEVICE_DISK) {
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                     _("can't detach device of type %d"), dev->type);
         goto cleanup;
+    }
+
+    /*
+     * First acquire a static reference to the device (MAC address or
+     * destination disk). We'll use this if the domain isn't running,
+     * otherwise we'll rely upon the XenStore devid.
+     */
+
+    if (virDomainDevRef(domain, dev, class, ref, sizeof(ref)) == -1) {
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                     _("can't detach device: not found "));
+        goto cleanup;
+    }
+
+    if (domain->id >= 0) {
+        if (virDomainDevID(domain, dev->type, ref, devid, sizeof(devid))) {
+            virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                         _("can't detach device: not found "));
+            goto cleanup;
+        }
+    } else {
+        strncpy(devid, ref, 80);
+    }
+
+    VIR_DEBUG("device_destroy(type = %s, ref = %s, devid = %s)",
+              class, ref, devid);
 
     ret = xend_op(domain->conn, domain->name, "op", "device_destroy",
-                  "type", class, "dev", ref, "force", "0", "rm_cfg", "1", NULL);
+                  "type", class, "dev", devid, "force", "0",
+                  "rm_cfg", "1", NULL);
 
 cleanup:
     virDomainDefFree(def);
@@ -5502,12 +5547,48 @@ error:
 
 
 /**
- * virDomainXMLDevID:
+ * virDomainXMLDevRef:
  * @domain: pointer to domain object
  * @dev: pointer to device config object
  * @class: Xen device class "vbd" or "vif" (OUT)
  * @ref: Xen device reference (OUT)
  *
+ * Return the class (vbd/vif) and reference (MAC address / disk
+ * destination) of the given device.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+virDomainDevRef(virDomainPtr domain,
+                virDomainDeviceDefPtr dev,
+                char *class,
+                char *ref,
+                int ref_len)
+{
+    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
+        if (dev->data.disk->dst == NULL)
+            return -1;
+        strncpy(ref, dev->data.disk->dst, ref_len);
+        strcpy(class, "vbd");
+    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+        virFormatMacAddr(dev->data.net->mac, ref);
+        strcpy(class, "vif");
+    } else {
+        virXendError(NULL, VIR_ERR_NO_SUPPORT,
+                      _("no support for device type %d"), dev->type);
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * virDomainXMLDevID:
+ * @domain: pointer to domain object
+ * @class: either 'vbd' or 'vif'
+ * @ref: Xen device reference
+ * @devid: Xen device ID (OUT)
+ *
  * Set class according to XML root, and:
  *  - if disk, copy in ref the target name from description
  *  - if network, get MAC address from description, scan XenStore and
@@ -5516,54 +5597,41 @@ error:
  * Returns 0 in case of success, -1 in case of failure.
  */
 static int
-virDomainXMLDevID(virDomainPtr domain,
-                  virDomainDeviceDefPtr dev,
-                  char *class,
-                  char *ref,
-                  int ref_len)
+virDomainDevID(virDomainPtr domain,
+                int type,
+                const char *ref,
+                char *devid,
+                int devid_len)
 {
     xenUnifiedPrivatePtr priv = domain->conn->privateData;
-    char *xref;
-
-    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
-        strcpy(class, "vbd");
-        if (dev->data.disk->dst == NULL)
-            return -1;
-        xenUnifiedLock(priv);
-        xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
-                                       dev->data.disk->dst);
-        xenUnifiedUnlock(priv);
-        if (xref == NULL)
-            return -1;
-
-        strncpy(ref, xref, ref_len);
-        free(xref);
-        ref[ref_len - 1] = '\0';
-    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
-        char mac[30];
-        virDomainNetDefPtr def = dev->data.net;
-        snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
-                 def->mac[0], def->mac[1], def->mac[2],
-                 def->mac[3], def->mac[4], def->mac[5]);
-
-        strcpy(class, "vif");
-
-        xenUnifiedLock(priv);
-        xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
-                                          mac);
-        xenUnifiedUnlock(priv);
-        if (xref == NULL)
-            return -1;
-
-        strncpy(ref, xref, ref_len);
-        free(xref);
-        ref[ref_len - 1] = '\0';
+    char *id = NULL;
+
+    if (domain->id < 0) {
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                     _("devid not available for shutdown domain"));
+        return -1;
+    }
+          
+    xenUnifiedLock(priv);
+
+    if (type == VIR_DOMAIN_DEVICE_DISK) {
+        id = xenStoreDomainGetDiskID(domain->conn, domain->id, ref);
+                                     
+    } else if (type == VIR_DOMAIN_DEVICE_NET) {
+        id = xenStoreDomainGetNetworkID(domain->conn, domain->id, ref);
     } else {
         virXendError(NULL, VIR_ERR_NO_SUPPORT,
-                     "%s", _("hotplug of device type not supported"));
+                      _("no support for device type %d"), type);
+    }
+
+    xenUnifiedUnlock(priv);
+
+    if (id == NULL)
         return -1;
-    }
-
+
+    strncpy(devid, id, devid_len);
+    VIR_FREE(id);
+    devid[devid_len - 1] = '\0';
     return 0;
 }
 




More information about the libvir-list mailing list