return ret;
}
+static int qemudDomainAttachPciControllerDevice(virConnectPtr conn,
+ struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainControllerDefPtr def)
+{
+ int i, ret;
+ const char* type = virDomainControllerTypeToString(def->type);
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ for (i = 0 ; i < vm->def->ncontrollers ; i++) {
+ if ((vm->def->controllers[i]->type == def->type) &&
+ (vm->def->controllers[i]->idx == def->idx)) {
+ qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+ _("target %s:%d already exists"),
+ type, def->idx);
+ return -1;
+ }
+ }
+
+ if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ ret = qemuMonitorAttachPCIDiskController(priv->mon,
+ type,
+ &def->info.addr.pci);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ if (ret == 0) {
+ def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ virDomainControllerInsertPreAlloced(vm->def, def);
+ }
+
+ return ret;
+}
+
+
static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm,
virCgroupDenyDevicePath(cgroup,
dev->data.disk->src);
}
+ } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
+ if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
+ ret = qemudDomainAttachPciControllerDevice(dom->conn, driver, vm, dev->data.controller);
+ } else {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ _("disk controller bus '%s' cannot be hotplugged."),
+ virDomainControllerTypeToString(dev->data.controller->type));
+ /* fallthrough */
+ }
} else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
return ret;
}
+static int qemudDomainDetachPciControllerDevice(virConnectPtr conn,
+ struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev)
+{
+ int i, ret = -1;
+ virDomainControllerDefPtr detach = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ for (i = 0 ; i < vm->def->ncontrollers ; i++) {
+ if ((vm->def->controllers[i]->type == dev->data.controller->type) &&
+ (vm->def->controllers[i]->idx == dev->data.controller->idx)) {
+ detach = vm->def->controllers[i];
+ break;
+ }
+ }
+
+ if (!detach) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("disk controller %s:%d not found"),
+ virDomainControllerTypeToString(dev->data.controller->type),
+ dev->data.controller->idx);
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceAddressIsValid(&detach->info,
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, "%s",
+ _("device cannot be detached without a PCI address"));
+ goto cleanup;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (qemuMonitorRemovePCIDevice(priv->mon,
+ &detach->info.addr.pci) < 0) {
+ qemuDomainObjExitMonitor(vm);
+ goto cleanup;
+ }
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ if (vm->def->ncontrollers > 1) {
+ memmove(vm->def->controllers + i,
+ vm->def->controllers + i + 1,
+ sizeof(*vm->def->controllers) *
+ (vm->def->ncontrollers - (i + 1)));
+ vm->def->ncontrollers--;
+ if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers) < 0) {
+ /* ignore, harmless */
+ }
+ } else {
+ VIR_FREE(vm->def->controllers);
+ vm->def->ncontrollers = 0;
+ }
+ virDomainControllerDefFree(detach);
+
+ ret = 0;
+
+cleanup:
+ return ret;
+}
+
static int
qemudDomainDetachNetDevice(virConnectPtr conn,
struct qemud_driver *driver,
VIR_WARN0("Fail to restore disk device ownership");
} else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
ret = qemudDomainDetachNetDevice(dom->conn, driver, vm, dev);
+ } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
+ if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
+ ret = qemudDomainDetachPciControllerDevice(dom->conn, driver, vm, dev);
+ } else {
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+ _("disk controller bus '%s' cannot be hotunplugged."),
+ virDomainControllerTypeToString(dev->data.controller->type));
+ /* fallthrough */
+ }
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
ret = qemudDomainDetachHostDevice(dom->conn, driver, vm, dev);
} else
ret = 0;
cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return ret;
+}
+
+
+int qemuMonitorTextAttachPCIDiskController(qemuMonitorPtr mon,
+ const char *bus,
+ virDomainDevicePCIAddress *guestAddr)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ int tryOldSyntax = 0;
+ int ret = -1;
+
+try_command:
+ if (virAsprintf(&cmd, "pci_add %s storage if=%s",
+ (tryOldSyntax ? "0": "pci_addr=auto"), bus) < 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("cannot attach %s disk controller"), bus);
+ goto cleanup;
+ }
+
+ if (qemuMonitorTextParsePciAddReply(mon, reply, guestAddr) < 0) {
+ if (!tryOldSyntax && strstr(reply, "invalid char in expression")) {
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+ tryOldSyntax = 1;
+ goto try_command;
+ }
+
+ qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("adding %s disk controller failed: %s"), bus, reply);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(cmd);
VIR_FREE(reply);
return ret;
}