On Fri, Oct 17, 2008 at 02:37:17PM +0200, Daniel Veillard wrote:
[..snip..] 
>   Looks fine, i just removed a couple of extra spaces at end of line
> before commiting :-)
Thanks a lot for applying this so quickly! Attached is a patch that
allows for unplugging of disks. To do that I added a token to
virDomainDiskDef that holds the PCI bus/slot number [1] so we can
indentify the device on unplug. It's a union since other
busses/hypervisors might have other requirements. The token is meant as
an internal handle and will never show up in an XML and should probably
move up into virDomainDeviceDef. Comments are welcome.
 -- Guido

[1] bus is always == 0 at the moment
>From cad4833d5321e22c3f692e86add2eea850ca115f Mon Sep 17 00:00:00 2001
From: Guido Guenther <[EMAIL PROTECTED]>
Date: Fri, 17 Oct 2008 15:46:38 +0200
Subject: [PATCH] device detach for disks

---
 src/domain_conf.h |    6 ++
 src/qemu_driver.c |  132 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 133 insertions(+), 5 deletions(-)

diff --git a/src/domain_conf.h b/src/domain_conf.h
index 4d193f4..d97f7fe 100644
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -84,6 +84,12 @@ struct _virDomainDiskDef {
     int type;
     int device;
     int bus;
+    union {
+        struct {
+            int bus;
+            int slot;
+        } pci;
+    } token;
     char *src;
     char *dst;
     char *driverName;
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 3df208d..77c988a 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -2503,12 +2503,12 @@ static int qemudDomainChangeEjectableMedia(virDomainPtr dom,
     return 0;
 }
 
-static int qemudDomainAttachDiskDevice(virDomainPtr dom, virDomainDeviceDefPtr dev)
+static int qemudDomainAttachPciDiskDevice(virDomainPtr dom, virDomainDeviceDefPtr dev)
 {
     struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
     virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
     int ret, i;
-    char *cmd, *reply;
+    char *cmd, *reply, *s;
     char *safe_path;
     const char* type = virDomainDiskBusTypeToString(dev->data.disk->bus);
 
@@ -2556,7 +2556,14 @@ static int qemudDomainAttachDiskDevice(virDomainPtr dom, virDomainDeviceDefPtr d
     DEBUG ("pci_add reply: %s", reply);
     /* If the command succeeds qemu prints:
      * OK bus 0... */
-    if (!strstr(reply, "OK bus 0")) {
+#define PCI_ATTACH_OK_MSG "OK bus 0, slot "
+    if ((s=strstr(reply, PCI_ATTACH_OK_MSG))) {
+    	char* dummy = s;
+    	s += strlen(PCI_ATTACH_OK_MSG);
+
+        if (virStrToLong_i ((const char*)s, &dummy, 10, &dev->data.disk->token.pci.slot) == -1)
+        	qemudLog(QEMUD_WARN, _("Unable to parse slot number\n"));
+    } else {
         qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                           _("adding %s disk failed"), type);
         VIR_FREE(reply);
@@ -2737,7 +2744,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
                 } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                            dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
                     supported = 1;
-                    ret = qemudDomainAttachDiskDevice(dom, dev);
+                    ret = qemudDomainAttachPciDiskDevice(dom, dev);
                 }
                 break;
         }
@@ -2758,6 +2765,121 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
     return ret;
 }
 
+static int qemudDomainDetchPciDiskDevice(virDomainPtr dom, virDomainDeviceDefPtr dev)
+{
+    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    int i, ret = -1;
+    char *cmd, *reply;
+    virDomainDiskDefPtr detach=NULL;
+
+    if (!vm) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+                         "%s", _("no domain with matching uuid"));
+        return -1;
+    }
+
+    for (i = 0 ; i < vm->def->ndisks ; i++) {
+        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
+            detach = vm->def->disks[i];
+            break;
+        }
+    }
+
+    if (!detach) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("disk %s not found"), dev->data.disk->dst);
+        return -1;
+    }
+
+    if (detach->token.pci.slot < 1 || detach->token.pci.bus != 0) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("disk %s cannot be detached"), detach->dst);
+        return -1;
+    }
+
+    ret = asprintf(&cmd, "pci_del 0 %d", detach->token.pci.slot);
+    if (ret == -1) {
+        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
+        return ret;
+    }
+
+    if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("cannot detach disk %s"), detach->dst);
+        VIR_FREE(cmd);
+        return -1;
+    }
+
+    DEBUG ("pci_del reply: %s", reply);
+    /* If the command fails due to a wrong slot qemu prints: invalid slot, 
+     * nothing is printed on success */
+    if (strstr(reply, "invalid slot")) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                          _("cannot detach disk %s"), detach->dst);
+        ret = -1;
+        goto out; 
+    }
+  
+    if (vm->def->ndisks > 1) {
+        vm->def->disks[i] = vm->def->disks[--vm->def->ndisks];
+        if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks) < 0) {
+            qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
+            ret = -1;
+            goto out;
+        }
+        qsort(vm->def->disks, vm->def->ndisks, sizeof(*vm->def->disks),
+              virDomainDiskQSort);
+    } else {
+        VIR_FREE(vm->def->disks[0]);
+        vm->def->ndisks = 0;
+    }
+    ret = 0;
+out:
+    VIR_FREE(reply);
+    VIR_FREE(cmd);
+    return ret;
+}
+
+static int qemudDomainDetchDevice(virDomainPtr dom,
+                                   const char *xml) {
+    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+    virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    virDomainDeviceDefPtr dev;
+    int ret = 0;
+
+    if (!vm) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+                         "%s", _("no domain with matching uuid"));
+        return -1;
+    }
+
+    if (!virDomainIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "%s", _("cannot attach device on inactive domain"));
+        return -1;
+    }
+
+    dev = virDomainDeviceDefParse(dom->conn, vm->def, xml);
+    if (dev == NULL) {
+        return -1;
+    }
+
+    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
+        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+        (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
+         dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO))
+                    ret = qemudDomainDetchPciDiskDevice(dom, dev);
+    else {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                         "%s", _("this device type cannot be attached"));
+        ret = -1;
+    }
+
+    VIR_FREE(dev);
+    return ret;
+}
+
 static int qemudDomainGetAutostart(virDomainPtr dom,
                             int *autostart) {
     struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
@@ -3200,7 +3322,7 @@ static virDriver qemuDriver = {
     qemudDomainDefine, /* domainDefineXML */
     qemudDomainUndefine, /* domainUndefine */
     qemudDomainAttachDevice, /* domainAttachDevice */
-    NULL, /* domainDetachDevice */
+    qemudDomainDetchDevice, /* domainDetachDevice */
     qemudDomainGetAutostart, /* domainGetAutostart */
     qemudDomainSetAutostart, /* domainSetAutostart */
     NULL, /* domainGetSchedulerType */
-- 
1.6.0.2

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

Reply via email to