[libvirt] [PATCH 0/4] Another set of functions for the libxl driver

This patch set adds some more functions to the libxl driver. Best regards Markus Markus Groß (4): Add domainIsUpdated to libxl driver Add domainSet/GetSchedulerParameters to libxl driver Add cputune support to libxl driver Add domainSave/Restore to libxl driver src/libxl/libxl_conf.h | 10 + src/libxl/libxl_driver.c | 517 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 485 insertions(+), 42 deletions(-) -- 1.7.4.3

--- src/libxl/libxl_driver.c | 24 +++++++++++++++++++++++- 1 files changed, 23 insertions(+), 1 deletions(-) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 8cc4469..e95c403 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2330,6 +2330,28 @@ libxlDomainIsPersistent(virDomainPtr dom) } static int +libxlDomainIsUpdated(virDomainPtr dom) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + ret = vm->updated; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int libxlDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, virFreeCallback freecb) @@ -2456,7 +2478,7 @@ static virDriver libxlDriver = { NULL, /* IsSecure */ libxlDomainIsActive, /* DomainIsActive */ libxlDomainIsPersistent, /* DomainIsPersistent */ - NULL, /* domainIsUpdated */ + libxlDomainIsUpdated, /* domainIsUpdated */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */ -- 1.7.4.3

Markus Groß wrote:
--- src/libxl/libxl_driver.c | 24 +++++++++++++++++++++++- 1 files changed, 23 insertions(+), 1 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 8cc4469..e95c403 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2330,6 +2330,28 @@ libxlDomainIsPersistent(virDomainPtr dom) }
static int +libxlDomainIsUpdated(virDomainPtr dom) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + ret = vm->updated; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int libxlDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, virFreeCallback freecb) @@ -2456,7 +2478,7 @@ static virDriver libxlDriver = { NULL, /* IsSecure */ libxlDomainIsActive, /* DomainIsActive */ libxlDomainIsPersistent, /* DomainIsPersistent */ - NULL, /* domainIsUpdated */ + libxlDomainIsUpdated, /* domainIsUpdated */ NULL, /* cpuCompare */ NULL, /* cpuBaseline */ NULL, /* domainGetJobInfo */
ACK, and pushed. Thanks Markus. Regards, Jim

Libxenlight currently only supports the credit scheduler. Therefore setting or getting a parameter of other schedulers raise an error (for now). --- src/libxl/libxl_driver.c | 166 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 164 insertions(+), 2 deletions(-) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index e95c403..c760a23 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2286,6 +2286,168 @@ cleanup: } static int +libxlDomainGetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, + int * nparams) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + libxlDomainObjPrivatePtr priv; + virDomainObjPtr vm; + libxl_sched_credit sc_info; + int sched_id; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if ((sched_id = libxl_get_sched_id(&priv->ctx)) < 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get scheduler id for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + if (sched_id != XEN_SCHEDULER_CREDIT) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Only 'credit' scheduler is supported")); + goto cleanup; + } + + if (*nparams != XEN_SCHED_CREDIT_NPARAM) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("Invalid parameter count")); + goto cleanup; + } + + if (libxl_sched_credit_domain_get(&priv->ctx, dom->id, &sc_info) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get scheduler parameters for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + params[0].value.ui = sc_info.weight; + params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT; + if (virStrcpyStatic(params[0].field, "weight") == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field weight too long for destination")); + goto cleanup; + } + + params[1].value.ui = sc_info.cap; + params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT; + if (virStrcpyStatic(params[1].field, "cap") == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field cap too long for destination")); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +libxlDomainSetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, + int nparams) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + libxlDomainObjPrivatePtr priv; + virDomainObjPtr vm; + libxl_sched_credit sc_info; + int sched_id; + int i; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if ((sched_id = libxl_get_sched_id(&priv->ctx)) < 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get scheduler id for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + if (sched_id != XEN_SCHEDULER_CREDIT) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Only 'credit' scheduler is supported")); + goto cleanup; + } + + if (nparams != XEN_SCHED_CREDIT_NPARAM) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("Invalid parameter count")); + goto cleanup; + } + + for (i = 0; i < nparams; ++i) { + virSchedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, "weight")) { + if (param->type != VIR_DOMAIN_SCHED_FIELD_UINT) { + libxlError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for weight tunable, expected a 'uint'")); + goto cleanup; + } + sc_info.weight = params[i].value.ui; + + } else if (STREQ(param->field, "cap")) { + if (param->type != VIR_DOMAIN_SCHED_FIELD_UINT) { + libxlError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for cap tunable, expected a 'uint'")); + goto cleanup; + } + sc_info.cap = params[i].value.ui; + } else { + libxlError(VIR_ERR_INVALID_ARG, + _("Invalid parameter '%s'"), param->field); + goto cleanup; + } + } + + if (libxl_sched_credit_domain_set(&priv->ctx, dom->id, &sc_info) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set scheduler parameters for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int libxlDomainIsActive(virDomainPtr dom) { libxlDriverPrivatePtr driver = dom->conn->privateData; @@ -2453,8 +2615,8 @@ static virDriver libxlDriver = { libxlDomainGetAutostart, /* domainGetAutostart */ libxlDomainSetAutostart, /* domainSetAutostart */ libxlDomainGetSchedulerType,/* domainGetSchedulerType */ - NULL, /* domainGetSchedulerParameters */ - NULL, /* domainSetSchedulerParameters */ + libxlDomainGetSchedulerParameters,/* domainGetSchedulerParameters */ + libxlDomainSetSchedulerParameters,/* domainSetSchedulerParameters */ NULL, /* domainMigratePrepare */ NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */ -- 1.7.4.3

Markus Groß wrote:
Libxenlight currently only supports the credit scheduler. Therefore setting or getting a parameter of other schedulers raise an error (for now). --- src/libxl/libxl_driver.c | 166 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 164 insertions(+), 2 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index e95c403..c760a23 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2286,6 +2286,168 @@ cleanup: }
static int +libxlDomainGetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, + int * nparams)
In most libvirt code that would be 'int *nparams'.
+{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + libxlDomainObjPrivatePtr priv; + virDomainObjPtr vm; + libxl_sched_credit sc_info; + int sched_id; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + }
Is this API restricted to active domains only? I suppose schedule parameters are classified as runtime tunables, and not defined in persistent config.
+ + priv = vm->privateData; + + if ((sched_id = libxl_get_sched_id(&priv->ctx)) < 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get scheduler id for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + if (sched_id != XEN_SCHEDULER_CREDIT) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Only 'credit' scheduler is supported")); + goto cleanup; + } + + if (*nparams != XEN_SCHED_CREDIT_NPARAM) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("Invalid parameter count")); + goto cleanup; + } + + if (libxl_sched_credit_domain_get(&priv->ctx, dom->id, &sc_info) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get scheduler parameters for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + params[0].value.ui = sc_info.weight; + params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
The libxl_sched_credit fields are int, but treated as unsigned internally. Using UINT plays nicely with "legacy" weight and cap handling in virsh and is the correct type to use here IMO. ACK. I fixed the whitespace issue noted above and pushed. Thanks Markus. Regards, Jim
+ if (virStrcpyStatic(params[0].field, "weight") == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field weight too long for destination")); + goto cleanup; + } + + params[1].value.ui = sc_info.cap; + params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT; + if (virStrcpyStatic(params[1].field, "cap") == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Field cap too long for destination")); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +libxlDomainSetSchedulerParameters(virDomainPtr dom, virSchedParameterPtr params, + int nparams) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + libxlDomainObjPrivatePtr priv; + virDomainObjPtr vm; + libxl_sched_credit sc_info; + int sched_id; + int i; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + libxlDriverUnlock(driver); + + if (!vm) { + libxlError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if ((sched_id = libxl_get_sched_id(&priv->ctx)) < 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get scheduler id for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + if (sched_id != XEN_SCHEDULER_CREDIT) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Only 'credit' scheduler is supported")); + goto cleanup; + } + + if (nparams != XEN_SCHED_CREDIT_NPARAM) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("Invalid parameter count")); + goto cleanup; + } + + for (i = 0; i < nparams; ++i) { + virSchedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, "weight")) { + if (param->type != VIR_DOMAIN_SCHED_FIELD_UINT) { + libxlError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for weight tunable, expected a 'uint'")); + goto cleanup; + } + sc_info.weight = params[i].value.ui; + + } else if (STREQ(param->field, "cap")) { + if (param->type != VIR_DOMAIN_SCHED_FIELD_UINT) { + libxlError(VIR_ERR_INVALID_ARG, "%s", + _("invalid type for cap tunable, expected a 'uint'")); + goto cleanup; + } + sc_info.cap = params[i].value.ui; + } else { + libxlError(VIR_ERR_INVALID_ARG, + _("Invalid parameter '%s'"), param->field); + goto cleanup; + } + } + + if (libxl_sched_credit_domain_set(&priv->ctx, dom->id, &sc_info) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set scheduler parameters for domain '%d'" + " with libxenlight"), dom->id); + goto cleanup; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int libxlDomainIsActive(virDomainPtr dom) { libxlDriverPrivatePtr driver = dom->conn->privateData; @@ -2453,8 +2615,8 @@ static virDriver libxlDriver = { libxlDomainGetAutostart, /* domainGetAutostart */ libxlDomainSetAutostart, /* domainSetAutostart */ libxlDomainGetSchedulerType,/* domainGetSchedulerType */ - NULL, /* domainGetSchedulerParameters */ - NULL, /* domainSetSchedulerParameters */ + libxlDomainGetSchedulerParameters,/* domainGetSchedulerParameters */ + libxlDomainSetSchedulerParameters,/* domainSetSchedulerParameters */ NULL, /* domainMigratePrepare */ NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */

The nodeGetInfo code had to be moved into a helper function to reuse it without a virConnectPtr. --- src/libxl/libxl_driver.c | 143 ++++++++++++++++++++++++++++++++++------------ 1 files changed, 107 insertions(+), 36 deletions(-) diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index c760a23..1539385 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -199,6 +199,46 @@ libxlAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, virDomainObjUnlock(vm); } +static int +libxlDoNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info) +{ + libxl_physinfo phy_info; + const libxl_version_info* ver_info; + struct utsname utsname; + + if (libxl_get_physinfo(&driver->ctx, &phy_info)) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("libxl_get_physinfo_info failed")); + return -1; + } + + if ((ver_info = libxl_get_version_info(&driver->ctx)) == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("libxl_get_version_info failed")); + return -1; + } + + uname(&utsname); + if (virStrncpy(info->model, + utsname.machine, + strlen(utsname.machine), + sizeof(info->model)) == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("machine type %s too big for destination"), + utsname.machine); + return -1; + } + + info->memory = phy_info.total_pages * (ver_info->pagesize / 1024); + info->cpus = phy_info.nr_cpus; + info->nodes = phy_info.nr_nodes; + info->cores = phy_info.cores_per_socket; + info->threads = phy_info.threads_per_core; + info->sockets = 1; + info->mhz = phy_info.cpu_khz / 1000; + return 0; +} + /* * Cleanup function for domain that has reached shutoff state. * @@ -391,6 +431,62 @@ error: return -1; } +static int +libxlDomainSetVcpuAffinites(libxlDriverPrivatePtr driver, virDomainObjPtr vm) +{ + libxlDomainObjPrivatePtr priv = vm->privateData; + virDomainDefPtr def = vm->def; + libxl_cpumap map; + uint8_t *cpumask = NULL; + uint8_t *cpumap = NULL; + virNodeInfo nodeinfo; + size_t cpumaplen; + unsigned int pos; + int vcpu, i; + int ret = -1; + + if (libxlDoNodeGetInfo(driver, &nodeinfo) < 0) + goto cleanup; + + cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); + + for (vcpu = 0; vcpu < def->cputune.nvcpupin; ++vcpu) { + if (vcpu != def->cputune.vcpupin[vcpu]->vcpuid) + continue; + + if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) { + virReportOOMError(); + goto cleanup; + } + + cpumask = (uint8_t*) def->cputune.vcpupin[vcpu]->cpumask; + + for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; ++i) { + if (cpumask[i]) { + pos = i / 8; + cpumap[pos] |= 1 << (i % 8); + } + } + + map.size = cpumaplen; + map.map = cpumap; + + if (libxl_set_vcpuaffinity(&priv->ctx, def->id, vcpu, &map) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to pin vcpu '%d' with libxenlight"), vcpu); + goto cleanup; + } + + VIR_FREE(cpumap); + } + + ret = 0; + +cleanup: + VIR_FREE(cpumap); + return ret; +} + /* * Start a domain through libxenlight. * @@ -440,6 +536,9 @@ libxlVmStart(libxlDriverPrivatePtr driver, if (libxlCreateDomEvents(vm) < 0) goto error; + if (libxlDomainSetVcpuAffinites(driver, vm) < 0) + goto error; + if (!start_paused) { libxl_domain_unpause(&priv->ctx, domid); vm->state = VIR_DOMAIN_RUNNING; @@ -869,42 +968,7 @@ libxlGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED) static int libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) { - libxl_physinfo phy_info; - const libxl_version_info* ver_info; - libxlDriverPrivatePtr driver = conn->privateData; - struct utsname utsname; - - if (libxl_get_physinfo(&driver->ctx, &phy_info)) { - libxlError(VIR_ERR_INTERNAL_ERROR, - _("libxl_get_physinfo_info failed")); - return -1; - } - - if ((ver_info = libxl_get_version_info(&driver->ctx)) == NULL) { - libxlError(VIR_ERR_INTERNAL_ERROR, - _("libxl_get_version_info failed")); - return -1; - } - - uname(&utsname); - if (virStrncpy(info->model, - utsname.machine, - strlen(utsname.machine), - sizeof(info->model)) == NULL) { - libxlError(VIR_ERR_INTERNAL_ERROR, - _("machine type %s too big for destination"), - utsname.machine); - return -1; - } - - info->memory = phy_info.total_pages * (ver_info->pagesize / 1024); - info->cpus = phy_info.nr_cpus; - info->nodes = phy_info.nr_nodes; - info->cores = phy_info.cores_per_socket; - info->threads = phy_info.threads_per_core; - info->sockets = 1; - info->mhz = phy_info.cpu_khz / 1000; - return 0; + return libxlDoNodeGetInfo(conn->privateData, info); } static char * @@ -1712,6 +1776,13 @@ libxlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap, _("Failed to pin vcpu '%d' with libxenlight"), vcpu); goto cleanup; } + + if (virDomainVcpupinAdd(vm->def, cpumap, maplen, vcpu) < 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + "%s", _("failed to update or add vcpupin xml")); + goto cleanup; + } + ret = 0; cleanup: -- 1.7.4.3

Markus Groß wrote:
The nodeGetInfo code had to be moved into a helper function to reuse it without a virConnectPtr.
Sounds good.
--- src/libxl/libxl_driver.c | 143 ++++++++++++++++++++++++++++++++++------------ 1 files changed, 107 insertions(+), 36 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index c760a23..1539385 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -199,6 +199,46 @@ libxlAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, virDomainObjUnlock(vm); }
+static int +libxlDoNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info) +{ + libxl_physinfo phy_info; + const libxl_version_info* ver_info; + struct utsname utsname; + + if (libxl_get_physinfo(&driver->ctx, &phy_info)) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("libxl_get_physinfo_info failed")); + return -1; + } + + if ((ver_info = libxl_get_version_info(&driver->ctx)) == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("libxl_get_version_info failed")); + return -1; + } + + uname(&utsname); + if (virStrncpy(info->model, + utsname.machine, + strlen(utsname.machine), + sizeof(info->model)) == NULL) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("machine type %s too big for destination"), + utsname.machine); + return -1; + } + + info->memory = phy_info.total_pages * (ver_info->pagesize / 1024); + info->cpus = phy_info.nr_cpus; + info->nodes = phy_info.nr_nodes; + info->cores = phy_info.cores_per_socket; + info->threads = phy_info.threads_per_core; + info->sockets = 1; + info->mhz = phy_info.cpu_khz / 1000; + return 0; +} + /* * Cleanup function for domain that has reached shutoff state. * @@ -391,6 +431,62 @@ error: return -1; }
+static int +libxlDomainSetVcpuAffinites(libxlDriverPrivatePtr driver, virDomainObjPtr vm) +{ + libxlDomainObjPrivatePtr priv = vm->privateData; + virDomainDefPtr def = vm->def; + libxl_cpumap map; + uint8_t *cpumask = NULL; + uint8_t *cpumap = NULL; + virNodeInfo nodeinfo; + size_t cpumaplen; + unsigned int pos; + int vcpu, i; + int ret = -1; + + if (libxlDoNodeGetInfo(driver, &nodeinfo) < 0) + goto cleanup; + + cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); + + for (vcpu = 0; vcpu < def->cputune.nvcpupin; ++vcpu) { + if (vcpu != def->cputune.vcpupin[vcpu]->vcpuid) + continue; + + if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) { + virReportOOMError(); + goto cleanup; + } + + cpumask = (uint8_t*) def->cputune.vcpupin[vcpu]->cpumask; + + for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; ++i) { + if (cpumask[i]) { + pos = i / 8; + cpumap[pos] |= 1 << (i % 8); + } + } + + map.size = cpumaplen; + map.map = cpumap; + + if (libxl_set_vcpuaffinity(&priv->ctx, def->id, vcpu, &map) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to pin vcpu '%d' with libxenlight"), vcpu); + goto cleanup; + } + + VIR_FREE(cpumap); + } + + ret = 0; + +cleanup: + VIR_FREE(cpumap); + return ret; +} + /* * Start a domain through libxenlight. * @@ -440,6 +536,9 @@ libxlVmStart(libxlDriverPrivatePtr driver, if (libxlCreateDomEvents(vm) < 0) goto error;
+ if (libxlDomainSetVcpuAffinites(driver, vm) < 0) + goto error; + if (!start_paused) { libxl_domain_unpause(&priv->ctx, domid); vm->state = VIR_DOMAIN_RUNNING; @@ -869,42 +968,7 @@ libxlGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED) static int libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) { - libxl_physinfo phy_info; - const libxl_version_info* ver_info; - libxlDriverPrivatePtr driver = conn->privateData; - struct utsname utsname; - - if (libxl_get_physinfo(&driver->ctx, &phy_info)) { - libxlError(VIR_ERR_INTERNAL_ERROR, - _("libxl_get_physinfo_info failed")); - return -1; - } - - if ((ver_info = libxl_get_version_info(&driver->ctx)) == NULL) { - libxlError(VIR_ERR_INTERNAL_ERROR, - _("libxl_get_version_info failed")); - return -1; - } - - uname(&utsname); - if (virStrncpy(info->model, - utsname.machine, - strlen(utsname.machine), - sizeof(info->model)) == NULL) { - libxlError(VIR_ERR_INTERNAL_ERROR, - _("machine type %s too big for destination"), - utsname.machine); - return -1; - } - - info->memory = phy_info.total_pages * (ver_info->pagesize / 1024); - info->cpus = phy_info.nr_cpus; - info->nodes = phy_info.nr_nodes; - info->cores = phy_info.cores_per_socket; - info->threads = phy_info.threads_per_core; - info->sockets = 1; - info->mhz = phy_info.cpu_khz / 1000; - return 0; + return libxlDoNodeGetInfo(conn->privateData, info); }
static char * @@ -1712,6 +1776,13 @@ libxlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap, _("Failed to pin vcpu '%d' with libxenlight"), vcpu); goto cleanup; } + + if (virDomainVcpupinAdd(vm->def, cpumap, maplen, vcpu) < 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + "%s", _("failed to update or add vcpupin xml")); + goto cleanup; + } +
I'm not sure about this hunk. The cputune info is in memory but not saved anywhere. E.g. # virsh start domU # virsh vcpupin domU 0 0,1,2 # virsh dumpxml domU | grep vcpupin <vcpupin vcpu='0' cpuset='0-2'/> # restart libvirtd # virsh dumpxml domU | grep vcpupin # I think config in driver->stateDir needs updated to handle this case. # virsh start domU # virsh vcpuping domU 0 0,1,2 # virsh shutdown domU # wait for shutdown # virsh dumpxml domU | grep vcpupin <vcpupin vcpu='0' cpuset='0-2'/> # restart libvirtd # virsh dumpxml domU | grep vcpupin # Once the domain is shutdown, the affinitiy config should be removed right? Documentation for virDomainPinVcpu states: "This command only changes the runtime configuration of the domain, so can only be called on an active domain". Regards, Jim

--- src/libxl/libxl_conf.h | 10 +++ src/libxl/libxl_driver.c | 184 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 191 insertions(+), 3 deletions(-) diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index f2f0d8a..e28615b 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -1,5 +1,6 @@ /*---------------------------------------------------------------------------*/ /* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. + * Copyright (C) 2011 Univention GmbH. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,7 @@ * * Authors: * Jim Fehlig <jfehlig@novell.com> + * Markus Groß <gross@univention.de> */ /*---------------------------------------------------------------------------*/ @@ -85,6 +87,14 @@ struct _libxlDomainObjPrivate { int eventHdl; }; +static const char libxlSavefileMagic[16]= "libvirt-xml\n \0 \r"; +typedef struct _libxlSavefileHeader libxlSavefileHeader; +typedef libxlSavefileHeader *libxlSavefileHeaderPtr; +struct _libxlSavefileHeader { + char magic[16]; /* magic id */ + uint32_t xmlLen; /* length of saved xml */ +}; + # define libxlError(code, ...) \ virReportErrorHelper(NULL, VIR_FROM_LIBXL, code, __FILE__, \ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 1539385..b02d4b7 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -29,6 +29,7 @@ #include <sys/utsname.h> #include <math.h> #include <libxl.h> +#include <fcntl.h> #include "internal.h" #include "logging.h" @@ -60,7 +61,6 @@ static libxlDriverPrivatePtr libxl_driver = NULL; - /* Function declarations */ static int libxlVmStart(libxlDriverPrivatePtr driver, @@ -1555,6 +1555,184 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) } static int +libxlDomainSave(virDomainPtr dom, const char * to) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm; + libxlDomainObjPrivatePtr priv; + virDomainEventPtr event = NULL; + libxlSavefileHeader hdr; + libxl_domain_suspend_info s_info; + char * xml; + uint32_t xml_len; + int fd; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + libxlError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (vm->state != VIR_DOMAIN_PAUSED) { + memset(&s_info, 0, sizeof(s_info)); + + if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR, + getuid(), getgid(), 0)) < 0) { + virReportSystemError(-fd, + _("Failed to create domain save file '%s'"), + to); + goto cleanup; + } + + if ((xml = virDomainDefFormat(vm->def, 0)) == NULL) + goto cleanup; + xml_len = strlen(xml) + 1; + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic)); + hdr.xmlLen = xml_len; + + if (safewrite(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("Failed to write save file header")); + goto cleanup; + } + + if (safewrite(fd, xml, xml_len) != xml_len) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("Failed to write xml description")); + goto cleanup; + } + + if (libxl_domain_suspend(&priv->ctx, &s_info, dom->id, fd) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to save domain '%d' with libxenlight"), + dom->id); + goto cleanup; + } + + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SAVED); + + if (libxlVmReap(driver, vm, 1) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to destroy domain '%d'"), dom->id); + goto cleanup; + } + + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + ret = 0; + } +cleanup: + VIR_FREE(xml); + if (VIR_CLOSE(fd) < 0) + virReportSystemError(errno, "%s", _("cannot close file")); + if (vm) + virDomainObjUnlock(vm); + if (event) + libxlDomainEventQueue(driver, event); + libxlDriverUnlock(driver); + return ret; +} + +static int +libxlDomainRestore(virConnectPtr conn, const char * from) +{ + libxlDriverPrivatePtr driver = conn->privateData; + virDomainDefPtr def = NULL; + virDomainObjPtr vm = NULL; + virDomainEventPtr event = NULL; + libxlSavefileHeader hdr; + char * xml = NULL; + int fd; + int ret = -1; + + libxlDriverLock(driver); + + if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) { + libxlError(VIR_ERR_OPERATION_FAILED, + "%s", _("cannot read domain image")); + goto cleanup; + } + + if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + libxlError(VIR_ERR_OPERATION_FAILED, + "%s", _("failed to read libxl header")); + goto cleanup; + } + + if (memcmp(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic))) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); + goto cleanup; + } + + if (hdr.xmlLen <= 0) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("invalid XML length: %d"), hdr.xmlLen); + goto cleanup; + } + + if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { + libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); + goto cleanup; + } + + if (!(def = virDomainDefParseString(driver->caps, xml, 0))) + goto cleanup; + + if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0) + goto cleanup; + + if (!(vm = virDomainAssignDef(driver->caps, &driver->domains, def, false))) + goto cleanup; + + def = NULL; + + ret = libxlVmStart(driver, vm, false); + + if (ret == 0) { + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_RESTORED); + } else if (ret < 0 && !vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + +cleanup: + VIR_FREE(xml); + virDomainDefFree(def); + if (VIR_CLOSE(fd) < 0) + virReportSystemError(errno, "%s", _("cannot close file")); + if (vm) + virDomainObjUnlock(vm); + if (event) + libxlDomainEventQueue(driver, event); + libxlDriverUnlock(driver); + return ret; +} + +static int libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) { @@ -2658,8 +2836,8 @@ static virDriver libxlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ libxlDomainGetInfo, /* domainGetInfo */ - NULL, /* domainSave */ - NULL, /* domainRestore */ + libxlDomainSave, /* domainSave */ + libxlDomainRestore, /* domainRestore */ NULL, /* domainCoreDump */ libxlDomainSetVcpus, /* domainSetVcpus */ libxlDomainSetVcpusFlags, /* domainSetVcpusFlags */ -- 1.7.4.3

Markus Groß wrote:
--- src/libxl/libxl_conf.h | 10 +++ src/libxl/libxl_driver.c | 184 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 191 insertions(+), 3 deletions(-)
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index f2f0d8a..e28615b 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -1,5 +1,6 @@ /*---------------------------------------------------------------------------*/ /* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. + * Copyright (C) 2011 Univention GmbH. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,7 @@ * * Authors: * Jim Fehlig <jfehlig@novell.com> + * Markus Groß <gross@univention.de> */ /*---------------------------------------------------------------------------*/
@@ -85,6 +87,14 @@ struct _libxlDomainObjPrivate { int eventHdl; };
+static const char libxlSavefileMagic[16]= "libvirt-xml\n \0 \r"; +typedef struct _libxlSavefileHeader libxlSavefileHeader; +typedef libxlSavefileHeader *libxlSavefileHeaderPtr; +struct _libxlSavefileHeader { + char magic[16]; /* magic id */ + uint32_t xmlLen; /* length of saved xml */ +};
I think we should pad the header, similar to qemu driver, and provide a version field.
+
# define libxlError(code, ...) \ virReportErrorHelper(NULL, VIR_FROM_LIBXL, code, __FILE__, \ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 1539385..b02d4b7 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -29,6 +29,7 @@ #include <sys/utsname.h> #include <math.h> #include <libxl.h> +#include <fcntl.h>
#include "internal.h" #include "logging.h" @@ -60,7 +61,6 @@
static libxlDriverPrivatePtr libxl_driver = NULL;
- /* Function declarations */ static int libxlVmStart(libxlDriverPrivatePtr driver, @@ -1555,6 +1555,184 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) }
static int +libxlDomainSave(virDomainPtr dom, const char * to) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm; + libxlDomainObjPrivatePtr priv; + virDomainEventPtr event = NULL; + libxlSavefileHeader hdr; + libxl_domain_suspend_info s_info; + char * xml; + uint32_t xml_len; + int fd; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + libxlError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (vm->state != VIR_DOMAIN_PAUSED) { + memset(&s_info, 0, sizeof(s_info)); + + if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR, + getuid(), getgid(), 0)) < 0) { + virReportSystemError(-fd, + _("Failed to create domain save file '%s'"), + to); + goto cleanup; + } + + if ((xml = virDomainDefFormat(vm->def, 0)) == NULL) + goto cleanup; + xml_len = strlen(xml) + 1; + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic)); + hdr.xmlLen = xml_len; + + if (safewrite(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("Failed to write save file header")); + goto cleanup; + } + + if (safewrite(fd, xml, xml_len) != xml_len) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("Failed to write xml description")); + goto cleanup; + } + + if (libxl_domain_suspend(&priv->ctx, &s_info, dom->id, fd) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to save domain '%d' with libxenlight"), + dom->id); + goto cleanup; + } + + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SAVED); + + if (libxlVmReap(driver, vm, 1) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to destroy domain '%d'"), dom->id); + goto cleanup; + } + + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + ret = 0; + } +cleanup: + VIR_FREE(xml); + if (VIR_CLOSE(fd) < 0) + virReportSystemError(errno, "%s", _("cannot close file")); + if (vm) + virDomainObjUnlock(vm); + if (event) + libxlDomainEventQueue(driver, event); + libxlDriverUnlock(driver); + return ret; +} + +static int +libxlDomainRestore(virConnectPtr conn, const char * from) +{ + libxlDriverPrivatePtr driver = conn->privateData; + virDomainDefPtr def = NULL; + virDomainObjPtr vm = NULL; + virDomainEventPtr event = NULL; + libxlSavefileHeader hdr; + char * xml = NULL; + int fd; + int ret = -1; + + libxlDriverLock(driver); + + if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) { + libxlError(VIR_ERR_OPERATION_FAILED, + "%s", _("cannot read domain image")); + goto cleanup; + } + + if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + libxlError(VIR_ERR_OPERATION_FAILED, + "%s", _("failed to read libxl header")); + goto cleanup; + } + + if (memcmp(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic))) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); + goto cleanup; + } + + if (hdr.xmlLen <= 0) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("invalid XML length: %d"), hdr.xmlLen); + goto cleanup; + } + + if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { + libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); + goto cleanup; + } + + if (!(def = virDomainDefParseString(driver->caps, xml, 0))) + goto cleanup; + + if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0) + goto cleanup; + + if (!(vm = virDomainAssignDef(driver->caps, &driver->domains, def, false))) + goto cleanup; + + def = NULL; + + ret = libxlVmStart(driver, vm, false);
This starts a new domain. To restore a domain, you need to use libxl_domain_create_restore(). Regards, Jim
+ + if (ret == 0) { + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_RESTORED); + } else if (ret < 0 && !vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + +cleanup: + VIR_FREE(xml); + virDomainDefFree(def); + if (VIR_CLOSE(fd) < 0) + virReportSystemError(errno, "%s", _("cannot close file")); + if (vm) + virDomainObjUnlock(vm); + if (event) + libxlDomainEventQueue(driver, event); + libxlDriverUnlock(driver); + return ret; +} + +static int libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) { @@ -2658,8 +2836,8 @@ static virDriver libxlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ libxlDomainGetInfo, /* domainGetInfo */ - NULL, /* domainSave */ - NULL, /* domainRestore */ + libxlDomainSave, /* domainSave */ + libxlDomainRestore, /* domainRestore */ NULL, /* domainCoreDump */ libxlDomainSetVcpus, /* domainSetVcpus */ libxlDomainSetVcpusFlags, /* domainSetVcpusFlags */

Thanks Jim for the review of patch 3 and 4. I will rework them and post a v2 as soon as I am back from vacation. Cheers, Markus Quoting Jim Fehlig <jfehlig@novell.com>:
Markus Groß wrote:
--- src/libxl/libxl_conf.h | 10 +++ src/libxl/libxl_driver.c | 184 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 191 insertions(+), 3 deletions(-)
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index f2f0d8a..e28615b 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -1,5 +1,6 @@
/*---------------------------------------------------------------------------*/ /* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. + * Copyright (C) 2011 Univention GmbH. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,7 @@ * * Authors: * Jim Fehlig <jfehlig@novell.com> + * Markus Groß <gross@univention.de> */
/*---------------------------------------------------------------------------*/
@@ -85,6 +87,14 @@ struct _libxlDomainObjPrivate { int eventHdl; };
+static const char libxlSavefileMagic[16]= "libvirt-xml\n \0 \r"; +typedef struct _libxlSavefileHeader libxlSavefileHeader; +typedef libxlSavefileHeader *libxlSavefileHeaderPtr; +struct _libxlSavefileHeader { + char magic[16]; /* magic id */ + uint32_t xmlLen; /* length of saved xml */ +};
I think we should pad the header, similar to qemu driver, and provide a version field.
+
# define libxlError(code, ...) \ virReportErrorHelper(NULL, VIR_FROM_LIBXL, code, __FILE__, \ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 1539385..b02d4b7 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -29,6 +29,7 @@ #include <sys/utsname.h> #include <math.h> #include <libxl.h> +#include <fcntl.h>
#include "internal.h" #include "logging.h" @@ -60,7 +61,6 @@
static libxlDriverPrivatePtr libxl_driver = NULL;
- /* Function declarations */ static int libxlVmStart(libxlDriverPrivatePtr driver, @@ -1555,6 +1555,184 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) }
static int +libxlDomainSave(virDomainPtr dom, const char * to) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm; + libxlDomainObjPrivatePtr priv; + virDomainEventPtr event = NULL; + libxlSavefileHeader hdr; + libxl_domain_suspend_info s_info; + char * xml; + uint32_t xml_len; + int fd; + int ret = -1; + + libxlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + libxlError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (vm->state != VIR_DOMAIN_PAUSED) { + memset(&s_info, 0, sizeof(s_info)); + + if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR, + getuid(), getgid(), 0)) < 0) { + virReportSystemError(-fd, + _("Failed to create domain save file '%s'"), + to); + goto cleanup; + } + + if ((xml = virDomainDefFormat(vm->def, 0)) == NULL) + goto cleanup; + xml_len = strlen(xml) + 1; + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic)); + hdr.xmlLen = xml_len; + + if (safewrite(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("Failed to write save file header")); + goto cleanup; + } + + if (safewrite(fd, xml, xml_len) != xml_len) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("Failed to write xml description")); + goto cleanup; + } + + if (libxl_domain_suspend(&priv->ctx, &s_info, dom->id, fd) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to save domain '%d' with libxenlight"), + dom->id); + goto cleanup; + } + + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SAVED); + + if (libxlVmReap(driver, vm, 1) != 0) { + libxlError(VIR_ERR_INTERNAL_ERROR, + _("Failed to destroy domain '%d'"), dom->id); + goto cleanup; + } + + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + ret = 0; + } +cleanup: + VIR_FREE(xml); + if (VIR_CLOSE(fd) < 0) + virReportSystemError(errno, "%s", _("cannot close file")); + if (vm) + virDomainObjUnlock(vm); + if (event) + libxlDomainEventQueue(driver, event); + libxlDriverUnlock(driver); + return ret; +} + +static int +libxlDomainRestore(virConnectPtr conn, const char * from) +{ + libxlDriverPrivatePtr driver = conn->privateData; + virDomainDefPtr def = NULL; + virDomainObjPtr vm = NULL; + virDomainEventPtr event = NULL; + libxlSavefileHeader hdr; + char * xml = NULL; + int fd; + int ret = -1; + + libxlDriverLock(driver); + + if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) { + libxlError(VIR_ERR_OPERATION_FAILED, + "%s", _("cannot read domain image")); + goto cleanup; + } + + if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + libxlError(VIR_ERR_OPERATION_FAILED, + "%s", _("failed to read libxl header")); + goto cleanup; + } + + if (memcmp(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic))) { + libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); + goto cleanup; + } + + if (hdr.xmlLen <= 0) { + libxlError(VIR_ERR_OPERATION_FAILED, + _("invalid XML length: %d"), hdr.xmlLen); + goto cleanup; + } + + if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { + libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); + goto cleanup; + } + + if (!(def = virDomainDefParseString(driver->caps, xml, 0))) + goto cleanup; + + if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0) + goto cleanup; + + if (!(vm = virDomainAssignDef(driver->caps, &driver->domains, def, false))) + goto cleanup; + + def = NULL; + + ret = libxlVmStart(driver, vm, false);
This starts a new domain. To restore a domain, you need to use libxl_domain_create_restore().
Regards, Jim
+ + if (ret == 0) { + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_RESTORED); + } else if (ret < 0 && !vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + +cleanup: + VIR_FREE(xml); + virDomainDefFree(def); + if (VIR_CLOSE(fd) < 0) + virReportSystemError(errno, "%s", _("cannot close file")); + if (vm) + virDomainObjUnlock(vm); + if (event) + libxlDomainEventQueue(driver, event); + libxlDriverUnlock(driver); + return ret; +} + +static int libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) { @@ -2658,8 +2836,8 @@ static virDriver libxlDriver = { NULL, /* domainSetBlkioParameters */ NULL, /* domainGetBlkioParameters */ libxlDomainGetInfo, /* domainGetInfo */ - NULL, /* domainSave */ - NULL, /* domainRestore */ + libxlDomainSave, /* domainSave */ + libxlDomainRestore, /* domainRestore */ NULL, /* domainCoreDump */ libxlDomainSetVcpus, /* domainSetVcpus */ libxlDomainSetVcpusFlags, /* domainSetVcpusFlags */
participants (3)
-
Jim Fehlig
-
Markus Gross
-
Markus Groß