2013-08-30 17:18:31 +00:00
|
|
|
/*
|
|
|
|
* libxl_domain.c: libxl domain object private state
|
|
|
|
*
|
2015-02-02 21:12:58 +00:00
|
|
|
* Copyright (C) 2011-2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
2013-08-30 17:18:31 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2014-02-26 04:28:51 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
#include "libxl_domain.h"
|
2016-03-04 18:35:20 +00:00
|
|
|
#include "libxl_capabilities.h"
|
2013-08-30 17:18:31 +00:00
|
|
|
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virfile.h"
|
|
|
|
#include "virerror.h"
|
2016-07-11 11:55:53 +00:00
|
|
|
#include "virhook.h"
|
2013-08-30 17:18:31 +00:00
|
|
|
#include "virlog.h"
|
|
|
|
#include "virstring.h"
|
2013-12-19 05:54:39 +00:00
|
|
|
#include "virtime.h"
|
2015-04-14 20:38:46 +00:00
|
|
|
#include "locking/domain_lock.h"
|
2016-01-11 11:40:32 +00:00
|
|
|
#include "xen_common.h"
|
2018-07-26 14:32:04 +00:00
|
|
|
#include "driver.h"
|
2013-08-30 17:18:31 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_LIBXL
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("libxl.libxl_domain");
|
2013-08-30 17:18:31 +00:00
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(libxlDomainJob,
|
|
|
|
LIBXL_JOB_LAST,
|
2013-12-19 05:54:39 +00:00
|
|
|
"none",
|
|
|
|
"query",
|
|
|
|
"destroy",
|
|
|
|
"modify",
|
|
|
|
);
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
static virClassPtr libxlDomainObjPrivateClass;
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainObjPrivateDispose(void *obj);
|
|
|
|
|
|
|
|
static int
|
|
|
|
libxlDomainObjPrivateOnceInit(void)
|
|
|
|
{
|
2018-04-17 15:42:33 +00:00
|
|
|
if (!VIR_CLASS_NEW(libxlDomainObjPrivate, virClassForObjectLockable()))
|
2013-08-30 17:18:31 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:23:29 +00:00
|
|
|
VIR_ONCE_GLOBAL_INIT(libxlDomainObjPrivate);
|
2013-08-30 17:18:31 +00:00
|
|
|
|
2013-12-19 05:54:39 +00:00
|
|
|
static int
|
|
|
|
libxlDomainObjInitJob(libxlDomainObjPrivatePtr priv)
|
|
|
|
{
|
|
|
|
memset(&priv->job, 0, sizeof(priv->job));
|
|
|
|
|
|
|
|
if (virCondInit(&priv->job.cond) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-09-23 18:43:09 +00:00
|
|
|
priv->job.current = g_new0(virDomainJobInfo, 1);
|
2015-11-13 13:14:47 +00:00
|
|
|
|
2013-12-19 05:54:39 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainObjResetJob(libxlDomainObjPrivatePtr priv)
|
|
|
|
{
|
|
|
|
struct libxlDomainJobObj *job = &priv->job;
|
|
|
|
|
|
|
|
job->active = LIBXL_JOB_NONE;
|
|
|
|
job->owner = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainObjFreeJob(libxlDomainObjPrivatePtr priv)
|
|
|
|
{
|
|
|
|
ignore_value(virCondDestroy(&priv->job.cond));
|
2015-11-13 13:14:47 +00:00
|
|
|
VIR_FREE(priv->job.current);
|
2013-12-19 05:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Give up waiting for mutex after 30 seconds */
|
|
|
|
#define LIBXL_JOB_WAIT_TIME (1000ull * 30)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* obj must be locked before calling, libxlDriverPrivatePtr must NOT be locked
|
|
|
|
*
|
|
|
|
* This must be called by anything that will change the VM state
|
|
|
|
* in any way
|
|
|
|
*
|
|
|
|
* Upon successful return, the object will have its ref count increased,
|
|
|
|
* successful calls must be followed by EndJob eventually
|
|
|
|
*/
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
libxlDomainObjBeginJob(libxlDriverPrivatePtr driver G_GNUC_UNUSED,
|
2013-12-19 05:54:39 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
enum libxlDomainJob job)
|
|
|
|
{
|
|
|
|
libxlDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
unsigned long long now;
|
|
|
|
unsigned long long then;
|
|
|
|
|
|
|
|
if (virTimeMillisNow(&now) < 0)
|
|
|
|
return -1;
|
|
|
|
then = now + LIBXL_JOB_WAIT_TIME;
|
|
|
|
|
|
|
|
while (priv->job.active) {
|
|
|
|
VIR_DEBUG("Wait normal job condition for starting job: %s",
|
|
|
|
libxlDomainJobTypeToString(job));
|
|
|
|
if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
libxlDomainObjResetJob(priv);
|
|
|
|
|
|
|
|
VIR_DEBUG("Starting job: %s", libxlDomainJobTypeToString(job));
|
|
|
|
priv->job.active = job;
|
|
|
|
priv->job.owner = virThreadSelfID();
|
2015-11-13 13:14:47 +00:00
|
|
|
priv->job.started = now;
|
|
|
|
priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
|
2013-12-19 05:54:39 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:51:17 +00:00
|
|
|
error:
|
2013-12-19 05:54:39 +00:00
|
|
|
VIR_WARN("Cannot start job (%s) for domain %s;"
|
|
|
|
" current job is (%s) owned by (%d)",
|
|
|
|
libxlDomainJobTypeToString(job),
|
|
|
|
obj->def->name,
|
|
|
|
libxlDomainJobTypeToString(priv->job.active),
|
|
|
|
priv->job.owner);
|
|
|
|
|
|
|
|
if (errno == ETIMEDOUT)
|
|
|
|
virReportError(VIR_ERR_OPERATION_TIMEOUT,
|
|
|
|
"%s", _("cannot acquire state change lock"));
|
|
|
|
else
|
|
|
|
virReportSystemError(errno,
|
|
|
|
"%s", _("cannot acquire job mutex"));
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* obj must be locked before calling
|
|
|
|
*
|
|
|
|
* To be called after completing the work associated with the
|
|
|
|
* earlier libxlDomainBeginJob() call
|
|
|
|
*
|
|
|
|
* Returns true if the remaining reference count on obj is
|
|
|
|
* non-zero, false if the reference count has dropped to zero
|
|
|
|
* and obj is disposed.
|
|
|
|
*/
|
2016-06-12 10:30:00 +00:00
|
|
|
void
|
2019-10-14 12:45:33 +00:00
|
|
|
libxlDomainObjEndJob(libxlDriverPrivatePtr driver G_GNUC_UNUSED,
|
2013-12-19 05:54:39 +00:00
|
|
|
virDomainObjPtr obj)
|
|
|
|
{
|
|
|
|
libxlDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
enum libxlDomainJob job = priv->job.active;
|
|
|
|
|
|
|
|
VIR_DEBUG("Stopping job: %s",
|
|
|
|
libxlDomainJobTypeToString(job));
|
|
|
|
|
|
|
|
libxlDomainObjResetJob(priv);
|
|
|
|
virCondSignal(&priv->job.cond);
|
|
|
|
}
|
|
|
|
|
2015-11-13 13:14:47 +00:00
|
|
|
int
|
|
|
|
libxlDomainJobUpdateTime(struct libxlDomainJobObj *job)
|
|
|
|
{
|
|
|
|
virDomainJobInfoPtr jobInfo = job->current;
|
|
|
|
unsigned long long now;
|
|
|
|
|
|
|
|
if (!job->started)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virTimeMillisNow(&now) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (now < job->started) {
|
|
|
|
job->started = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
jobInfo->timeElapsed = now - job->started;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
static void *
|
2019-10-14 12:45:33 +00:00
|
|
|
libxlDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED)
|
2013-08-30 17:18:31 +00:00
|
|
|
{
|
|
|
|
libxlDomainObjPrivatePtr priv;
|
|
|
|
|
|
|
|
if (libxlDomainObjPrivateInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(priv = virObjectLockableNew(libxlDomainObjPrivateClass)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(priv->devs = virChrdevAlloc())) {
|
|
|
|
virObjectUnref(priv);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-19 05:54:39 +00:00
|
|
|
if (libxlDomainObjInitJob(priv) < 0) {
|
|
|
|
virChrdevFree(priv->devs);
|
|
|
|
virObjectUnref(priv);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
return priv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainObjPrivateDispose(void *obj)
|
|
|
|
{
|
|
|
|
libxlDomainObjPrivatePtr priv = obj;
|
|
|
|
|
2013-12-19 05:54:39 +00:00
|
|
|
libxlDomainObjFreeJob(priv);
|
2013-08-30 17:18:31 +00:00
|
|
|
virChrdevFree(priv->devs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainObjPrivateFree(void *data)
|
|
|
|
{
|
|
|
|
libxlDomainObjPrivatePtr priv = data;
|
|
|
|
|
2015-04-14 20:38:46 +00:00
|
|
|
VIR_FREE(priv->lockState);
|
2013-08-30 17:18:31 +00:00
|
|
|
virObjectUnref(priv);
|
|
|
|
}
|
|
|
|
|
2015-04-14 20:38:46 +00:00
|
|
|
static int
|
2015-05-19 08:14:19 +00:00
|
|
|
libxlDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
|
2015-07-24 17:35:00 +00:00
|
|
|
virDomainObjPtr vm,
|
2019-10-14 12:45:33 +00:00
|
|
|
virDomainDefParserConfigPtr config G_GNUC_UNUSED)
|
2015-04-14 20:38:46 +00:00
|
|
|
{
|
2015-05-19 08:14:19 +00:00
|
|
|
libxlDomainObjPrivatePtr priv = vm->privateData;
|
2015-04-14 20:38:46 +00:00
|
|
|
|
|
|
|
priv->lockState = virXPathString("string(./lockstate)", ctxt);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2015-05-19 08:14:19 +00:00
|
|
|
libxlDomainObjPrivateXMLFormat(virBufferPtr buf,
|
|
|
|
virDomainObjPtr vm)
|
2015-04-14 20:38:46 +00:00
|
|
|
{
|
2015-05-19 08:14:19 +00:00
|
|
|
libxlDomainObjPrivatePtr priv = vm->privateData;
|
2015-04-14 20:38:46 +00:00
|
|
|
|
|
|
|
if (priv->lockState)
|
|
|
|
virBufferAsprintf(buf, "<lockstate>%s</lockstate>\n", priv->lockState);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
virDomainXMLPrivateDataCallbacks libxlDomainXMLPrivateDataCallbacks = {
|
|
|
|
.alloc = libxlDomainObjPrivateAlloc,
|
|
|
|
.free = libxlDomainObjPrivateFree,
|
2015-04-14 20:38:46 +00:00
|
|
|
.parse = libxlDomainObjPrivateXMLParse,
|
|
|
|
.format = libxlDomainObjPrivateXMLFormat,
|
2013-08-30 17:18:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
maint: avoid 'const fooPtr' in domain_conf
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/conf/domain_conf, and their fallout.
Several things to note: virObjectLock() requires a non-const
argument; if this were C++, we could treat the locking field
as 'mutable' and allow locking an otherwise 'const' object, but
that is a more invasive change, so I instead dropped attempts
to be const-correct on domain lookup. virXMLPropString and
friends require a non-const xmlNodePtr - this is because libxml2
is not a const-correct library. We could make the src/util/virxml
wrappers cast away const, but I figured it was easier to not
try to mark xmlNodePtr as const. Finally, virDomainDeviceDefCopy
was a rather hard conversion - it calls virDomainDeviceDefPostParse,
which in turn in the xen driver was actually modifying the domain
outside of the current device being visited. We should not be
adding a device on the first per-device callback, but waiting until
after all per-device callbacks are complete.
* src/conf/domain_conf.h (virDomainObjListFindByID)
(virDomainObjListFindByUUID, virDomainObjListFindByName)
(virDomainObjAssignDef, virDomainObjListAdd): Drop attempt at
const.
(virDomainDeviceDefCopy): Use intended type.
(virDomainDeviceDefParse, virDomainDeviceDefPostParseCallback)
(virDomainVideoDefaultType, virDomainVideoDefaultRAM)
(virDomainChrGetDomainPtrs): Make const-correct.
* src/conf/domain_conf.c (virDomainObjListFindByID)
(virDomainObjListFindByUUID, virDomainObjListFindByName)
(virDomainDeviceDefCopy, virDomainObjListAdd)
(virDomainObjAssignDef, virDomainHostdevSubsysUsbDefParseXML)
(virDomainHostdevSubsysPciOrigStatesDefParseXML)
(virDomainHostdevSubsysPciDefParseXML)
(virDomainHostdevSubsysScsiDefParseXML)
(virDomainControllerModelTypeFromString)
(virDomainTPMDefParseXML, virDomainTimerDefParseXML)
(virDomainSoundCodecDefParseXML, virDomainSoundDefParseXML)
(virDomainWatchdogDefParseXML, virDomainRNGDefParseXML)
(virDomainMemballoonDefParseXML, virDomainNVRAMDefParseXML)
(virSysinfoParseXML, virDomainVideoAccelDefParseXML)
(virDomainVideoDefParseXML, virDomainHostdevDefParseXML)
(virDomainRedirdevDefParseXML)
(virDomainRedirFilterUsbDevDefParseXML)
(virDomainRedirFilterDefParseXML, virDomainIdMapEntrySort)
(virDomainIdmapDefParseXML, virDomainVcpuPinDefParseXML)
(virDiskNameToBusDeviceIndex, virDomainDeviceDefCopy)
(virDomainVideoDefaultType, virDomainHostdevAssignAddress)
(virDomainDeviceDefPostParseInternal, virDomainDeviceDefPostParse)
(virDomainChrGetDomainPtrs, virDomainControllerSCSINextUnit)
(virDomainSCSIDriveAddressIsUsed)
(virDomainDriveAddressIsUsedByDisk)
(virDomainDriveAddressIsUsedByHostdev): Fix fallout.
* src/openvz/openvz_driver.c (openvzDomainDeviceDefPostParse):
Likewise.
* src/libxl/libxl_domain.c (libxlDomainDeviceDefPostParse):
Likewise.
* src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse)
(qemuDomainDefaultNetModel): Likewise.
* src/lxc/lxc_domain.c (virLXCDomainDeviceDefPostParse):
Likewise.
* src/uml/uml_driver.c (umlDomainDeviceDefPostParse): Likewise.
* src/xen/xen_driver.c (xenDomainDeviceDefPostParse): Split...
(xenDomainDefPostParse): ...since per-device callback is not the
time to be adding a device.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-08 15:08:25 +00:00
|
|
|
const virDomainDef *def,
|
2019-10-14 12:45:33 +00:00
|
|
|
unsigned int parseFlags G_GNUC_UNUSED,
|
|
|
|
void *opaque G_GNUC_UNUSED,
|
|
|
|
void *parseOpaque G_GNUC_UNUSED)
|
2013-08-30 17:18:31 +00:00
|
|
|
{
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
|
|
|
|
dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
|
|
|
|
dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE &&
|
2015-04-17 00:11:06 +00:00
|
|
|
def->os.type != VIR_DOMAIN_OSTYPE_HVM)
|
2013-08-30 17:18:31 +00:00
|
|
|
dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
|
|
|
|
2014-07-15 05:03:15 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV ||
|
|
|
|
(dev->type == VIR_DOMAIN_DEVICE_NET &&
|
|
|
|
dev->data.net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
|
|
|
|
|
|
|
|
virDomainHostdevDefPtr hostdev;
|
2014-07-03 20:31:39 +00:00
|
|
|
virDomainHostdevSubsysPCIPtr pcisrc;
|
2014-07-15 05:03:15 +00:00
|
|
|
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_NET)
|
2016-02-23 08:07:58 +00:00
|
|
|
hostdev = &dev->data.net->data.hostdev.def;
|
2014-07-15 05:03:15 +00:00
|
|
|
else
|
|
|
|
hostdev = dev->data.hostdev;
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc = &hostdev->source.subsys.u.pci;
|
2014-03-06 08:44:22 +00:00
|
|
|
|
2014-06-25 06:45:59 +00:00
|
|
|
/* forbid capabilities mode hostdev in this kind of hypervisor */
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev mode 'capabilities' is not "
|
|
|
|
"supported in %s"),
|
|
|
|
virDomainVirtTypeToString(def->virtType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-03-06 08:44:22 +00:00
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
|
2014-07-03 20:31:39 +00:00
|
|
|
pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)
|
|
|
|
pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
|
2014-03-06 08:44:22 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 16:14:31 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) {
|
|
|
|
if (dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT) {
|
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
|
|
|
|
def->os.type == VIR_DOMAIN_OSTYPE_LINUX)
|
|
|
|
dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
|
|
|
|
else if (ARCH_IS_PPC64(def->os.arch))
|
|
|
|
dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VGA;
|
|
|
|
else
|
|
|
|
dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
|
|
|
int dm_type = libxlDomainGetEmulatorType(def);
|
|
|
|
|
|
|
|
switch (dev->data.video->type) {
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VGA:
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_XEN:
|
|
|
|
if (dev->data.video->vram == 0) {
|
|
|
|
if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
|
|
|
|
dev->data.video->vram = 16 * 1024;
|
|
|
|
else
|
|
|
|
dev->data.video->vram = 8 * 1024;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
|
|
|
|
if (dev->data.video->vram == 0) {
|
|
|
|
if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
|
|
|
|
dev->data.video->vram = 8 * 1024;
|
|
|
|
else
|
|
|
|
dev->data.video->vram = 4 * 1024;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_QXL:
|
|
|
|
if (dev->data.video->vram == 0)
|
|
|
|
dev->data.video->vram = 128 * 1024;
|
|
|
|
break;
|
2014-07-01 07:58:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-23 21:56:01 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
virDomainDiskDefPtr disk = dev->data.disk;
|
|
|
|
int actual_type = virStorageSourceGetActualType(disk->src);
|
2017-02-07 18:00:33 +00:00
|
|
|
int format = virDomainDiskGetFormat(disk);
|
2016-05-23 21:56:01 +00:00
|
|
|
|
2017-02-07 18:00:33 +00:00
|
|
|
/* for network-based disks, set 'qemu' as the default driver */
|
2016-05-23 21:56:01 +00:00
|
|
|
if (actual_type == VIR_STORAGE_TYPE_NETWORK) {
|
|
|
|
if (!virDomainDiskGetDriver(disk) &&
|
|
|
|
virDomainDiskSetDriver(disk, "qemu") < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2017-02-07 18:00:33 +00:00
|
|
|
|
|
|
|
/* xl.cfg default format is raw. See xl-disk-configuration(5) */
|
|
|
|
if (format == VIR_STORAGE_FILE_NONE)
|
|
|
|
virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
|
2016-05-23 21:56:01 +00:00
|
|
|
}
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-30 16:20:38 +00:00
|
|
|
static int
|
|
|
|
libxlDomainDefPostParse(virDomainDefPtr def,
|
2019-10-14 12:45:33 +00:00
|
|
|
unsigned int parseFlags G_GNUC_UNUSED,
|
2019-12-03 10:49:49 +00:00
|
|
|
void *opaque,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *parseOpaque G_GNUC_UNUSED)
|
2014-06-30 16:20:38 +00:00
|
|
|
{
|
2019-12-03 10:49:49 +00:00
|
|
|
libxlDriverPrivatePtr driver = opaque;
|
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
|
|
|
|
|
|
|
if (!virCapabilitiesDomainSupported(cfg->caps, def->os.type,
|
2019-11-26 16:09:33 +00:00
|
|
|
def->os.arch,
|
|
|
|
def->virtType))
|
|
|
|
return -1;
|
|
|
|
|
2015-03-16 14:33:45 +00:00
|
|
|
/* Xen PV domains always have a PV console, so add one to the domain config
|
|
|
|
* via post-parse callback if not explicitly specified in the XML. */
|
2015-04-17 00:11:06 +00:00
|
|
|
if (def->os.type != VIR_DOMAIN_OSTYPE_HVM && def->nconsoles == 0) {
|
2014-06-30 16:20:38 +00:00
|
|
|
virDomainChrDefPtr chrdef;
|
|
|
|
|
2016-06-17 10:36:11 +00:00
|
|
|
if (!(chrdef = virDomainChrDefNew(NULL)))
|
2014-06-30 16:20:38 +00:00
|
|
|
return -1;
|
|
|
|
|
2016-10-21 11:45:54 +00:00
|
|
|
chrdef->source->type = VIR_DOMAIN_CHR_TYPE_PTY;
|
2014-06-30 16:20:38 +00:00
|
|
|
chrdef->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
|
|
|
|
chrdef->target.port = 0;
|
|
|
|
chrdef->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
|
|
|
|
|
2020-09-23 18:43:09 +00:00
|
|
|
def->consoles = g_new0(virDomainChrDefPtr, 1);
|
2014-06-30 16:20:38 +00:00
|
|
|
def->nconsoles = 1;
|
|
|
|
def->consoles[0] = chrdef;
|
|
|
|
}
|
2014-08-11 15:40:32 +00:00
|
|
|
|
2016-01-11 11:40:32 +00:00
|
|
|
/* add implicit input devices */
|
|
|
|
if (xenDomainDefAddImplicitInputDevice(def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-11-02 15:47:22 +00:00
|
|
|
/* For x86_64 HVM */
|
2017-01-12 00:42:42 +00:00
|
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
|
|
|
|
def->os.arch == VIR_ARCH_X86_64) {
|
2017-11-02 15:47:22 +00:00
|
|
|
/* always enable pae */
|
2017-01-12 00:42:42 +00:00
|
|
|
def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
|
2017-11-02 15:47:22 +00:00
|
|
|
|
|
|
|
/* if vnuma is effective enable acpi */
|
|
|
|
if (virDomainNumaGetNodeCount(def->numa) > 0)
|
|
|
|
def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
|
2017-01-12 00:42:42 +00:00
|
|
|
}
|
|
|
|
|
2018-04-10 00:15:17 +00:00
|
|
|
/* add implicit balloon device */
|
|
|
|
if (def->memballoon == NULL) {
|
|
|
|
virDomainMemballoonDefPtr memballoon;
|
2020-09-23 18:43:09 +00:00
|
|
|
memballoon = g_new0(virDomainMemballoonDef,
|
|
|
|
1);
|
2018-04-10 00:15:17 +00:00
|
|
|
|
|
|
|
memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_XEN;
|
|
|
|
def->memballoon = memballoon;
|
|
|
|
}
|
|
|
|
|
2019-03-07 00:43:21 +00:00
|
|
|
/* add implicit xenbus device */
|
|
|
|
if (virDomainControllerFindByType(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS) == -1)
|
|
|
|
if (virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS, -1, -1) == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2014-06-30 16:20:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-30 17:18:31 +00:00
|
|
|
virDomainDefParserConfig libxlDomainDefParserConfig = {
|
|
|
|
.macPrefix = { 0x00, 0x16, 0x3e },
|
2019-11-26 16:44:40 +00:00
|
|
|
.netPrefix = LIBXL_GENERATED_PREFIX_XEN,
|
2013-08-30 17:18:31 +00:00
|
|
|
.devicesPostParseCallback = libxlDomainDeviceDefPostParse,
|
2014-06-30 16:20:38 +00:00
|
|
|
.domainPostParseCallback = libxlDomainDefPostParse,
|
2019-01-18 20:57:32 +00:00
|
|
|
.features = VIR_DOMAIN_DEF_FEATURE_NET_MODEL_STRING,
|
2013-08-30 17:18:31 +00:00
|
|
|
};
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
|
2018-10-31 16:54:14 +00:00
|
|
|
static void
|
|
|
|
libxlDomainShutdownHandleDestroy(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
libxlDomainDestroyInternal(driver, vm);
|
|
|
|
libxlDomainCleanup(driver, vm);
|
|
|
|
if (!vm->persistent)
|
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainShutdownHandleRestart(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
libxlDomainDestroyInternal(driver, vm);
|
|
|
|
libxlDomainCleanup(driver, vm);
|
|
|
|
if (libxlDomainStartNew(driver, vm, false) < 0) {
|
|
|
|
VIR_ERROR(_("Failed to restart VM '%s': %s"),
|
|
|
|
vm->def->name, virGetLastErrorMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
struct libxlShutdownThreadInfo
|
|
|
|
{
|
2015-02-11 22:22:05 +00:00
|
|
|
libxlDriverPrivatePtr driver;
|
2014-02-26 22:50:57 +00:00
|
|
|
libxl_event *event;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainShutdownThread(void *opaque)
|
|
|
|
{
|
|
|
|
struct libxlShutdownThreadInfo *shutdown_info = opaque;
|
2016-09-21 21:02:34 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2014-02-26 22:50:57 +00:00
|
|
|
libxl_event *ev = shutdown_info->event;
|
2015-02-11 22:22:05 +00:00
|
|
|
libxlDriverPrivatePtr driver = shutdown_info->driver;
|
2014-02-26 22:50:57 +00:00
|
|
|
virObjectEventPtr dom_event = NULL;
|
|
|
|
libxl_shutdown_reason xl_reason = ev->u.domain_shutdown.shutdown_reason;
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2018-10-31 17:03:37 +00:00
|
|
|
libxl_domain_config d_config;
|
2014-02-26 22:50:57 +00:00
|
|
|
|
2018-10-31 17:03:37 +00:00
|
|
|
libxl_domain_config_init(&d_config);
|
2014-02-26 22:50:57 +00:00
|
|
|
|
2018-03-09 15:59:28 +00:00
|
|
|
vm = virDomainObjListFindByID(driver->domains, ev->domid);
|
2016-09-21 21:02:34 +00:00
|
|
|
if (!vm) {
|
|
|
|
VIR_INFO("Received event for unknown domain ID %d", ev->domid);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-03-01 23:22:07 +00:00
|
|
|
if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
if (xl_reason == LIBXL_SHUTDOWN_REASON_POWEROFF) {
|
2015-07-07 18:29:24 +00:00
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
|
|
|
|
VIR_DOMAIN_SHUTOFF_SHUTDOWN);
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
dom_event = virDomainEventLifecycleNewFromObj(vm,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainLifecycleAction) vm->def->onPoweroff) {
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleDestroy(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleRestart(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
|
2017-10-10 12:51:38 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
|
2015-03-01 23:22:07 +00:00
|
|
|
goto endjob;
|
2014-02-26 22:50:57 +00:00
|
|
|
}
|
|
|
|
} else if (xl_reason == LIBXL_SHUTDOWN_REASON_CRASH) {
|
2015-07-07 18:29:24 +00:00
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
|
|
|
|
VIR_DOMAIN_SHUTOFF_CRASHED);
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
dom_event = virDomainEventLifecycleNewFromObj(vm,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED_CRASHED);
|
2017-10-10 12:51:38 +00:00
|
|
|
switch ((virDomainLifecycleAction) vm->def->onCrash) {
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleDestroy(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:51:38 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleRestart(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:51:38 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
|
2015-03-01 23:22:07 +00:00
|
|
|
goto endjob;
|
2017-10-10 12:51:38 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
|
2014-02-26 22:50:57 +00:00
|
|
|
libxlDomainAutoCoreDump(driver, vm);
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleDestroy(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:51:38 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
|
2014-02-26 22:50:57 +00:00
|
|
|
libxlDomainAutoCoreDump(driver, vm);
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleRestart(driver, vm);
|
|
|
|
goto endjob;
|
2014-02-26 22:50:57 +00:00
|
|
|
}
|
|
|
|
} else if (xl_reason == LIBXL_SHUTDOWN_REASON_REBOOT) {
|
2015-07-07 18:29:24 +00:00
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
|
|
|
|
VIR_DOMAIN_SHUTOFF_SHUTDOWN);
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
dom_event = virDomainEventLifecycleNewFromObj(vm,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
|
2014-06-01 00:22:30 +00:00
|
|
|
switch ((virDomainLifecycleAction) vm->def->onReboot) {
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleDestroy(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
|
2018-10-31 16:54:14 +00:00
|
|
|
libxlDomainShutdownHandleRestart(driver, vm);
|
|
|
|
goto endjob;
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
|
2017-10-10 12:51:38 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
|
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
|
2017-10-10 12:32:11 +00:00
|
|
|
case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
|
2015-03-01 23:22:07 +00:00
|
|
|
goto endjob;
|
2014-02-26 22:50:57 +00:00
|
|
|
}
|
2018-10-31 17:03:37 +00:00
|
|
|
#ifdef LIBXL_HAVE_SOFT_RESET
|
|
|
|
} else if (xl_reason == LIBXL_SHUTDOWN_REASON_SOFT_RESET) {
|
|
|
|
libxlDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
if (libxl_retrieve_domain_configuration(cfg->ctx, vm->def->id,
|
|
|
|
&d_config) != 0) {
|
|
|
|
VIR_ERROR(_("Failed to retrieve config for VM '%s'. "
|
|
|
|
"Unable to perform soft reset. Destroying VM"),
|
|
|
|
vm->def->name);
|
|
|
|
libxlDomainShutdownHandleDestroy(driver, vm);
|
|
|
|
goto endjob;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->deathW) {
|
|
|
|
libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
|
|
|
|
priv->deathW = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (libxl_domain_soft_reset(cfg->ctx, &d_config, vm->def->id,
|
|
|
|
NULL, NULL) != 0) {
|
|
|
|
VIR_ERROR(_("Failed to soft reset VM '%s'. Destroying VM"),
|
|
|
|
vm->def->name);
|
|
|
|
libxlDomainShutdownHandleDestroy(driver, vm);
|
|
|
|
goto endjob;
|
|
|
|
}
|
|
|
|
libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW);
|
|
|
|
libxl_domain_unpause(cfg->ctx, vm->def->id);
|
|
|
|
#endif
|
2014-02-26 22:50:57 +00:00
|
|
|
} else {
|
|
|
|
VIR_INFO("Unhandled shutdown_reason %d", xl_reason);
|
2015-02-13 20:09:09 +00:00
|
|
|
}
|
2014-02-26 22:50:57 +00:00
|
|
|
|
2015-03-01 23:22:07 +00:00
|
|
|
endjob:
|
2016-06-12 10:30:00 +00:00
|
|
|
libxlDomainObjEndJob(driver, vm);
|
2015-03-01 23:22:07 +00:00
|
|
|
|
2014-03-25 06:51:17 +00:00
|
|
|
cleanup:
|
2016-06-12 10:30:00 +00:00
|
|
|
virDomainObjEndAPI(&vm);
|
2018-06-12 17:33:01 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, dom_event);
|
2015-02-11 22:22:05 +00:00
|
|
|
libxl_event_free(cfg->ctx, ev);
|
2014-02-26 22:50:57 +00:00
|
|
|
VIR_FREE(shutdown_info);
|
2018-11-06 22:21:19 +00:00
|
|
|
libxl_domain_config_dispose(&d_config);
|
2014-02-26 22:50:57 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 02:46:00 +00:00
|
|
|
static void
|
|
|
|
libxlDomainDeathThread(void *opaque)
|
|
|
|
{
|
|
|
|
struct libxlShutdownThreadInfo *shutdown_info = opaque;
|
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
libxl_event *ev = shutdown_info->event;
|
|
|
|
libxlDriverPrivatePtr driver = shutdown_info->driver;
|
|
|
|
virObjectEventPtr dom_event = NULL;
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2018-12-08 02:46:00 +00:00
|
|
|
libxlDomainObjPrivatePtr priv;
|
|
|
|
|
|
|
|
vm = virDomainObjListFindByID(driver->domains, ev->domid);
|
|
|
|
if (!vm) {
|
|
|
|
/* vm->def->id already cleared, means the death was handled by the
|
|
|
|
* driver already */
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv = vm->privateData;
|
|
|
|
|
|
|
|
if (priv->ignoreDeathEvent) {
|
|
|
|
priv->ignoreDeathEvent = false;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED);
|
|
|
|
dom_event = virDomainEventLifecycleNewFromObj(vm,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED,
|
|
|
|
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
|
|
|
|
libxlDomainCleanup(driver, vm);
|
|
|
|
if (!vm->persistent)
|
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
|
|
|
libxlDomainObjEndJob(driver, vm);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainObjEndAPI(&vm);
|
|
|
|
virObjectEventStateQueue(driver->domainEventState, dom_event);
|
|
|
|
libxl_event_free(cfg->ctx, ev);
|
|
|
|
VIR_FREE(shutdown_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
/*
|
|
|
|
* Handle previously registered domain event notification from libxenlight.
|
|
|
|
*/
|
2015-02-12 18:37:46 +00:00
|
|
|
void
|
|
|
|
libxlDomainEventHandler(void *data, VIR_LIBXL_EVENT_CONST libxl_event *event)
|
2014-02-26 22:50:57 +00:00
|
|
|
{
|
2015-02-11 22:22:05 +00:00
|
|
|
libxlDriverPrivatePtr driver = data;
|
2019-08-13 19:33:24 +00:00
|
|
|
libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason;
|
2015-03-26 01:35:11 +00:00
|
|
|
struct libxlShutdownThreadInfo *shutdown_info = NULL;
|
2014-02-26 22:50:57 +00:00
|
|
|
virThread thread;
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = NULL;
|
2018-12-08 02:46:00 +00:00
|
|
|
int ret = -1;
|
2020-02-14 11:20:10 +00:00
|
|
|
g_autofree char *name = NULL;
|
2014-02-26 22:50:57 +00:00
|
|
|
|
2018-12-08 02:46:00 +00:00
|
|
|
if (event->type != LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN &&
|
|
|
|
event->type != LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
|
2014-02-26 22:50:57 +00:00
|
|
|
VIR_INFO("Unhandled event type %d", event->type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-08-13 19:33:24 +00:00
|
|
|
/*
|
|
|
|
* Similar to the xl implementation, ignore SUSPEND. Any actions needed
|
|
|
|
* after calling libxl_domain_suspend() are handled by its callers.
|
|
|
|
*/
|
|
|
|
if (xl_reason == LIBXL_SHUTDOWN_REASON_SUSPEND)
|
|
|
|
goto error;
|
|
|
|
|
2014-02-26 22:50:57 +00:00
|
|
|
/*
|
|
|
|
* Start a thread to handle shutdown. We don't want to be tying up
|
|
|
|
* libxl's event machinery by doing a potentially lengthy shutdown.
|
|
|
|
*/
|
2020-09-23 18:43:09 +00:00
|
|
|
shutdown_info = g_new0(struct libxlShutdownThreadInfo, 1);
|
2014-02-26 22:50:57 +00:00
|
|
|
|
2015-02-11 22:22:05 +00:00
|
|
|
shutdown_info->driver = driver;
|
2014-02-26 22:50:57 +00:00
|
|
|
shutdown_info->event = (libxl_event *)event;
|
2020-02-14 11:20:10 +00:00
|
|
|
name = g_strdup_printf("ev-%d", event->domid);
|
2018-12-08 02:46:00 +00:00
|
|
|
if (event->type == LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN)
|
2020-02-14 11:20:10 +00:00
|
|
|
ret = virThreadCreateFull(&thread, false, libxlDomainShutdownThread,
|
|
|
|
name, false, shutdown_info);
|
2018-12-08 02:46:00 +00:00
|
|
|
else if (event->type == LIBXL_EVENT_TYPE_DOMAIN_DEATH)
|
2020-02-14 11:20:10 +00:00
|
|
|
ret = virThreadCreateFull(&thread, false, libxlDomainDeathThread,
|
|
|
|
name, false, shutdown_info);
|
2018-12-08 02:46:00 +00:00
|
|
|
|
|
|
|
if (ret < 0) {
|
2014-02-26 22:50:57 +00:00
|
|
|
/*
|
|
|
|
* Not much we can do on error here except log it.
|
|
|
|
*/
|
|
|
|
VIR_ERROR(_("Failed to create thread to handle domain shutdown"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-09-21 21:02:34 +00:00
|
|
|
* libxlShutdownThreadInfo and libxl_event are freed in shutdown thread
|
2014-02-26 22:50:57 +00:00
|
|
|
*/
|
|
|
|
return;
|
|
|
|
|
2014-03-25 06:51:17 +00:00
|
|
|
error:
|
2015-02-11 22:22:05 +00:00
|
|
|
cfg = libxlDriverConfigGet(driver);
|
2014-02-26 22:50:57 +00:00
|
|
|
/* Cast away any const */
|
2015-02-11 22:22:05 +00:00
|
|
|
libxl_event_free(cfg->ctx, (libxl_event *)event);
|
2015-03-26 01:35:11 +00:00
|
|
|
VIR_FREE(shutdown_info);
|
2014-02-26 22:50:57 +00:00
|
|
|
}
|
|
|
|
|
2014-02-26 03:55:47 +00:00
|
|
|
char *
|
2014-03-18 08:19:33 +00:00
|
|
|
libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
|
|
|
|
{
|
2014-02-26 03:55:47 +00:00
|
|
|
char *ret;
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2014-02-26 03:55:47 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
ret = g_strdup_printf("%s/%s.save", cfg->saveDir, vm->def->name);
|
2014-02-26 03:55:47 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-02-26 04:28:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a saved image file and initialize domain definition from the header.
|
|
|
|
*
|
|
|
|
* Returns the opened fd on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver,
|
2019-11-27 12:29:21 +00:00
|
|
|
libxlDriverConfigPtr cfg G_GNUC_UNUSED,
|
2014-02-26 04:28:51 +00:00
|
|
|
const char *from,
|
|
|
|
virDomainDefPtr *ret_def,
|
|
|
|
libxlSavefileHeaderPtr ret_hdr)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
libxlSavefileHeader hdr;
|
|
|
|
char *xml = NULL;
|
|
|
|
|
|
|
|
if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
|
|
|
|
virReportSystemError(-fd,
|
|
|
|
_("Failed to open domain image file '%s'"), from);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("failed to read libxl header"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr.version > LIBXL_SAVE_VERSION) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("image version is not supported (%d > %d)"),
|
|
|
|
hdr.version, LIBXL_SAVE_VERSION);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr.xmlLen <= 0) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("invalid XML length: %d"), hdr.xmlLen);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-09-23 18:43:09 +00:00
|
|
|
xml = g_new0(char, hdr.xmlLen);
|
2014-02-26 04:28:51 +00:00
|
|
|
|
|
|
|
if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-11-27 12:29:21 +00:00
|
|
|
if (!(def = virDomainDefParseString(xml, driver->xmlopt, NULL,
|
2016-05-26 13:58:53 +00:00
|
|
|
VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
|
|
|
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
|
2014-02-26 04:28:51 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
VIR_FREE(xml);
|
|
|
|
|
|
|
|
*ret_def = def;
|
|
|
|
*ret_hdr = hdr;
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
2014-03-25 06:51:17 +00:00
|
|
|
error:
|
2014-02-26 04:28:51 +00:00
|
|
|
VIR_FREE(xml);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-02-26 19:04:34 +00:00
|
|
|
|
2015-03-04 00:54:50 +00:00
|
|
|
/*
|
|
|
|
* Internal domain destroy function.
|
|
|
|
*
|
|
|
|
* virDomainObjPtr must be locked on invocation
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
libxlDomainDestroyInternal(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2018-12-08 02:46:00 +00:00
|
|
|
libxlDomainObjPrivatePtr priv = vm->privateData;
|
2015-03-04 00:54:50 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2018-12-08 02:46:00 +00:00
|
|
|
/* Ignore next LIBXL_EVENT_TYPE_DOMAIN_DEATH as the caller will handle
|
|
|
|
* domain death appropriately already (having more info, like the reason).
|
|
|
|
*/
|
|
|
|
priv->ignoreDeathEvent = true;
|
2015-03-04 00:54:50 +00:00
|
|
|
/* Unlock virDomainObj during destroy, which can take considerable
|
|
|
|
* time on large memory domains.
|
|
|
|
*/
|
|
|
|
virObjectUnlock(vm);
|
|
|
|
ret = libxl_domain_destroy(cfg->ctx, vm->def->id, NULL);
|
|
|
|
virObjectLock(vm);
|
2018-12-08 02:46:00 +00:00
|
|
|
if (ret)
|
|
|
|
priv->ignoreDeathEvent = false;
|
2015-03-04 00:54:50 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-26 19:04:34 +00:00
|
|
|
/*
|
|
|
|
* Cleanup function for domain that has reached shutoff state.
|
|
|
|
*
|
|
|
|
* virDomainObjPtr must be locked on invocation
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
libxlDomainCleanup(libxlDriverPrivatePtr driver,
|
2015-07-07 18:29:24 +00:00
|
|
|
virDomainObjPtr vm)
|
2014-02-26 19:04:34 +00:00
|
|
|
{
|
|
|
|
libxlDomainObjPrivatePtr priv = vm->privateData;
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2014-02-26 19:04:34 +00:00
|
|
|
int vnc_port;
|
|
|
|
char *file;
|
|
|
|
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
|
2016-05-19 08:14:33 +00:00
|
|
|
unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;
|
2018-07-26 14:32:04 +00:00
|
|
|
virConnectPtr conn = NULL;
|
2016-05-19 08:14:33 +00:00
|
|
|
|
|
|
|
#ifdef LIBXL_HAVE_PVUSB
|
|
|
|
hostdev_flags |= VIR_HOSTDEV_SP_USB;
|
|
|
|
#endif
|
2014-02-26 19:04:34 +00:00
|
|
|
|
2016-07-11 11:55:53 +00:00
|
|
|
/* now that we know it's stopped call the hook if present */
|
|
|
|
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
2019-11-27 11:57:34 +00:00
|
|
|
char *xml = virDomainDefFormat(vm->def, driver->xmlopt, 0);
|
2016-07-11 11:55:53 +00:00
|
|
|
|
|
|
|
/* we can't stop the operation even if the script raised an error */
|
|
|
|
ignore_value(virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
|
|
|
VIR_HOOK_LIBXL_OP_STOPPED, VIR_HOOK_SUBOP_END,
|
|
|
|
NULL, xml, NULL));
|
|
|
|
VIR_FREE(xml);
|
|
|
|
}
|
|
|
|
|
2020-05-04 21:20:37 +00:00
|
|
|
virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
|
2016-05-19 08:14:33 +00:00
|
|
|
vm->def, hostdev_flags, NULL);
|
2014-02-26 19:04:34 +00:00
|
|
|
|
2015-04-14 20:38:46 +00:00
|
|
|
VIR_FREE(priv->lockState);
|
|
|
|
if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
|
|
|
|
VIR_WARN("Unable to release lease on %s", vm->def->name);
|
|
|
|
VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
|
|
|
|
|
2018-05-31 21:41:37 +00:00
|
|
|
libxlLoggerCloseFile(cfg->logger, vm->def->id);
|
2014-02-26 19:04:34 +00:00
|
|
|
vm->def->id = -1;
|
|
|
|
|
|
|
|
if (priv->deathW) {
|
2015-02-11 23:40:07 +00:00
|
|
|
libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
|
2014-02-26 19:04:34 +00:00
|
|
|
priv->deathW = NULL;
|
|
|
|
}
|
|
|
|
|
2018-12-08 02:46:00 +00:00
|
|
|
priv->ignoreDeathEvent = false;
|
|
|
|
|
2020-01-31 16:12:11 +00:00
|
|
|
if (!!g_atomic_int_dec_and_test(&driver->nactive) && driver->inhibitCallback)
|
2014-02-26 19:04:34 +00:00
|
|
|
driver->inhibitCallback(false, driver->inhibitOpaque);
|
|
|
|
|
|
|
|
if ((vm->def->ngraphics == 1) &&
|
|
|
|
vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
|
|
|
|
vm->def->graphics[0]->data.vnc.autoport) {
|
|
|
|
vnc_port = vm->def->graphics[0]->data.vnc.port;
|
|
|
|
if (vnc_port >= LIBXL_VNC_PORT_MIN) {
|
2018-02-06 09:09:08 +00:00
|
|
|
if (virPortAllocatorRelease(vnc_port) < 0)
|
2014-02-26 19:04:34 +00:00
|
|
|
VIR_DEBUG("Could not mark port %d as unused", vnc_port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-24 13:25:46 +00:00
|
|
|
if ((vm->def->nnets)) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < vm->def->nnets; i++) {
|
|
|
|
virDomainNetDefPtr net = vm->def->nets[i];
|
|
|
|
|
|
|
|
if (net->ifname &&
|
|
|
|
STRPREFIX(net->ifname, LIBXL_GENERATED_PREFIX_XEN))
|
|
|
|
VIR_FREE(net->ifname);
|
2016-04-07 10:09:19 +00:00
|
|
|
|
|
|
|
/* cleanup actual device */
|
|
|
|
virDomainNetRemoveHostdev(vm->def, net);
|
2018-07-26 14:32:04 +00:00
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
|
|
|
if (conn || (conn = virGetConnectNetwork()))
|
|
|
|
virDomainNetReleaseActualDevice(conn, vm->def, net);
|
|
|
|
else
|
|
|
|
VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
|
|
|
|
}
|
2016-02-24 13:25:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
file = g_strdup_printf("%s/%s.xml", cfg->stateDir, vm->def->name);
|
|
|
|
|
|
|
|
if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
|
|
|
|
VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name);
|
|
|
|
VIR_FREE(file);
|
2014-02-26 19:04:34 +00:00
|
|
|
|
2016-07-11 11:55:53 +00:00
|
|
|
/* The "release" hook cleans up additional resources */
|
|
|
|
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
2019-11-27 11:57:34 +00:00
|
|
|
char *xml = virDomainDefFormat(vm->def, driver->xmlopt, 0);
|
2016-07-11 11:55:53 +00:00
|
|
|
|
|
|
|
/* we can't stop the operation even if the script raised an error */
|
|
|
|
ignore_value(virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
|
|
|
VIR_HOOK_LIBXL_OP_RELEASE, VIR_HOOK_SUBOP_END,
|
2016-08-02 13:18:56 +00:00
|
|
|
NULL, xml, NULL));
|
2016-07-11 11:55:53 +00:00
|
|
|
VIR_FREE(xml);
|
|
|
|
}
|
|
|
|
|
2016-09-08 13:16:58 +00:00
|
|
|
virDomainObjRemoveTransientDef(vm);
|
2018-07-26 14:32:04 +00:00
|
|
|
virObjectUnref(conn);
|
2014-02-26 19:04:34 +00:00
|
|
|
}
|
|
|
|
|
2014-02-26 19:33:46 +00:00
|
|
|
/*
|
|
|
|
* Core dump domain to default dump path.
|
|
|
|
*
|
|
|
|
* virDomainObjPtr must be locked on invocation
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2020-01-09 14:07:15 +00:00
|
|
|
g_autoptr(GDateTime) now = g_date_time_new_now_local();
|
|
|
|
g_autofree char *nowstr = NULL;
|
2014-02-26 19:33:46 +00:00
|
|
|
char *dumpfile = NULL;
|
|
|
|
|
2020-01-09 14:07:15 +00:00
|
|
|
nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S");
|
2014-02-26 19:33:46 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
dumpfile = g_strdup_printf("%s/%s-%s", cfg->autoDumpDir, vm->def->name,
|
2020-01-09 14:07:15 +00:00
|
|
|
nowstr);
|
2014-02-26 19:33:46 +00:00
|
|
|
|
|
|
|
/* Unlock virDomainObj while dumping core */
|
|
|
|
virObjectUnlock(vm);
|
2015-02-11 23:40:07 +00:00
|
|
|
libxl_domain_core_dump(cfg->ctx, vm->def->id, dumpfile, NULL);
|
2014-02-26 19:33:46 +00:00
|
|
|
virObjectLock(vm);
|
|
|
|
|
|
|
|
VIR_FREE(dumpfile);
|
2019-10-22 13:26:14 +00:00
|
|
|
return 0;
|
2014-02-26 19:33:46 +00:00
|
|
|
}
|
2014-02-26 20:48:11 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
|
|
|
|
{
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2016-06-29 11:16:22 +00:00
|
|
|
virDomainVcpuDefPtr vcpu;
|
2014-02-26 20:48:11 +00:00
|
|
|
libxl_bitmap map;
|
|
|
|
virBitmapPtr cpumask = NULL;
|
2015-05-22 08:20:55 +00:00
|
|
|
size_t i;
|
2014-02-26 20:48:11 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2015-06-19 16:33:30 +00:00
|
|
|
libxl_bitmap_init(&map);
|
|
|
|
|
2015-12-18 16:31:50 +00:00
|
|
|
for (i = 0; i < virDomainDefGetVcpus(vm->def); ++i) {
|
2016-01-29 09:20:44 +00:00
|
|
|
vcpu = virDomainDefGetVcpu(vm->def, i);
|
2015-12-18 16:31:50 +00:00
|
|
|
|
2016-01-29 09:20:44 +00:00
|
|
|
if (!vcpu->online)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(cpumask = vcpu->cpumask))
|
2015-12-18 16:31:50 +00:00
|
|
|
cpumask = vm->def->cpumask;
|
|
|
|
|
|
|
|
if (!cpumask)
|
|
|
|
continue;
|
2014-02-26 20:48:11 +00:00
|
|
|
|
2015-05-22 07:53:12 +00:00
|
|
|
if (virBitmapToData(cpumask, &map.map, (int *)&map.size) < 0)
|
|
|
|
goto cleanup;
|
2014-02-26 20:48:11 +00:00
|
|
|
|
2018-03-27 17:50:14 +00:00
|
|
|
if (libxl_set_vcpuaffinity(cfg->ctx, vm->def->id, i, &map, NULL) != 0) {
|
2014-02-26 20:48:11 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2016-01-29 09:20:44 +00:00
|
|
|
_("Failed to pin vcpu '%zu' with libxenlight"), i);
|
2014-02-26 20:48:11 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-06-19 16:33:30 +00:00
|
|
|
libxl_bitmap_dispose(&map); /* Also returns to freshly-init'd state */
|
2014-02-26 20:48:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:51:17 +00:00
|
|
|
cleanup:
|
2015-06-19 16:33:30 +00:00
|
|
|
libxl_bitmap_dispose(&map);
|
2014-02-26 20:48:11 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-02-26 20:51:36 +00:00
|
|
|
|
2015-02-11 21:47:42 +00:00
|
|
|
static int
|
|
|
|
libxlDomainFreeMem(libxl_ctx *ctx, libxl_domain_config *d_config)
|
2014-02-26 20:51:36 +00:00
|
|
|
{
|
|
|
|
uint32_t needed_mem;
|
|
|
|
uint32_t free_mem;
|
2017-01-17 22:11:32 +00:00
|
|
|
int32_t target_mem;
|
2014-02-26 20:51:36 +00:00
|
|
|
int tries = 3;
|
|
|
|
int wait_secs = 10;
|
|
|
|
|
libxl: fix dom0 balloon logic
Recent testing on large memory systems revealed a bug in the Xen xl
tool's freemem() function. When autoballooning is enabled, freemem()
is used to ensure enough memory is available to start a domain,
ballooning dom0 if necessary. When ballooning large amounts of memory
from dom0, freemem() would exceed its self-imposed wait time and
return an error. Meanwhile, dom0 continued to balloon. Starting the
domain later, after sufficient memory was ballooned from dom0, would
succeed. The libvirt implementation in libxlDomainFreeMem() suffers
the same bug since it is modeled after freemem().
In the end, the best place to fix the bug on the Xen side was to
slightly change the behavior of libxl_wait_for_memory_target().
Instead of failing after caller-provided wait_sec, the function now
blocks as long as dom0 memory ballooning is progressing. It will return
failure only when more memory is needed to reach the target and wait_sec
have expired with no progress being made. See xen.git commit fd3aa246.
There was a dicussion on how this would affect other libxl apps like
libvirt
http://lists.xen.org/archives/html/xen-devel/2015-03/msg00739.html
If libvirt containing this patch was build against a Xen containing
the old libxl_wait_for_memory_target() behavior, libxlDomainFreeMem()
will fail after 30 sec and domain creation will be terminated.
Without this patch and with old libxl_wait_for_memory_target() behavior,
libxlDomainFreeMem() does not succeed after 30 sec, but returns success
anyway. Domain creation continues resulting in all sorts of fun stuff
like cpu soft lockups in the guest OS. It was decided to properly fix
libxl_wait_for_memory_target(), and if anything improve the default
behavior of apps using the freemem reference impl in xl.
xl was patched to accommodate the change in libxl_wait_for_memory_target()
with xen.git commit 883b30a0. This patch does the same in the libxl
driver. While at it, I changed the logic to essentially match
freemem() in $xensrc/tools/libxl/xl_cmdimpl.c. It was a bit cleaner
IMO and will make it easier to spot future, potentially interesting
divergences.
2015-03-20 23:08:34 +00:00
|
|
|
if (libxl_domain_need_memory(ctx, &d_config->b_info, &needed_mem) < 0)
|
|
|
|
goto error;
|
2014-02-26 20:51:36 +00:00
|
|
|
|
libxl: fix dom0 balloon logic
Recent testing on large memory systems revealed a bug in the Xen xl
tool's freemem() function. When autoballooning is enabled, freemem()
is used to ensure enough memory is available to start a domain,
ballooning dom0 if necessary. When ballooning large amounts of memory
from dom0, freemem() would exceed its self-imposed wait time and
return an error. Meanwhile, dom0 continued to balloon. Starting the
domain later, after sufficient memory was ballooned from dom0, would
succeed. The libvirt implementation in libxlDomainFreeMem() suffers
the same bug since it is modeled after freemem().
In the end, the best place to fix the bug on the Xen side was to
slightly change the behavior of libxl_wait_for_memory_target().
Instead of failing after caller-provided wait_sec, the function now
blocks as long as dom0 memory ballooning is progressing. It will return
failure only when more memory is needed to reach the target and wait_sec
have expired with no progress being made. See xen.git commit fd3aa246.
There was a dicussion on how this would affect other libxl apps like
libvirt
http://lists.xen.org/archives/html/xen-devel/2015-03/msg00739.html
If libvirt containing this patch was build against a Xen containing
the old libxl_wait_for_memory_target() behavior, libxlDomainFreeMem()
will fail after 30 sec and domain creation will be terminated.
Without this patch and with old libxl_wait_for_memory_target() behavior,
libxlDomainFreeMem() does not succeed after 30 sec, but returns success
anyway. Domain creation continues resulting in all sorts of fun stuff
like cpu soft lockups in the guest OS. It was decided to properly fix
libxl_wait_for_memory_target(), and if anything improve the default
behavior of apps using the freemem reference impl in xl.
xl was patched to accommodate the change in libxl_wait_for_memory_target()
with xen.git commit 883b30a0. This patch does the same in the libxl
driver. While at it, I changed the logic to essentially match
freemem() in $xensrc/tools/libxl/xl_cmdimpl.c. It was a bit cleaner
IMO and will make it easier to spot future, potentially interesting
divergences.
2015-03-20 23:08:34 +00:00
|
|
|
do {
|
|
|
|
if (libxl_get_free_memory(ctx, &free_mem) < 0)
|
|
|
|
goto error;
|
2014-02-26 20:51:36 +00:00
|
|
|
|
libxl: fix dom0 balloon logic
Recent testing on large memory systems revealed a bug in the Xen xl
tool's freemem() function. When autoballooning is enabled, freemem()
is used to ensure enough memory is available to start a domain,
ballooning dom0 if necessary. When ballooning large amounts of memory
from dom0, freemem() would exceed its self-imposed wait time and
return an error. Meanwhile, dom0 continued to balloon. Starting the
domain later, after sufficient memory was ballooned from dom0, would
succeed. The libvirt implementation in libxlDomainFreeMem() suffers
the same bug since it is modeled after freemem().
In the end, the best place to fix the bug on the Xen side was to
slightly change the behavior of libxl_wait_for_memory_target().
Instead of failing after caller-provided wait_sec, the function now
blocks as long as dom0 memory ballooning is progressing. It will return
failure only when more memory is needed to reach the target and wait_sec
have expired with no progress being made. See xen.git commit fd3aa246.
There was a dicussion on how this would affect other libxl apps like
libvirt
http://lists.xen.org/archives/html/xen-devel/2015-03/msg00739.html
If libvirt containing this patch was build against a Xen containing
the old libxl_wait_for_memory_target() behavior, libxlDomainFreeMem()
will fail after 30 sec and domain creation will be terminated.
Without this patch and with old libxl_wait_for_memory_target() behavior,
libxlDomainFreeMem() does not succeed after 30 sec, but returns success
anyway. Domain creation continues resulting in all sorts of fun stuff
like cpu soft lockups in the guest OS. It was decided to properly fix
libxl_wait_for_memory_target(), and if anything improve the default
behavior of apps using the freemem reference impl in xl.
xl was patched to accommodate the change in libxl_wait_for_memory_target()
with xen.git commit 883b30a0. This patch does the same in the libxl
driver. While at it, I changed the logic to essentially match
freemem() in $xensrc/tools/libxl/xl_cmdimpl.c. It was a bit cleaner
IMO and will make it easier to spot future, potentially interesting
divergences.
2015-03-20 23:08:34 +00:00
|
|
|
if (free_mem >= needed_mem)
|
|
|
|
return 0;
|
2014-02-26 20:51:36 +00:00
|
|
|
|
2017-01-17 22:11:32 +00:00
|
|
|
target_mem = free_mem - needed_mem;
|
|
|
|
if (libxl_set_memory_target(ctx, 0, target_mem,
|
libxl: fix dom0 balloon logic
Recent testing on large memory systems revealed a bug in the Xen xl
tool's freemem() function. When autoballooning is enabled, freemem()
is used to ensure enough memory is available to start a domain,
ballooning dom0 if necessary. When ballooning large amounts of memory
from dom0, freemem() would exceed its self-imposed wait time and
return an error. Meanwhile, dom0 continued to balloon. Starting the
domain later, after sufficient memory was ballooned from dom0, would
succeed. The libvirt implementation in libxlDomainFreeMem() suffers
the same bug since it is modeled after freemem().
In the end, the best place to fix the bug on the Xen side was to
slightly change the behavior of libxl_wait_for_memory_target().
Instead of failing after caller-provided wait_sec, the function now
blocks as long as dom0 memory ballooning is progressing. It will return
failure only when more memory is needed to reach the target and wait_sec
have expired with no progress being made. See xen.git commit fd3aa246.
There was a dicussion on how this would affect other libxl apps like
libvirt
http://lists.xen.org/archives/html/xen-devel/2015-03/msg00739.html
If libvirt containing this patch was build against a Xen containing
the old libxl_wait_for_memory_target() behavior, libxlDomainFreeMem()
will fail after 30 sec and domain creation will be terminated.
Without this patch and with old libxl_wait_for_memory_target() behavior,
libxlDomainFreeMem() does not succeed after 30 sec, but returns success
anyway. Domain creation continues resulting in all sorts of fun stuff
like cpu soft lockups in the guest OS. It was decided to properly fix
libxl_wait_for_memory_target(), and if anything improve the default
behavior of apps using the freemem reference impl in xl.
xl was patched to accommodate the change in libxl_wait_for_memory_target()
with xen.git commit 883b30a0. This patch does the same in the libxl
driver. While at it, I changed the logic to essentially match
freemem() in $xensrc/tools/libxl/xl_cmdimpl.c. It was a bit cleaner
IMO and will make it easier to spot future, potentially interesting
divergences.
2015-03-20 23:08:34 +00:00
|
|
|
/* relative */ 1, 0) < 0)
|
|
|
|
goto error;
|
2014-02-26 20:51:36 +00:00
|
|
|
|
libxl: fix dom0 balloon logic
Recent testing on large memory systems revealed a bug in the Xen xl
tool's freemem() function. When autoballooning is enabled, freemem()
is used to ensure enough memory is available to start a domain,
ballooning dom0 if necessary. When ballooning large amounts of memory
from dom0, freemem() would exceed its self-imposed wait time and
return an error. Meanwhile, dom0 continued to balloon. Starting the
domain later, after sufficient memory was ballooned from dom0, would
succeed. The libvirt implementation in libxlDomainFreeMem() suffers
the same bug since it is modeled after freemem().
In the end, the best place to fix the bug on the Xen side was to
slightly change the behavior of libxl_wait_for_memory_target().
Instead of failing after caller-provided wait_sec, the function now
blocks as long as dom0 memory ballooning is progressing. It will return
failure only when more memory is needed to reach the target and wait_sec
have expired with no progress being made. See xen.git commit fd3aa246.
There was a dicussion on how this would affect other libxl apps like
libvirt
http://lists.xen.org/archives/html/xen-devel/2015-03/msg00739.html
If libvirt containing this patch was build against a Xen containing
the old libxl_wait_for_memory_target() behavior, libxlDomainFreeMem()
will fail after 30 sec and domain creation will be terminated.
Without this patch and with old libxl_wait_for_memory_target() behavior,
libxlDomainFreeMem() does not succeed after 30 sec, but returns success
anyway. Domain creation continues resulting in all sorts of fun stuff
like cpu soft lockups in the guest OS. It was decided to properly fix
libxl_wait_for_memory_target(), and if anything improve the default
behavior of apps using the freemem reference impl in xl.
xl was patched to accommodate the change in libxl_wait_for_memory_target()
with xen.git commit 883b30a0. This patch does the same in the libxl
driver. While at it, I changed the logic to essentially match
freemem() in $xensrc/tools/libxl/xl_cmdimpl.c. It was a bit cleaner
IMO and will make it easier to spot future, potentially interesting
divergences.
2015-03-20 23:08:34 +00:00
|
|
|
if (libxl_wait_for_memory_target(ctx, 0, wait_secs) < 0)
|
|
|
|
goto error;
|
2014-02-26 20:51:36 +00:00
|
|
|
|
libxl: fix dom0 balloon logic
Recent testing on large memory systems revealed a bug in the Xen xl
tool's freemem() function. When autoballooning is enabled, freemem()
is used to ensure enough memory is available to start a domain,
ballooning dom0 if necessary. When ballooning large amounts of memory
from dom0, freemem() would exceed its self-imposed wait time and
return an error. Meanwhile, dom0 continued to balloon. Starting the
domain later, after sufficient memory was ballooned from dom0, would
succeed. The libvirt implementation in libxlDomainFreeMem() suffers
the same bug since it is modeled after freemem().
In the end, the best place to fix the bug on the Xen side was to
slightly change the behavior of libxl_wait_for_memory_target().
Instead of failing after caller-provided wait_sec, the function now
blocks as long as dom0 memory ballooning is progressing. It will return
failure only when more memory is needed to reach the target and wait_sec
have expired with no progress being made. See xen.git commit fd3aa246.
There was a dicussion on how this would affect other libxl apps like
libvirt
http://lists.xen.org/archives/html/xen-devel/2015-03/msg00739.html
If libvirt containing this patch was build against a Xen containing
the old libxl_wait_for_memory_target() behavior, libxlDomainFreeMem()
will fail after 30 sec and domain creation will be terminated.
Without this patch and with old libxl_wait_for_memory_target() behavior,
libxlDomainFreeMem() does not succeed after 30 sec, but returns success
anyway. Domain creation continues resulting in all sorts of fun stuff
like cpu soft lockups in the guest OS. It was decided to properly fix
libxl_wait_for_memory_target(), and if anything improve the default
behavior of apps using the freemem reference impl in xl.
xl was patched to accommodate the change in libxl_wait_for_memory_target()
with xen.git commit 883b30a0. This patch does the same in the libxl
driver. While at it, I changed the logic to essentially match
freemem() in $xensrc/tools/libxl/xl_cmdimpl.c. It was a bit cleaner
IMO and will make it easier to spot future, potentially interesting
divergences.
2015-03-20 23:08:34 +00:00
|
|
|
tries--;
|
|
|
|
} while (tries > 0);
|
|
|
|
|
|
|
|
error:
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("Failed to balloon domain0 memory"));
|
|
|
|
return -1;
|
2014-02-26 20:51:36 +00:00
|
|
|
}
|
2014-02-26 21:11:30 +00:00
|
|
|
|
2016-04-07 10:09:19 +00:00
|
|
|
static int
|
|
|
|
libxlNetworkPrepareDevices(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
size_t i;
|
2018-07-26 14:32:04 +00:00
|
|
|
virConnectPtr conn = NULL;
|
|
|
|
int ret = -1;
|
2016-04-07 10:09:19 +00:00
|
|
|
|
|
|
|
for (i = 0; i < def->nnets; i++) {
|
|
|
|
virDomainNetDefPtr net = def->nets[i];
|
2016-09-23 15:04:53 +00:00
|
|
|
virDomainNetType actualType;
|
2016-04-07 10:09:19 +00:00
|
|
|
|
|
|
|
/* If appropriate, grab a physical device from the configured
|
|
|
|
* network's pool of devices, or resolve bridge device name
|
|
|
|
* to the one defined in the network definition.
|
|
|
|
*/
|
2018-07-26 14:32:04 +00:00
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
|
|
|
if (!conn && !(conn = virGetConnectNetwork()))
|
|
|
|
goto cleanup;
|
|
|
|
if (virDomainNetAllocateActualDevice(conn, def, net) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2016-04-07 10:09:19 +00:00
|
|
|
|
conf: add hypervisor agnostic, domain start-time, validation function for NetDef
<interface> devices (virDomainNetDef) are a bit different from other
types of devices in that their actual type may come from a network (in
the form of a port connection), and that doesn't happen until the
domain is started. This means that any validation of an <interface> at
parse time needs to be a bit liberal in what it accepts - when
type='network', you could think that something is/isn't allowed, but
once the domain is started and a port is created by the configured
network, the opposite might be true.
To solve this problem hypervisor drivers need to do an extra
validation step when the domain is being started. I recently (commit
3cff23f7, libvirt 5.7.0) added a function to peform such validation
for all interfaces to the QEMU driver -
qemuDomainValidateActualNetDef() - but while that function is a good
single point to call for the multiple places that need to "start" an
interface (domain startup, device hotplug, device update), it can't be
called by the other hypervisor drivers, since 1) it's in the QEMU
driver, and 2) it contains some checks specific to QEMU. For
validation that applies to network devices on *all* hypervisors, we
need yet another interface validation function that can be called by
any hypervisor driver (not just QEMU) right after its network port has
been created during domain startup or hotplug. This patch adds that
function - virDomainActualNetDefValidate(), in the conf directory,
and calls it in appropriate places in the QEMU, lxc, and libxl
drivers.
This new function is the place to put all network device validation
that 1) is hypervisor agnostic, and 2) can't be done until we know the
"actual type" of an interface.
There is no framework for validation at domain startup as there is for
post-parse validation, but I don't want to create a whole elaborate
system that will only be used by one type of device. For that reason,
I just made a single function that should be called directly from the
hypervisors, when they are initializing interfaces to start a domain,
right after conditionally allocating the network port (and regardless
of whether or not that was actually needed). In the case of the QEMU
driver, qemuDomainValidateActualNetDef() is already called in all the
appropriate places, so we can just call the new function from
there. In the case of the other hypervisors, we search for
virDomainNetAllocateActualDevice() (which is the hypervisor-agnostic
function that calls virNetworkPortCreateXML()), and add the call to our
new function right after that.
The new function itself could be plunked down into many places in the
code, but we already have 3 validation functions for network devices
in 2 different places (not counting any basic validation done in
virDomainNetDefParseXML() itself):
1) post-parse hypervisor-agnostic
(virDomainNetDefValidate() - domain_conf.c:6145)
2) post-parse hypervisor-specific
(qemuDomainDeviceDefValidateNetwork() - qemu_domain.c:5498)
3) domain-start hypervisor-specific
(qemuDomainValidateActualNetDef() - qemu_domain.c:5390)
I placed (3) right next to (2) when I added it, specifically to avoid
spreading validation all over the code. For the same reason, I decided
to put this new function right next to (1) - this way if someone needs
to add validation specific to qemu, they go to one location, and if
they need to add validation applying to everyone, they go to the
other. It looks a bit strange to have a public function in between a
bunch of statics, but I think it's better than the alternative of
further fragmentation. (I'm open to other ideas though, of course.)
Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Cole Robinson <crobinso@redhat.com>
2019-10-18 19:48:13 +00:00
|
|
|
/* final validation now that actual type is known */
|
|
|
|
if (virDomainActualNetDefValidate(net) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-04-07 10:09:19 +00:00
|
|
|
actualType = virDomainNetGetActualType(net);
|
|
|
|
if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
|
|
|
|
net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
|
|
|
/* Each type='hostdev' network device must also have a
|
|
|
|
* corresponding entry in the hostdevs array. For netdevs
|
|
|
|
* that are hardcoded as type='hostdev', this is already
|
|
|
|
* done by the parser, but for those allocated from a
|
|
|
|
* network / determined at runtime, we need to do it
|
|
|
|
* separately.
|
|
|
|
*/
|
|
|
|
virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
|
|
|
|
virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
|
|
|
|
|
|
|
|
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
|
|
|
pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
|
|
|
|
|
|
|
|
if (virDomainHostdevInsert(def, hostdev) < 0)
|
2018-07-26 14:32:04 +00:00
|
|
|
goto cleanup;
|
2016-04-07 10:09:19 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-26 14:32:04 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virObjectUnref(conn);
|
|
|
|
return ret;
|
2016-04-07 10:09:19 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 16:40:19 +00:00
|
|
|
static void
|
2015-02-11 21:54:43 +00:00
|
|
|
libxlConsoleCallback(libxl_ctx *ctx, libxl_event *ev, void *for_callback)
|
2015-01-15 16:40:19 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr vm = for_callback;
|
|
|
|
size_t i;
|
2016-08-18 02:20:48 +00:00
|
|
|
virDomainChrDefPtr chr;
|
|
|
|
char *console = NULL;
|
|
|
|
int ret;
|
2015-01-15 16:40:19 +00:00
|
|
|
|
|
|
|
virObjectLock(vm);
|
|
|
|
for (i = 0; i < vm->def->nconsoles; i++) {
|
2016-08-18 02:20:48 +00:00
|
|
|
chr = vm->def->consoles[i];
|
|
|
|
|
2016-06-22 02:25:23 +00:00
|
|
|
if (i == 0 &&
|
|
|
|
chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
|
|
|
|
chr = vm->def->serials[0];
|
|
|
|
|
2016-10-21 11:45:54 +00:00
|
|
|
if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
|
2015-01-15 16:40:19 +00:00
|
|
|
libxl_console_type console_type;
|
|
|
|
|
|
|
|
console_type =
|
2016-06-22 02:25:23 +00:00
|
|
|
(chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL ?
|
2015-01-15 16:40:19 +00:00
|
|
|
LIBXL_CONSOLE_TYPE_SERIAL : LIBXL_CONSOLE_TYPE_PV);
|
2015-02-11 21:54:43 +00:00
|
|
|
ret = libxl_console_get_tty(ctx, ev->domid,
|
2015-01-15 16:40:19 +00:00
|
|
|
chr->target.port, console_type,
|
|
|
|
&console);
|
|
|
|
if (!ret) {
|
2016-10-21 11:45:54 +00:00
|
|
|
VIR_FREE(chr->source->data.file.path);
|
2019-10-18 11:27:03 +00:00
|
|
|
if (console && console[0] != '\0')
|
|
|
|
chr->source->data.file.path = g_strdup(console);
|
2015-01-15 16:40:19 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(console);
|
|
|
|
}
|
|
|
|
}
|
2016-08-18 02:20:48 +00:00
|
|
|
for (i = 0; i < vm->def->nserials; i++) {
|
|
|
|
chr = vm->def->serials[i];
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
chr->info.alias = g_strdup_printf("serial%zd", i);
|
2016-10-21 11:45:54 +00:00
|
|
|
if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
|
|
|
|
if (chr->source->data.file.path)
|
2016-08-18 02:20:48 +00:00
|
|
|
continue;
|
|
|
|
ret = libxl_console_get_tty(ctx, ev->domid,
|
|
|
|
chr->target.port,
|
|
|
|
LIBXL_CONSOLE_TYPE_SERIAL,
|
|
|
|
&console);
|
|
|
|
if (!ret) {
|
2016-10-21 11:45:54 +00:00
|
|
|
VIR_FREE(chr->source->data.file.path);
|
2019-10-18 11:27:03 +00:00
|
|
|
if (console && console[0] != '\0')
|
|
|
|
chr->source->data.file.path = g_strdup(console);
|
2016-08-18 02:20:48 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(console);
|
|
|
|
}
|
|
|
|
}
|
2015-01-15 16:40:19 +00:00
|
|
|
virObjectUnlock(vm);
|
|
|
|
libxl_event_free(ctx, ev);
|
|
|
|
}
|
|
|
|
|
2016-02-24 13:25:46 +00:00
|
|
|
/*
|
|
|
|
* Create interface names for the network devices in parameter def.
|
|
|
|
* Names are created with the pattern 'vif<domid>.<devid><suffix>'.
|
|
|
|
* devid is extracted from the network devices in the d_config
|
|
|
|
* parameter. User-provided interface names are skipped.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
libxlDomainCreateIfaceNames(virDomainDefPtr def, libxl_domain_config *d_config)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->nnets && i < d_config->num_nics; i++) {
|
|
|
|
virDomainNetDefPtr net = def->nets[i];
|
|
|
|
libxl_device_nic *x_nic = &d_config->nics[i];
|
|
|
|
const char *suffix =
|
|
|
|
x_nic->nictype != LIBXL_NIC_TYPE_VIF ? "-emu" : "";
|
|
|
|
|
|
|
|
if (net->ifname)
|
|
|
|
continue;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
net->ifname = g_strdup_printf(LIBXL_GENERATED_PREFIX_XEN "%d.%d%s",
|
|
|
|
def->id, x_nic->devid, suffix);
|
2016-02-24 13:25:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 19:05:15 +00:00
|
|
|
static void
|
|
|
|
libxlDomainUpdateDiskParams(virDomainDefPtr def, libxl_ctx *ctx)
|
|
|
|
{
|
|
|
|
libxl_device_disk *disks;
|
|
|
|
int num_disks = 0;
|
|
|
|
size_t i;
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
disks = libxl_device_disk_list(ctx, def->id, &num_disks);
|
|
|
|
if (!disks)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < num_disks; i++) {
|
|
|
|
if ((idx = virDomainDiskIndexByName(def, disks[i].vdev, false)) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
libxlUpdateDiskDef(def->disks[idx], &disks[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < num_disks; i++)
|
|
|
|
libxl_device_disk_dispose(&disks[i]);
|
|
|
|
VIR_FREE(disks);
|
|
|
|
}
|
|
|
|
|
libxl: channels support
And allow libxl to handle channel element which creates a Xen
console visible to the guest as a low-bandwitdh communication
channel. If type is PTY we also fetch the tty after boot using
libxl_channel_getinfo to fetch the tty path. On socket case,
we autogenerate a path if not specified in the XML. Path autogenerated
is slightly different from qemu driver: qemu stores also on
"channels/target" but it creates then a directory per domain with
each channel target name. libxl doesn't appear to have a clear
definition of private files associated with each domain, so for
simplicity we do it slightly different. On qemu each autogenerated
channel goes like:
channels/target/<domain-name>/<target name>
Whereas for libxl:
channels/target/<domain-name>-<target name>
Should note that if path is not specified it won't persist,
existing only on live XML, unless user had initially specified it.
Since support for libxl channels only came on Xen >= 4.5 we therefore
need to conditionally compile it with LIBXL_HAVE_DEVICE_CHANNEL.
After this patch and having a qemu guest agent:
$ cat domain.xml | grep -a1 channel | head -n 5 | tail -n 4
<channel type='unix'>
<source mode='bind' path='/tmp/channel'/>
<target type='xen' name='org.qemu.guest_agent.0'/>
</channel>
$ virsh create domain.xml
$ echo '{"execute":"guest-network-get-interfaces"}' | socat
stdio,ignoreeof unix-connect:/tmp/channel
{"execute":"guest-network-get-interfaces"}
{"return": [{"name": "lo", "ip-addresses": [{"ip-address-type": "ipv4",
"ip-address": "127.0.0.1", "prefix": 8}, {"ip-address-type": "ipv6",
"ip-address": "::1", "prefix": 128}], "hardware-address":
"00:00:00:00:00:00"}, {"name": "eth0", "ip-addresses":
[{"ip-address-type": "ipv4", "ip-address": "10.100.0.6", "prefix": 24},
{"ip-address-type": "ipv6", "ip-address": "fe80::216:3eff:fe40:88eb",
"prefix": 64}], "hardware-address": "00:16:3e:40:88:eb"}, {"name":
"sit0"}]}
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-09-26 17:33:16 +00:00
|
|
|
#ifdef LIBXL_HAVE_DEVICE_CHANNEL
|
|
|
|
static void
|
|
|
|
libxlDomainCreateChannelPTY(virDomainDefPtr def, libxl_ctx *ctx)
|
|
|
|
{
|
|
|
|
libxl_device_channel *x_channels;
|
|
|
|
virDomainChrDefPtr chr;
|
|
|
|
size_t i;
|
|
|
|
int nchannels;
|
|
|
|
|
|
|
|
x_channels = libxl_device_channel_list(ctx, def->id, &nchannels);
|
|
|
|
if (!x_channels)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < def->nchannels; i++) {
|
|
|
|
libxl_channelinfo channelinfo;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
chr = def->channels[i];
|
2016-10-21 11:45:54 +00:00
|
|
|
if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY)
|
libxl: channels support
And allow libxl to handle channel element which creates a Xen
console visible to the guest as a low-bandwitdh communication
channel. If type is PTY we also fetch the tty after boot using
libxl_channel_getinfo to fetch the tty path. On socket case,
we autogenerate a path if not specified in the XML. Path autogenerated
is slightly different from qemu driver: qemu stores also on
"channels/target" but it creates then a directory per domain with
each channel target name. libxl doesn't appear to have a clear
definition of private files associated with each domain, so for
simplicity we do it slightly different. On qemu each autogenerated
channel goes like:
channels/target/<domain-name>/<target name>
Whereas for libxl:
channels/target/<domain-name>-<target name>
Should note that if path is not specified it won't persist,
existing only on live XML, unless user had initially specified it.
Since support for libxl channels only came on Xen >= 4.5 we therefore
need to conditionally compile it with LIBXL_HAVE_DEVICE_CHANNEL.
After this patch and having a qemu guest agent:
$ cat domain.xml | grep -a1 channel | head -n 5 | tail -n 4
<channel type='unix'>
<source mode='bind' path='/tmp/channel'/>
<target type='xen' name='org.qemu.guest_agent.0'/>
</channel>
$ virsh create domain.xml
$ echo '{"execute":"guest-network-get-interfaces"}' | socat
stdio,ignoreeof unix-connect:/tmp/channel
{"execute":"guest-network-get-interfaces"}
{"return": [{"name": "lo", "ip-addresses": [{"ip-address-type": "ipv4",
"ip-address": "127.0.0.1", "prefix": 8}, {"ip-address-type": "ipv6",
"ip-address": "::1", "prefix": 128}], "hardware-address":
"00:00:00:00:00:00"}, {"name": "eth0", "ip-addresses":
[{"ip-address-type": "ipv4", "ip-address": "10.100.0.6", "prefix": 24},
{"ip-address-type": "ipv6", "ip-address": "fe80::216:3eff:fe40:88eb",
"prefix": 64}], "hardware-address": "00:16:3e:40:88:eb"}, {"name":
"sit0"}]}
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-09-26 17:33:16 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = libxl_device_channel_getinfo(ctx, def->id, &x_channels[i],
|
|
|
|
&channelinfo);
|
|
|
|
|
|
|
|
if (!ret && channelinfo.u.pty.path &&
|
2017-02-22 17:18:51 +00:00
|
|
|
*channelinfo.u.pty.path != '\0') {
|
2016-10-21 11:45:54 +00:00
|
|
|
VIR_FREE(chr->source->data.file.path);
|
2019-10-18 11:27:03 +00:00
|
|
|
chr->source->data.file.path = g_strdup(channelinfo.u.pty.path);
|
libxl: channels support
And allow libxl to handle channel element which creates a Xen
console visible to the guest as a low-bandwitdh communication
channel. If type is PTY we also fetch the tty after boot using
libxl_channel_getinfo to fetch the tty path. On socket case,
we autogenerate a path if not specified in the XML. Path autogenerated
is slightly different from qemu driver: qemu stores also on
"channels/target" but it creates then a directory per domain with
each channel target name. libxl doesn't appear to have a clear
definition of private files associated with each domain, so for
simplicity we do it slightly different. On qemu each autogenerated
channel goes like:
channels/target/<domain-name>/<target name>
Whereas for libxl:
channels/target/<domain-name>-<target name>
Should note that if path is not specified it won't persist,
existing only on live XML, unless user had initially specified it.
Since support for libxl channels only came on Xen >= 4.5 we therefore
need to conditionally compile it with LIBXL_HAVE_DEVICE_CHANNEL.
After this patch and having a qemu guest agent:
$ cat domain.xml | grep -a1 channel | head -n 5 | tail -n 4
<channel type='unix'>
<source mode='bind' path='/tmp/channel'/>
<target type='xen' name='org.qemu.guest_agent.0'/>
</channel>
$ virsh create domain.xml
$ echo '{"execute":"guest-network-get-interfaces"}' | socat
stdio,ignoreeof unix-connect:/tmp/channel
{"execute":"guest-network-get-interfaces"}
{"return": [{"name": "lo", "ip-addresses": [{"ip-address-type": "ipv4",
"ip-address": "127.0.0.1", "prefix": 8}, {"ip-address-type": "ipv6",
"ip-address": "::1", "prefix": 128}], "hardware-address":
"00:00:00:00:00:00"}, {"name": "eth0", "ip-addresses":
[{"ip-address-type": "ipv4", "ip-address": "10.100.0.6", "prefix": 24},
{"ip-address-type": "ipv6", "ip-address": "fe80::216:3eff:fe40:88eb",
"prefix": 64}], "hardware-address": "00:16:3e:40:88:eb"}, {"name":
"sit0"}]}
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-09-26 17:33:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nchannels; i++)
|
|
|
|
libxl_device_channel_dispose(&x_channels[i]);
|
|
|
|
}
|
|
|
|
#endif
|
2015-01-15 16:40:19 +00:00
|
|
|
|
libxl: support Xen migration stream V2 in save/restore
Xen 4.6 introduced a new migration stream commonly referred to as
"migration V2". Xen 4.6 and newer always produce this new stream,
whereas Xen 4.5 and older always produce the legacy stream.
Support for migration stream V2 can be detected at build time with
LIBXL_HAVE_SRM_V2 from libxl.h. The legacy and V2 streams are not
compatible, but a V2 host can accept and convert a legacy stream.
Commit e7440656 changed the libxl driver to use the lowest libxl
API version possible (version 0x040200) to ensure the driver
builds against older Xen releases. The old 4.2 restore API does
not support specifying a stream version and assumes a legacy
stream, even if the incoming stream is migration V2. Thinking it
has been given a legacy stream, libxl will fail to convert an
incoming stream that is already V2, which causes the entire
restore operation to fail. Xen's libvirt-related OSSTest has been
failing since commit e7440656 landed in libvirt.git master. One
of the more recent failures can be seen here
http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg00071.html
This patch changes the call to libxl_domain_create_restore() to
include the stream version if LIBXL_HAVE_SRM_V2 is defined. The
version field of the libxlSavefileHeader struct is also updated
to '2' when LIBXL_HAVE_SRM_V2 is defined, ensuring the stream
version in the header matches the actual stream version produced
by Xen. Along with bumping the libxl API requirement to 0x040400,
this patch fixes save/restore on a migration V2 Xen host.
Oddly, migration has never used the libxlSavefileHeader. It
handles passing configuration in the Begin and Prepare phases,
and then calls libxl directly to transfer domain state/memory
in the Perform phase. A subsequent patch will add stream
version handling in the Begin and Prepare phase handshaking,
which will fix the migration related OSSTest failures.
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-05-02 18:00:39 +00:00
|
|
|
#ifdef LIBXL_HAVE_SRM_V2
|
|
|
|
# define LIBXL_DOMSTART_RESTORE_VER_ATTR /* empty */
|
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
# define LIBXL_DOMSTART_RESTORE_VER_ATTR G_GNUC_UNUSED
|
libxl: support Xen migration stream V2 in save/restore
Xen 4.6 introduced a new migration stream commonly referred to as
"migration V2". Xen 4.6 and newer always produce this new stream,
whereas Xen 4.5 and older always produce the legacy stream.
Support for migration stream V2 can be detected at build time with
LIBXL_HAVE_SRM_V2 from libxl.h. The legacy and V2 streams are not
compatible, but a V2 host can accept and convert a legacy stream.
Commit e7440656 changed the libxl driver to use the lowest libxl
API version possible (version 0x040200) to ensure the driver
builds against older Xen releases. The old 4.2 restore API does
not support specifying a stream version and assumes a legacy
stream, even if the incoming stream is migration V2. Thinking it
has been given a legacy stream, libxl will fail to convert an
incoming stream that is already V2, which causes the entire
restore operation to fail. Xen's libvirt-related OSSTest has been
failing since commit e7440656 landed in libvirt.git master. One
of the more recent failures can be seen here
http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg00071.html
This patch changes the call to libxl_domain_create_restore() to
include the stream version if LIBXL_HAVE_SRM_V2 is defined. The
version field of the libxlSavefileHeader struct is also updated
to '2' when LIBXL_HAVE_SRM_V2 is defined, ensuring the stream
version in the header matches the actual stream version produced
by Xen. Along with bumping the libxl API requirement to 0x040400,
this patch fixes save/restore on a migration V2 Xen host.
Oddly, migration has never used the libxlSavefileHeader. It
handles passing configuration in the Begin and Prepare phases,
and then calls libxl directly to transfer domain state/memory
in the Perform phase. A subsequent patch will add stream
version handling in the Begin and Prepare phase handshaking,
which will fix the migration related OSSTest failures.
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-05-02 18:00:39 +00:00
|
|
|
#endif
|
|
|
|
|
2014-02-26 21:11:30 +00:00
|
|
|
/*
|
|
|
|
* Start a domain through libxenlight.
|
|
|
|
*
|
2015-03-02 01:24:26 +00:00
|
|
|
* virDomainObjPtr must be locked and a job acquired on invocation
|
2014-02-26 21:11:30 +00:00
|
|
|
*/
|
libxl: support Xen migration stream V2 in save/restore
Xen 4.6 introduced a new migration stream commonly referred to as
"migration V2". Xen 4.6 and newer always produce this new stream,
whereas Xen 4.5 and older always produce the legacy stream.
Support for migration stream V2 can be detected at build time with
LIBXL_HAVE_SRM_V2 from libxl.h. The legacy and V2 streams are not
compatible, but a V2 host can accept and convert a legacy stream.
Commit e7440656 changed the libxl driver to use the lowest libxl
API version possible (version 0x040200) to ensure the driver
builds against older Xen releases. The old 4.2 restore API does
not support specifying a stream version and assumes a legacy
stream, even if the incoming stream is migration V2. Thinking it
has been given a legacy stream, libxl will fail to convert an
incoming stream that is already V2, which causes the entire
restore operation to fail. Xen's libvirt-related OSSTest has been
failing since commit e7440656 landed in libvirt.git master. One
of the more recent failures can be seen here
http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg00071.html
This patch changes the call to libxl_domain_create_restore() to
include the stream version if LIBXL_HAVE_SRM_V2 is defined. The
version field of the libxlSavefileHeader struct is also updated
to '2' when LIBXL_HAVE_SRM_V2 is defined, ensuring the stream
version in the header matches the actual stream version produced
by Xen. Along with bumping the libxl API requirement to 0x040400,
this patch fixes save/restore on a migration V2 Xen host.
Oddly, migration has never used the libxlSavefileHeader. It
handles passing configuration in the Begin and Prepare phases,
and then calls libxl directly to transfer domain state/memory
in the Perform phase. A subsequent patch will add stream
version handling in the Begin and Prepare phase handshaking,
which will fix the migration related OSSTest failures.
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-05-02 18:00:39 +00:00
|
|
|
static int
|
|
|
|
libxlDomainStart(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
bool start_paused,
|
|
|
|
int restore_fd,
|
|
|
|
uint32_t restore_ver LIBXL_DOMSTART_RESTORE_VER_ATTR)
|
2014-02-26 21:11:30 +00:00
|
|
|
{
|
|
|
|
libxl_domain_config d_config;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
virObjectEventPtr event = NULL;
|
|
|
|
libxlSavefileHeader hdr;
|
|
|
|
int ret = -1;
|
|
|
|
uint32_t domid = 0;
|
|
|
|
char *dom_xml = NULL;
|
|
|
|
char *managed_save_path = NULL;
|
|
|
|
int managed_save_fd = -1;
|
|
|
|
libxlDomainObjPrivatePtr priv = vm->privateData;
|
2019-10-19 11:16:54 +00:00
|
|
|
g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
|
2014-02-26 21:11:30 +00:00
|
|
|
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
|
2015-01-15 16:40:19 +00:00
|
|
|
libxl_asyncprogress_how aop_console_how;
|
2016-04-29 03:08:28 +00:00
|
|
|
libxl_domain_restore_params params;
|
2016-05-19 08:14:33 +00:00
|
|
|
unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;
|
2017-01-09 15:20:50 +00:00
|
|
|
char *config_json = NULL;
|
2016-05-19 08:14:33 +00:00
|
|
|
|
|
|
|
#ifdef LIBXL_HAVE_PVUSB
|
|
|
|
hostdev_flags |= VIR_HOSTDEV_SP_USB;
|
|
|
|
#endif
|
2014-02-26 21:11:30 +00:00
|
|
|
|
2014-06-02 10:53:03 +00:00
|
|
|
libxl_domain_config_init(&d_config);
|
|
|
|
|
2014-02-26 21:11:30 +00:00
|
|
|
/* If there is a managed saved state restore it instead of starting
|
|
|
|
* from scratch. The old state is removed once the restoring succeeded. */
|
|
|
|
if (restore_fd < 0) {
|
|
|
|
managed_save_path = libxlDomainManagedSavePath(driver, vm);
|
|
|
|
if (managed_save_path == NULL)
|
2015-03-02 01:24:26 +00:00
|
|
|
goto cleanup;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
|
|
|
if (virFileExists(managed_save_path)) {
|
|
|
|
|
|
|
|
managed_save_fd = libxlDomainSaveImageOpen(driver, cfg,
|
|
|
|
managed_save_path,
|
|
|
|
&def, &hdr);
|
|
|
|
if (managed_save_fd < 0)
|
2015-03-02 01:24:26 +00:00
|
|
|
goto cleanup;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
|
|
|
restore_fd = managed_save_fd;
|
libxl: support Xen migration stream V2 in save/restore
Xen 4.6 introduced a new migration stream commonly referred to as
"migration V2". Xen 4.6 and newer always produce this new stream,
whereas Xen 4.5 and older always produce the legacy stream.
Support for migration stream V2 can be detected at build time with
LIBXL_HAVE_SRM_V2 from libxl.h. The legacy and V2 streams are not
compatible, but a V2 host can accept and convert a legacy stream.
Commit e7440656 changed the libxl driver to use the lowest libxl
API version possible (version 0x040200) to ensure the driver
builds against older Xen releases. The old 4.2 restore API does
not support specifying a stream version and assumes a legacy
stream, even if the incoming stream is migration V2. Thinking it
has been given a legacy stream, libxl will fail to convert an
incoming stream that is already V2, which causes the entire
restore operation to fail. Xen's libvirt-related OSSTest has been
failing since commit e7440656 landed in libvirt.git master. One
of the more recent failures can be seen here
http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg00071.html
This patch changes the call to libxl_domain_create_restore() to
include the stream version if LIBXL_HAVE_SRM_V2 is defined. The
version field of the libxlSavefileHeader struct is also updated
to '2' when LIBXL_HAVE_SRM_V2 is defined, ensuring the stream
version in the header matches the actual stream version produced
by Xen. Along with bumping the libxl API requirement to 0x040400,
this patch fixes save/restore on a migration V2 Xen host.
Oddly, migration has never used the libxlSavefileHeader. It
handles passing configuration in the Begin and Prepare phases,
and then calls libxl directly to transfer domain state/memory
in the Perform phase. A subsequent patch will add stream
version handling in the Begin and Prepare phase handshaking,
which will fix the migration related OSSTest failures.
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-05-02 18:00:39 +00:00
|
|
|
restore_ver = hdr.version;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
|
|
|
if (STRNEQ(vm->def->name, def->name) ||
|
|
|
|
memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
|
|
|
|
char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char def_uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(vm->def->uuid, vm_uuidstr);
|
|
|
|
virUUIDFormat(def->uuid, def_uuidstr);
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("cannot restore domain '%s' uuid %s from a file"
|
|
|
|
" which belongs to domain '%s' uuid %s"),
|
|
|
|
vm->def->name, vm_uuidstr, def->name, def_uuidstr);
|
2015-03-02 01:24:26 +00:00
|
|
|
goto cleanup;
|
2014-02-26 21:11:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virDomainObjAssignDef(vm, def, true, NULL);
|
|
|
|
def = NULL;
|
|
|
|
|
|
|
|
if (unlink(managed_save_path) < 0)
|
|
|
|
VIR_WARN("Failed to remove the managed state %s",
|
|
|
|
managed_save_path);
|
|
|
|
|
|
|
|
vm->hasManagedSave = false;
|
|
|
|
}
|
|
|
|
VIR_FREE(managed_save_path);
|
|
|
|
}
|
|
|
|
|
2019-11-27 12:41:59 +00:00
|
|
|
if (virDomainObjSetDefTransient(driver->xmlopt, vm, NULL) < 0)
|
2015-12-03 12:38:56 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2016-07-11 11:55:53 +00:00
|
|
|
/* Run an early hook to set-up missing devices */
|
|
|
|
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
2019-11-27 11:57:34 +00:00
|
|
|
char *xml = virDomainDefFormat(vm->def, driver->xmlopt, 0);
|
2016-07-11 11:55:53 +00:00
|
|
|
int hookret;
|
|
|
|
|
|
|
|
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
|
|
|
VIR_HOOK_LIBXL_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN,
|
|
|
|
NULL, xml, NULL);
|
|
|
|
VIR_FREE(xml);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the script raised an error abort the launch
|
|
|
|
*/
|
|
|
|
if (hookret < 0)
|
|
|
|
goto cleanup_dom;
|
|
|
|
}
|
|
|
|
|
2015-04-14 20:38:46 +00:00
|
|
|
if (virDomainLockProcessStart(driver->lockManager,
|
|
|
|
"xen:///system",
|
|
|
|
vm,
|
|
|
|
true,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2016-04-07 10:09:19 +00:00
|
|
|
if (libxlNetworkPrepareDevices(vm->def) < 0)
|
|
|
|
goto cleanup_dom;
|
|
|
|
|
2016-03-28 19:55:42 +00:00
|
|
|
if (libxlBuildDomainConfig(driver->reservedGraphicsPorts, vm->def,
|
2018-04-12 01:03:20 +00:00
|
|
|
cfg, &d_config) < 0)
|
2016-03-28 19:55:42 +00:00
|
|
|
goto cleanup_dom;
|
|
|
|
|
|
|
|
if (cfg->autoballoon && libxlDomainFreeMem(cfg->ctx, &d_config) < 0)
|
|
|
|
goto cleanup_dom;
|
|
|
|
|
2020-05-04 21:20:37 +00:00
|
|
|
if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
|
2016-05-19 08:14:33 +00:00
|
|
|
vm->def, hostdev_flags) < 0)
|
2016-03-28 19:55:42 +00:00
|
|
|
goto cleanup_dom;
|
|
|
|
|
2016-07-11 11:55:53 +00:00
|
|
|
/* now that we know it is about to start call the hook if present */
|
|
|
|
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
2019-11-27 11:57:34 +00:00
|
|
|
char *xml = virDomainDefFormat(vm->def, driver->xmlopt, 0);
|
2016-07-11 11:55:53 +00:00
|
|
|
int hookret;
|
|
|
|
|
|
|
|
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
|
|
|
VIR_HOOK_LIBXL_OP_START, VIR_HOOK_SUBOP_BEGIN,
|
|
|
|
NULL, xml, NULL);
|
|
|
|
VIR_FREE(xml);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the script raised an error abort the launch
|
|
|
|
*/
|
|
|
|
if (hookret < 0)
|
|
|
|
goto cleanup_dom;
|
|
|
|
}
|
|
|
|
|
2016-07-11 13:54:31 +00:00
|
|
|
if (priv->hookRun) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
|
|
|
|
|
|
|
VIR_WARN("Domain id='%d' name='%s' uuid='%s' is tainted: hook",
|
|
|
|
vm->def->id,
|
|
|
|
vm->def->name,
|
|
|
|
uuidstr);
|
|
|
|
}
|
|
|
|
|
2014-02-26 21:11:30 +00:00
|
|
|
/* Unlock virDomainObj while creating the domain */
|
|
|
|
virObjectUnlock(vm);
|
2015-01-15 16:40:19 +00:00
|
|
|
|
|
|
|
aop_console_how.for_callback = vm;
|
|
|
|
aop_console_how.callback = libxlConsoleCallback;
|
2014-02-26 21:11:30 +00:00
|
|
|
if (restore_fd < 0) {
|
2015-02-11 23:40:07 +00:00
|
|
|
ret = libxl_domain_create_new(cfg->ctx, &d_config,
|
2015-01-15 16:40:19 +00:00
|
|
|
&domid, NULL, &aop_console_how);
|
2014-02-26 21:11:30 +00:00
|
|
|
} else {
|
2016-04-29 03:08:28 +00:00
|
|
|
libxl_domain_restore_params_init(¶ms);
|
libxl: support Xen migration stream V2 in save/restore
Xen 4.6 introduced a new migration stream commonly referred to as
"migration V2". Xen 4.6 and newer always produce this new stream,
whereas Xen 4.5 and older always produce the legacy stream.
Support for migration stream V2 can be detected at build time with
LIBXL_HAVE_SRM_V2 from libxl.h. The legacy and V2 streams are not
compatible, but a V2 host can accept and convert a legacy stream.
Commit e7440656 changed the libxl driver to use the lowest libxl
API version possible (version 0x040200) to ensure the driver
builds against older Xen releases. The old 4.2 restore API does
not support specifying a stream version and assumes a legacy
stream, even if the incoming stream is migration V2. Thinking it
has been given a legacy stream, libxl will fail to convert an
incoming stream that is already V2, which causes the entire
restore operation to fail. Xen's libvirt-related OSSTest has been
failing since commit e7440656 landed in libvirt.git master. One
of the more recent failures can be seen here
http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg00071.html
This patch changes the call to libxl_domain_create_restore() to
include the stream version if LIBXL_HAVE_SRM_V2 is defined. The
version field of the libxlSavefileHeader struct is also updated
to '2' when LIBXL_HAVE_SRM_V2 is defined, ensuring the stream
version in the header matches the actual stream version produced
by Xen. Along with bumping the libxl API requirement to 0x040400,
this patch fixes save/restore on a migration V2 Xen host.
Oddly, migration has never used the libxlSavefileHeader. It
handles passing configuration in the Begin and Prepare phases,
and then calls libxl directly to transfer domain state/memory
in the Perform phase. A subsequent patch will add stream
version handling in the Begin and Prepare phase handshaking,
which will fix the migration related OSSTest failures.
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-05-02 18:00:39 +00:00
|
|
|
#ifdef LIBXL_HAVE_SRM_V2
|
|
|
|
params.stream_version = restore_ver;
|
|
|
|
#endif
|
2015-02-11 23:40:07 +00:00
|
|
|
ret = libxl_domain_create_restore(cfg->ctx, &d_config, &domid,
|
2016-04-29 03:08:28 +00:00
|
|
|
restore_fd, ¶ms, NULL,
|
|
|
|
&aop_console_how);
|
|
|
|
libxl_domain_restore_params_dispose(¶ms);
|
2014-02-26 21:11:30 +00:00
|
|
|
}
|
|
|
|
virObjectLock(vm);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
if (restore_fd < 0)
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("libxenlight failed to create new domain '%s'"),
|
|
|
|
d_config.c_info.name);
|
|
|
|
else
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("libxenlight failed to restore domain '%s'"),
|
|
|
|
d_config.c_info.name);
|
2016-03-28 19:55:42 +00:00
|
|
|
goto cleanup_dom;
|
2014-02-26 21:11:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The domain has been successfully created with libxl, so it should
|
|
|
|
* be cleaned up if there are any subsequent failures.
|
|
|
|
*/
|
|
|
|
vm->def->id = domid;
|
2017-01-09 15:20:50 +00:00
|
|
|
config_json = libxl_domain_config_to_json(cfg->ctx, &d_config);
|
|
|
|
|
|
|
|
libxlLoggerOpenFile(cfg->logger, domid, vm->def->name, config_json);
|
2015-02-12 19:02:27 +00:00
|
|
|
|
2019-10-14 20:01:00 +00:00
|
|
|
if (virDomainLockProcessResume(driver->lockManager,
|
|
|
|
"xen:///system",
|
|
|
|
vm,
|
|
|
|
priv->lockState) < 0)
|
|
|
|
goto destroy_dom;
|
|
|
|
VIR_FREE(priv->lockState);
|
|
|
|
|
2015-02-12 19:02:27 +00:00
|
|
|
/* Always enable domain death events */
|
2015-02-11 23:40:07 +00:00
|
|
|
if (libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW))
|
2016-03-28 19:47:07 +00:00
|
|
|
goto destroy_dom;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
2016-02-24 13:25:46 +00:00
|
|
|
libxlDomainCreateIfaceNames(vm->def, &d_config);
|
2017-02-07 19:05:15 +00:00
|
|
|
libxlDomainUpdateDiskParams(vm->def, cfg->ctx);
|
2015-04-14 20:38:46 +00:00
|
|
|
|
libxl: channels support
And allow libxl to handle channel element which creates a Xen
console visible to the guest as a low-bandwitdh communication
channel. If type is PTY we also fetch the tty after boot using
libxl_channel_getinfo to fetch the tty path. On socket case,
we autogenerate a path if not specified in the XML. Path autogenerated
is slightly different from qemu driver: qemu stores also on
"channels/target" but it creates then a directory per domain with
each channel target name. libxl doesn't appear to have a clear
definition of private files associated with each domain, so for
simplicity we do it slightly different. On qemu each autogenerated
channel goes like:
channels/target/<domain-name>/<target name>
Whereas for libxl:
channels/target/<domain-name>-<target name>
Should note that if path is not specified it won't persist,
existing only on live XML, unless user had initially specified it.
Since support for libxl channels only came on Xen >= 4.5 we therefore
need to conditionally compile it with LIBXL_HAVE_DEVICE_CHANNEL.
After this patch and having a qemu guest agent:
$ cat domain.xml | grep -a1 channel | head -n 5 | tail -n 4
<channel type='unix'>
<source mode='bind' path='/tmp/channel'/>
<target type='xen' name='org.qemu.guest_agent.0'/>
</channel>
$ virsh create domain.xml
$ echo '{"execute":"guest-network-get-interfaces"}' | socat
stdio,ignoreeof unix-connect:/tmp/channel
{"execute":"guest-network-get-interfaces"}
{"return": [{"name": "lo", "ip-addresses": [{"ip-address-type": "ipv4",
"ip-address": "127.0.0.1", "prefix": 8}, {"ip-address-type": "ipv6",
"ip-address": "::1", "prefix": 128}], "hardware-address":
"00:00:00:00:00:00"}, {"name": "eth0", "ip-addresses":
[{"ip-address-type": "ipv4", "ip-address": "10.100.0.6", "prefix": 24},
{"ip-address-type": "ipv6", "ip-address": "fe80::216:3eff:fe40:88eb",
"prefix": 64}], "hardware-address": "00:16:3e:40:88:eb"}, {"name":
"sit0"}]}
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-09-26 17:33:16 +00:00
|
|
|
#ifdef LIBXL_HAVE_DEVICE_CHANNEL
|
|
|
|
if (vm->def->nchannels > 0)
|
|
|
|
libxlDomainCreateChannelPTY(vm->def, cfg->ctx);
|
|
|
|
#endif
|
|
|
|
|
2019-11-27 11:57:34 +00:00
|
|
|
if ((dom_xml = virDomainDefFormat(vm->def, driver->xmlopt, 0)) == NULL)
|
2016-03-28 19:47:07 +00:00
|
|
|
goto destroy_dom;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
2015-02-11 23:40:07 +00:00
|
|
|
if (libxl_userdata_store(cfg->ctx, domid, "libvirt-xml",
|
2014-02-26 21:11:30 +00:00
|
|
|
(uint8_t *)dom_xml, strlen(dom_xml) + 1)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("libxenlight failed to store userdata"));
|
2016-03-28 19:47:07 +00:00
|
|
|
goto destroy_dom;
|
2014-02-26 21:11:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (libxlDomainSetVcpuAffinities(driver, vm) < 0)
|
2016-03-28 19:47:07 +00:00
|
|
|
goto destroy_dom;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
|
|
|
if (!start_paused) {
|
2015-02-11 23:40:07 +00:00
|
|
|
libxl_domain_unpause(cfg->ctx, domid);
|
2014-02-26 21:11:30 +00:00
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
|
|
|
|
} else {
|
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
|
|
|
|
}
|
|
|
|
|
2019-11-27 12:53:10 +00:00
|
|
|
if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
|
2016-03-28 19:47:07 +00:00
|
|
|
goto destroy_dom;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
2020-01-31 16:04:24 +00:00
|
|
|
if (g_atomic_int_add(&driver->nactive, 1) == 0 && driver->inhibitCallback)
|
2014-02-26 21:11:30 +00:00
|
|
|
driver->inhibitCallback(true, driver->inhibitOpaque);
|
|
|
|
|
2016-07-11 11:55:53 +00:00
|
|
|
/* finally we can call the 'started' hook script if any */
|
|
|
|
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
2019-11-27 11:57:34 +00:00
|
|
|
char *xml = virDomainDefFormat(vm->def, driver->xmlopt, 0);
|
2016-07-11 11:55:53 +00:00
|
|
|
int hookret;
|
|
|
|
|
|
|
|
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
|
|
|
VIR_HOOK_LIBXL_OP_STARTED, VIR_HOOK_SUBOP_BEGIN,
|
|
|
|
NULL, xml, NULL);
|
|
|
|
VIR_FREE(xml);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the script raised an error abort the launch
|
|
|
|
*/
|
|
|
|
if (hookret < 0)
|
|
|
|
goto cleanup_dom;
|
|
|
|
}
|
|
|
|
|
2014-02-26 21:11:30 +00:00
|
|
|
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED,
|
|
|
|
restore_fd < 0 ?
|
|
|
|
VIR_DOMAIN_EVENT_STARTED_BOOTED :
|
|
|
|
VIR_DOMAIN_EVENT_STARTED_RESTORED);
|
2018-06-12 17:33:01 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2014-02-26 21:11:30 +00:00
|
|
|
|
|
|
|
ret = 0;
|
2015-03-02 01:24:26 +00:00
|
|
|
goto cleanup;
|
2014-02-26 21:11:30 +00:00
|
|
|
|
2016-03-28 19:47:07 +00:00
|
|
|
destroy_dom:
|
2015-04-14 20:38:46 +00:00
|
|
|
ret = -1;
|
2015-03-04 00:54:50 +00:00
|
|
|
libxlDomainDestroyInternal(driver, vm);
|
2014-02-26 21:11:30 +00:00
|
|
|
vm->def->id = -1;
|
|
|
|
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
|
|
|
|
|
2016-03-28 19:55:42 +00:00
|
|
|
cleanup_dom:
|
|
|
|
libxlDomainCleanup(driver, vm);
|
2015-04-14 20:38:46 +00:00
|
|
|
|
2015-03-02 01:24:26 +00:00
|
|
|
cleanup:
|
2014-02-26 21:11:30 +00:00
|
|
|
libxl_domain_config_dispose(&d_config);
|
2017-01-09 15:20:50 +00:00
|
|
|
VIR_FREE(config_json);
|
2014-02-26 21:11:30 +00:00
|
|
|
VIR_FREE(dom_xml);
|
|
|
|
VIR_FREE(managed_save_path);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
VIR_FORCE_CLOSE(managed_save_fd);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-06-04 20:02:27 +00:00
|
|
|
|
libxl: support Xen migration stream V2 in save/restore
Xen 4.6 introduced a new migration stream commonly referred to as
"migration V2". Xen 4.6 and newer always produce this new stream,
whereas Xen 4.5 and older always produce the legacy stream.
Support for migration stream V2 can be detected at build time with
LIBXL_HAVE_SRM_V2 from libxl.h. The legacy and V2 streams are not
compatible, but a V2 host can accept and convert a legacy stream.
Commit e7440656 changed the libxl driver to use the lowest libxl
API version possible (version 0x040200) to ensure the driver
builds against older Xen releases. The old 4.2 restore API does
not support specifying a stream version and assumes a legacy
stream, even if the incoming stream is migration V2. Thinking it
has been given a legacy stream, libxl will fail to convert an
incoming stream that is already V2, which causes the entire
restore operation to fail. Xen's libvirt-related OSSTest has been
failing since commit e7440656 landed in libvirt.git master. One
of the more recent failures can be seen here
http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg00071.html
This patch changes the call to libxl_domain_create_restore() to
include the stream version if LIBXL_HAVE_SRM_V2 is defined. The
version field of the libxlSavefileHeader struct is also updated
to '2' when LIBXL_HAVE_SRM_V2 is defined, ensuring the stream
version in the header matches the actual stream version produced
by Xen. Along with bumping the libxl API requirement to 0x040400,
this patch fixes save/restore on a migration V2 Xen host.
Oddly, migration has never used the libxlSavefileHeader. It
handles passing configuration in the Begin and Prepare phases,
and then calls libxl directly to transfer domain state/memory
in the Perform phase. A subsequent patch will add stream
version handling in the Begin and Prepare phase handshaking,
which will fix the migration related OSSTest failures.
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
2016-05-02 18:00:39 +00:00
|
|
|
int
|
|
|
|
libxlDomainStartNew(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
bool start_paused)
|
|
|
|
{
|
|
|
|
return libxlDomainStart(driver, vm, start_paused, -1, LIBXL_SAVE_VERSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
libxlDomainStartRestore(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
bool start_paused,
|
|
|
|
int restore_fd,
|
|
|
|
uint32_t restore_ver)
|
|
|
|
{
|
|
|
|
return libxlDomainStart(driver, vm, start_paused,
|
|
|
|
restore_fd, restore_ver);
|
|
|
|
}
|
|
|
|
|
2014-06-04 20:02:27 +00:00
|
|
|
bool
|
|
|
|
libxlDomainDefCheckABIStability(libxlDriverPrivatePtr driver,
|
|
|
|
virDomainDefPtr src,
|
|
|
|
virDomainDefPtr dst)
|
|
|
|
{
|
|
|
|
virDomainDefPtr migratableDefSrc = NULL;
|
|
|
|
virDomainDefPtr migratableDefDst = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
|
2019-11-27 12:41:59 +00:00
|
|
|
if (!(migratableDefSrc = virDomainDefCopy(src, driver->xmlopt, NULL, true)) ||
|
|
|
|
!(migratableDefDst = virDomainDefCopy(dst, driver->xmlopt, NULL, true)))
|
2014-06-04 20:02:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-05-19 13:07:15 +00:00
|
|
|
ret = virDomainDefCheckABIStability(migratableDefSrc,
|
|
|
|
migratableDefDst,
|
|
|
|
driver->xmlopt);
|
2014-06-04 20:02:27 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainDefFree(migratableDefSrc);
|
|
|
|
virDomainDefFree(migratableDefDst);
|
|
|
|
return ret;
|
|
|
|
}
|
2020-07-30 19:25:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
libxlDomainDefNamespaceFree(void *nsdata)
|
|
|
|
{
|
|
|
|
libxlDomainXmlNsDefPtr def = nsdata;
|
|
|
|
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_strfreev(def->args);
|
|
|
|
g_free(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,
|
|
|
|
void **data)
|
|
|
|
{
|
|
|
|
libxlDomainXmlNsDefPtr nsdata = NULL;
|
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
|
|
|
ssize_t nnodes;
|
|
|
|
size_t i;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if ((nnodes = virXPathNodeSet("./xen:commandline/xen:arg", ctxt, &nodes)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (nnodes == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsdata = g_new0(libxlDomainXmlNsDef, 1);
|
|
|
|
nsdata->args = g_new0(char *, nnodes + 1);
|
|
|
|
|
|
|
|
for (i = 0; i < nnodes; i++) {
|
|
|
|
if (!(nsdata->args[nsdata->num_args++] = virXMLPropString(nodes[i], "value"))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No device model command-line argument specified"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*data = g_steal_pointer(&nsdata);
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
libxlDomainDefNamespaceFree(nsdata);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
libxlDomainDefNamespaceFormatXML(virBufferPtr buf,
|
|
|
|
void *nsdata)
|
|
|
|
{
|
|
|
|
libxlDomainXmlNsDefPtr cmd = nsdata;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!cmd->num_args)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<xen:commandline>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
for (i = 0; i < cmd->num_args; i++)
|
|
|
|
virBufferEscapeString(buf, "<xen:arg value='%s'/>\n",
|
|
|
|
cmd->args[i]);
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</xen:commandline>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virXMLNamespace libxlDriverDomainXMLNamespace = {
|
|
|
|
.parse = libxlDomainDefNamespaceParse,
|
|
|
|
.free = libxlDomainDefNamespaceFree,
|
|
|
|
.format = libxlDomainDefNamespaceFormatXML,
|
|
|
|
.prefix = "xen",
|
|
|
|
.uri = "http://libvirt.org/schemas/domain/xen/1.0",
|
|
|
|
};
|