qemu: Implement chardev hotplug on live level

Since previous patches has prepared everything for us, we may now
implement live hotplug of a character device.
This commit is contained in:
Michal Privoznik 2013-03-13 11:08:55 +01:00
parent 75f0fd5112
commit 24b0821926
4 changed files with 168 additions and 5 deletions

View File

@ -863,8 +863,41 @@ qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
return virAsprintf(&controller->info.alias, "%s%d", prefix, controller->idx);
}
static ssize_t
qemuGetNextChrDevIndex(virDomainDefPtr def,
virDomainChrDefPtr chr,
const char *prefix)
{
virDomainChrDefPtr **arrPtr;
size_t *cntPtr;
size_t i;
ssize_t idx = 0;
const char *prefix2 = NULL;
if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)
prefix2 = "serial";
virDomainChrGetDomainPtrs(def, chr, &arrPtr, &cntPtr);
for (i = 0; i < *cntPtr; i++) {
ssize_t thisidx;
if (((thisidx = qemuDomainDeviceAliasIndex(&(*arrPtr)[i]->info, prefix)) < 0) &&
(prefix2 &&
(thisidx = qemuDomainDeviceAliasIndex(&(*arrPtr)[i]->info, prefix2)) < 0)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to determine device index for character device"));
return -1;
}
if (thisidx >= idx)
idx = thisidx + 1;
}
return idx;
}
int
qemuAssignDeviceChrAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
qemuAssignDeviceChrAlias(virDomainDefPtr def,
virDomainChrDefPtr chr,
ssize_t idx)
{
@ -891,6 +924,9 @@ qemuAssignDeviceChrAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
return -1;
}
if (idx == -1 && (idx = qemuGetNextChrDevIndex(def, chr, prefix)) < 0)
return -1;
return virAsprintf(&chr->info.alias, "%s%zd", prefix, idx);
}

View File

@ -6390,6 +6390,13 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
dev->data.redirdev = NULL;
break;
case VIR_DOMAIN_DEVICE_CHR:
ret = qemuDomainAttachChrDevice(driver, vm,
dev->data.chr);
if (!ret)
dev->data.chr = NULL;
break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("live attach of device '%s' is not supported"),
@ -6477,6 +6484,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_HOSTDEV:
ret = qemuDomainDetachHostDevice(driver, vm, dev);
break;
case VIR_DOMAIN_DEVICE_CHR:
ret = qemuDomainDetachChrDevice(driver, vm, dev->data.chr);
break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("live detach of device '%s' is not supported"),
@ -6886,7 +6896,7 @@ static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
virDomainDefPtr vmdef = NULL;
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
int ret = -1;
unsigned int affect;
unsigned int affect, parse_flags = 0;
virQEMUCapsPtr qemuCaps = NULL;
qemuDomainObjPrivatePtr priv;
virQEMUDriverConfigPtr cfg = NULL;
@ -6934,9 +6944,13 @@ static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
goto endjob;
}
if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
!(flags & VIR_DOMAIN_AFFECT_LIVE))
parse_flags |= VIR_DOMAIN_XML_INACTIVE;
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
caps, driver->xmlopt,
VIR_DOMAIN_XML_INACTIVE);
parse_flags);
if (dev == NULL)
goto endjob;
@ -7164,7 +7178,7 @@ static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
virDomainDefPtr vmdef = NULL;
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
int ret = -1;
unsigned int affect;
unsigned int affect, parse_flags = 0;
virQEMUCapsPtr qemuCaps = NULL;
qemuDomainObjPrivatePtr priv;
virQEMUDriverConfigPtr cfg = NULL;
@ -7212,9 +7226,13 @@ static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
goto endjob;
}
if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
!(flags & VIR_DOMAIN_AFFECT_LIVE))
parse_flags |= VIR_DOMAIN_XML_INACTIVE;
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
caps, driver->xmlopt,
VIR_DOMAIN_XML_INACTIVE);
parse_flags);
if (dev == NULL)
goto endjob;

View File

@ -1244,6 +1244,62 @@ qemuDomainChrRemove(virDomainDefPtr vmdef,
return ret;
}
int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainDefPtr vmdef = vm->def;
char *devstr = NULL;
char *charAlias = NULL;
bool remove = false;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("qemu does not support -device"));
return ret;
}
if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
return ret;
if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0)
return ret;
if (virAsprintf(&charAlias, "char%s", chr->info.alias) < 0) {
virReportOOMError();
goto cleanup;
}
if (qemuDomainChrInsert(vmdef, chr) < 0)
goto cleanup;
remove = true;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorAttachCharDev(priv->mon, charAlias, &chr->source) < 0) {
qemuDomainObjExitMonitor(driver, vm);
goto cleanup;
}
if (devstr && qemuMonitorAddDevice(priv->mon, devstr) < 0) {
/* detach associated chardev on error */
qemuMonitorDetachCharDev(priv->mon, charAlias);
qemuDomainObjExitMonitor(driver, vm);
goto cleanup;
}
qemuDomainObjExitMonitor(driver, vm);
ret = 0;
cleanup:
if (ret < 0 && remove)
qemuDomainChrRemove(vmdef, chr);
VIR_FREE(charAlias);
VIR_FREE(devstr);
return ret;
}
int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
@ -3077,3 +3133,50 @@ int qemuDomainDetachLease(virQEMUDriverPtr driver,
virDomainLeaseDefFree(det_lease);
return 0;
}
int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainDefPtr vmdef = vm->def;
virDomainChrDefPtr tmpChr;
char *charAlias = NULL;
char *devstr = NULL;
if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("device not present in domain configuration"));
return ret;
}
if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0)
return ret;
if (virAsprintf(&charAlias, "char%s", tmpChr->info.alias) < 0) {
virReportOOMError();
return ret;
}
qemuDomainObjEnterMonitor(driver, vm);
if (devstr && qemuMonitorDelDevice(priv->mon, tmpChr->info.alias) < 0) {
qemuDomainObjExitMonitor(driver, vm);
goto cleanup;
}
if (qemuMonitorDetachCharDev(priv->mon, charAlias) < 0) {
qemuDomainObjExitMonitor(driver, vm);
goto cleanup;
}
qemuDomainObjExitMonitor(driver, vm);
qemuDomainChrRemove(vmdef, tmpChr);
virDomainChrDefFree(tmpChr);
ret = 0;
cleanup:
VIR_FREE(devstr);
VIR_FREE(charAlias);
return ret;
}

View File

@ -104,6 +104,12 @@ int qemuDomainAttachLease(virQEMUDriverPtr driver,
int qemuDomainDetachLease(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainLeaseDefPtr lease);
int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr);
int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr);
int