}
-static int qemudDomainSetVcpus(virDomainPtr dom,
- ATTRIBUTE_UNUSED unsigned int nvcpus) {
+static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int i, rc;
+ int ret = -1;
+
+ /* We need different branches here, because we want to offline
+ * in reverse order to onlining, so any partial fail leaves us in a
+ * reasonably sensible state */
+ if (nvcpus > vm->def->vcpus) {
+ for (i = vm->def->vcpus ; i < nvcpus ; i++) {
+ /* Online new CPU */
+ rc = qemuMonitorSetCPU(priv->mon, i, 1);
+ if (rc == 0)
+ goto unsupported;
+ if (rc < 0)
+ goto cleanup;
+
+ vm->def->vcpus++;
+ }
+ } else {
+ for (i = vm->def->vcpus - 1 ; i >= nvcpus ; i--) {
+ /* Offline old CPU */
+ rc = qemuMonitorSetCPU(priv->mon, i, 0);
+ if (rc == 0)
+ goto unsupported;
+ if (rc < 0)
+ goto cleanup;
+
+ vm->def->vcpus--;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ return ret;
+
+unsupported:
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot change vcpu count of this domain"));
+ goto cleanup;
+}
+
+
+static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
+ const char * type;
+ int max;
int ret = -1;
qemuDriverLock(driver);
goto cleanup;
}
- qemuReportError(VIR_ERR_NO_SUPPORT,
- "%s", _("cpu hotplug not yet supported"));
+ if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown virt type in domain definition '%d'"),
+ vm->def->virtType);
+ goto endjob;
+ }
+
+ if ((max = qemudGetMaxVCPUs(NULL, type)) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("could not determine max vcpus for the domain"));
+ goto endjob;
+ }
+
+ if (nvcpus > max) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("requested vcpus is greater than max allowable"
+ " vcpus for the domain: %d > %d"), nvcpus, max);
+ goto endjob;
+ }
+
+ ret = qemudDomainHotplugVcpus(vm, nvcpus);
+
+endjob:
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
cleanup:
if (vm)
return ret;
}
+
+int qemuMonitorSetCPU(qemuMonitorPtr mon, int cpu, int online)
+{
+ int ret;
+ DEBUG("mon=%p, fd=%d cpu=%d online=%d", mon, mon->fd, cpu, online);
+
+ if (mon->json)
+ ret = qemuMonitorJSONSetCPU(mon, cpu, online);
+ else
+ ret = qemuMonitorTextSetCPU(mon, cpu, online);
+ return ret;
+}
+
+
int qemuMonitorEjectMedia(qemuMonitorPtr mon,
const char *devname)
{
const char *password);
int qemuMonitorSetBalloon(qemuMonitorPtr mon,
unsigned long newmem);
+int qemuMonitorSetCPU(qemuMonitorPtr mon, int cpu, int online);
+
/* XXX should we pass the virDomainDiskDefPtr instead
* and hide devname details inside monitor. Reconsider
}
+/*
+ * Returns: 0 if CPU hotplug not supported, +1 if CPU hotplug worked
+ * or -1 on failure
+ */
+int qemuMonitorJSONSetCPU(qemuMonitorPtr mon,
+ int cpu, int online)
+{
+ int ret;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon",
+ "U:cpu", (unsigned long long)cpu,
+ "s:state", online ? "online" : "offline",
+ NULL);
+ virJSONValuePtr reply = NULL;
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ /* XXX See if CPU soft-failed due to lack of ACPI */
+#if 0
+ if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
+ qemuMonitorJSONHasError(reply, "KVMMissingCap"))
+ goto cleanup;
+#endif
+
+ /* See if any other fatal error occurred */
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ /* Real success */
+ if (ret == 0)
+ ret = 1;
+ }
+
+#if 0
+cleanup:
+#endif
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
const char *devname)
{
const char *password);
int qemuMonitorJSONSetBalloon(qemuMonitorPtr mon,
unsigned long newmem);
+int qemuMonitorJSONSetCPU(qemuMonitorPtr mon, int cpu, int online);
int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
const char *devname);
return ret;
}
+
+/*
+ * Returns: 0 if balloon not supported, +1 if balloon adjust worked
+ * or -1 on failure
+ */
+int qemuMonitorTextSetCPU(qemuMonitorPtr mon, int cpu, int online)
+{
+ char *cmd;
+ char *reply = NULL;
+ int ret = -1;
+
+ if (virAsprintf(&cmd, "set_cpu %d %s", cpu, online ? "online" : "offline") < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("could nt change CPU online status"));
+ VIR_FREE(cmd);
+ return -1;
+ }
+ VIR_FREE(cmd);
+
+ /* If the command failed qemu prints: 'unknown command'
+ * No message is printed on success it seems */
+ if (strstr(reply, "\nunknown command:")) {
+ /* Don't set error - it is expected CPU onlining fails on many qemu - caller will handle */
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+
+ VIR_FREE(reply);
+ return ret;
+}
+
+
int qemuMonitorTextEjectMedia(qemuMonitorPtr mon,
const char *devname)
{
const char *password);
int qemuMonitorTextSetBalloon(qemuMonitorPtr mon,
unsigned long newmem);
+int qemuMonitorTextSetCPU(qemuMonitorPtr mon, int cpu, int online);
int qemuMonitorTextEjectMedia(qemuMonitorPtr mon,
const char *devname);