# HG changeset patch # User john.levon@xxxxxxx # Date 1233765613 28800 # Node ID bda41ea0cbbdea409447686c30b7afb10b9cae85 # Parent e6b17082b9b9440ce14ad76bd2f4c003ae2404db 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@xxxxxxx> 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...) \ @@ -3857,7 +3863,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, @@ -3913,15 +3919,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: @@ -3944,7 +3959,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; @@ -3975,11 +3990,40 @@ 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); @@ -5501,12 +5545,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 @@ -5515,54 +5595,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; } -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list