2010-12-16 15:23:41 +00:00
|
|
|
/*
|
2014-03-07 13:38:51 +00:00
|
|
|
* qemu_domain.c: QEMU domain private state
|
2010-12-16 15:23:41 +00:00
|
|
|
*
|
2013-02-06 18:17:20 +00:00
|
|
|
* Copyright (C) 2006-2013 Red Hat, Inc.
|
2010-12-16 15:23:41 +00:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-12-16 15:23:41 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_domain.h"
|
|
|
|
#include "qemu_command.h"
|
2011-05-04 11:55:38 +00:00
|
|
|
#include "qemu_capabilities.h"
|
2011-07-19 00:27:30 +00:00
|
|
|
#include "qemu_migration.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2010-12-16 15:23:41 +00:00
|
|
|
#include "c-ctype.h"
|
2011-01-31 10:47:03 +00:00
|
|
|
#include "cpu/cpu.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2011-10-18 14:15:42 +00:00
|
|
|
#include "domain_event.h"
|
2011-11-29 12:33:23 +00:00
|
|
|
#include "virtime.h"
|
2012-12-13 15:25:48 +00:00
|
|
|
#include "virstoragefile.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2010-12-16 15:23:41 +00:00
|
|
|
|
2010-12-16 16:12:02 +00:00
|
|
|
#include <sys/time.h>
|
2011-05-05 11:38:04 +00:00
|
|
|
#include <fcntl.h>
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2010-12-16 15:23:41 +00:00
|
|
|
#include <libxml/xpathInternals.h>
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
#define QEMU_NAMESPACE_HREF "http://libvirt.org/schemas/domain/qemu/1.0"
|
|
|
|
|
2011-06-06 08:28:38 +00:00
|
|
|
VIR_ENUM_IMPL(qemuDomainJob, QEMU_JOB_LAST,
|
|
|
|
"none",
|
|
|
|
"query",
|
|
|
|
"destroy",
|
|
|
|
"suspend",
|
|
|
|
"modify",
|
2011-07-19 00:27:39 +00:00
|
|
|
"abort",
|
2011-07-19 00:27:36 +00:00
|
|
|
"migration operation",
|
2011-06-06 08:28:38 +00:00
|
|
|
"none", /* async job is never stored in job.active */
|
|
|
|
"async nested",
|
|
|
|
);
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(qemuDomainAsyncJob, QEMU_ASYNC_JOB_LAST,
|
|
|
|
"none",
|
|
|
|
"migration out",
|
|
|
|
"migration in",
|
|
|
|
"save",
|
|
|
|
"dump",
|
2012-10-08 14:34:19 +00:00
|
|
|
"snapshot",
|
2011-06-06 08:28:38 +00:00
|
|
|
);
|
|
|
|
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2011-06-06 08:30:54 +00:00
|
|
|
const char *
|
|
|
|
qemuDomainAsyncJobPhaseToString(enum qemuDomainAsyncJob job,
|
|
|
|
int phase ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
switch (job) {
|
|
|
|
case QEMU_ASYNC_JOB_MIGRATION_OUT:
|
|
|
|
case QEMU_ASYNC_JOB_MIGRATION_IN:
|
2011-07-19 00:27:30 +00:00
|
|
|
return qemuMigrationJobPhaseTypeToString(phase);
|
|
|
|
|
2011-06-06 08:30:54 +00:00
|
|
|
case QEMU_ASYNC_JOB_SAVE:
|
|
|
|
case QEMU_ASYNC_JOB_DUMP:
|
2012-10-08 14:34:19 +00:00
|
|
|
case QEMU_ASYNC_JOB_SNAPSHOT:
|
2011-06-06 08:30:54 +00:00
|
|
|
case QEMU_ASYNC_JOB_NONE:
|
|
|
|
case QEMU_ASYNC_JOB_LAST:
|
|
|
|
; /* fall through */
|
|
|
|
}
|
|
|
|
|
|
|
|
return "none";
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuDomainAsyncJobPhaseFromString(enum qemuDomainAsyncJob job,
|
|
|
|
const char *phase)
|
|
|
|
{
|
|
|
|
if (!phase)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (job) {
|
|
|
|
case QEMU_ASYNC_JOB_MIGRATION_OUT:
|
|
|
|
case QEMU_ASYNC_JOB_MIGRATION_IN:
|
2011-07-19 00:27:30 +00:00
|
|
|
return qemuMigrationJobPhaseTypeFromString(phase);
|
|
|
|
|
2011-06-06 08:30:54 +00:00
|
|
|
case QEMU_ASYNC_JOB_SAVE:
|
|
|
|
case QEMU_ASYNC_JOB_DUMP:
|
2012-10-08 14:34:19 +00:00
|
|
|
case QEMU_ASYNC_JOB_SNAPSHOT:
|
2011-06-06 08:30:54 +00:00
|
|
|
case QEMU_ASYNC_JOB_NONE:
|
|
|
|
case QEMU_ASYNC_JOB_LAST:
|
|
|
|
; /* fall through */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ(phase, "none"))
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-02-14 16:09:39 +00:00
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainEventQueue(virQEMUDriverPtr driver,
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event)
|
2011-02-14 16:09:39 +00:00
|
|
|
{
|
2013-11-21 10:43:10 +00:00
|
|
|
virObjectEventStateQueue(driver->domainEventState, event);
|
2011-02-14 16:09:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
static int
|
|
|
|
qemuDomainObjInitJob(qemuDomainObjPrivatePtr priv)
|
|
|
|
{
|
|
|
|
memset(&priv->job, 0, sizeof(priv->job));
|
|
|
|
|
|
|
|
if (virCondInit(&priv->job.cond) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
if (virCondInit(&priv->job.asyncCond) < 0) {
|
2013-02-07 14:03:17 +00:00
|
|
|
virCondDestroy(&priv->job.cond);
|
2011-06-30 09:23:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qemuDomainObjResetJob(qemuDomainObjPrivatePtr priv)
|
|
|
|
{
|
|
|
|
struct qemuDomainJobObj *job = &priv->job;
|
|
|
|
|
|
|
|
job->active = QEMU_JOB_NONE;
|
2012-04-06 16:55:46 +00:00
|
|
|
job->owner = 0;
|
2011-06-30 09:23:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv)
|
|
|
|
{
|
|
|
|
struct qemuDomainJobObj *job = &priv->job;
|
|
|
|
|
|
|
|
job->asyncJob = QEMU_ASYNC_JOB_NONE;
|
2012-04-06 16:55:46 +00:00
|
|
|
job->asyncOwner = 0;
|
2011-06-06 08:30:54 +00:00
|
|
|
job->phase = 0;
|
2011-06-30 09:23:50 +00:00
|
|
|
job->mask = DEFAULT_JOB_MASK;
|
2011-06-06 08:34:33 +00:00
|
|
|
job->start = 0;
|
2012-06-12 03:06:33 +00:00
|
|
|
job->dump_memory_only = false;
|
2012-11-08 13:49:55 +00:00
|
|
|
job->asyncAbort = false;
|
2013-02-08 08:58:03 +00:00
|
|
|
memset(&job->status, 0, sizeof(job->status));
|
2011-06-06 08:34:33 +00:00
|
|
|
memset(&job->info, 0, sizeof(job->info));
|
|
|
|
}
|
|
|
|
|
2011-07-04 21:33:39 +00:00
|
|
|
void
|
|
|
|
qemuDomainObjRestoreJob(virDomainObjPtr obj,
|
|
|
|
struct qemuDomainJobObj *job)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
|
|
|
memset(job, 0, sizeof(*job));
|
|
|
|
job->active = priv->job.active;
|
2012-04-06 16:55:46 +00:00
|
|
|
job->owner = priv->job.owner;
|
2011-07-04 21:33:39 +00:00
|
|
|
job->asyncJob = priv->job.asyncJob;
|
2012-04-06 16:55:46 +00:00
|
|
|
job->asyncOwner = priv->job.asyncOwner;
|
2011-06-06 08:30:54 +00:00
|
|
|
job->phase = priv->job.phase;
|
2011-07-04 21:33:39 +00:00
|
|
|
|
|
|
|
qemuDomainObjResetJob(priv);
|
|
|
|
qemuDomainObjResetAsyncJob(priv);
|
|
|
|
}
|
|
|
|
|
2012-04-06 16:55:46 +00:00
|
|
|
void
|
|
|
|
qemuDomainObjTransferJob(virDomainObjPtr obj)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
VIR_DEBUG("Changing job owner from %llu to %llu",
|
2012-04-06 16:55:46 +00:00
|
|
|
priv->job.owner, virThreadSelfID());
|
|
|
|
priv->job.owner = virThreadSelfID();
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
static void
|
|
|
|
qemuDomainObjFreeJob(qemuDomainObjPrivatePtr priv)
|
|
|
|
{
|
2013-02-07 14:03:17 +00:00
|
|
|
virCondDestroy(&priv->job.cond);
|
|
|
|
virCondDestroy(&priv->job.asyncCond);
|
2011-06-06 08:34:33 +00:00
|
|
|
}
|
|
|
|
|
2012-04-06 17:42:34 +00:00
|
|
|
static bool
|
|
|
|
qemuDomainTrackJob(enum qemuDomainJob job)
|
|
|
|
{
|
|
|
|
return (QEMU_DOMAIN_TRACK_JOBS & JOB_MASK(job)) != 0;
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
static void *
|
|
|
|
qemuDomainObjPrivateAlloc(void)
|
2010-12-16 15:23:41 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(priv) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (qemuDomainObjInitJob(priv) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to init qemu driver mutexes"));
|
2011-11-23 14:51:28 +00:00
|
|
|
goto error;
|
2013-07-04 10:02:00 +00:00
|
|
|
}
|
2011-05-13 10:11:47 +00:00
|
|
|
|
2013-07-11 15:11:02 +00:00
|
|
|
if (virCondInit(&priv->unplugFinished) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2013-01-02 15:38:52 +00:00
|
|
|
if (!(priv->devs = virChrdevAlloc()))
|
2011-10-06 10:24:47 +00:00
|
|
|
goto error;
|
|
|
|
|
2012-08-03 16:34:06 +00:00
|
|
|
priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
|
2011-08-26 18:10:22 +00:00
|
|
|
|
2010-12-16 15:23:41 +00:00
|
|
|
return priv;
|
2011-11-23 14:51:28 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(priv);
|
|
|
|
return NULL;
|
2010-12-16 15:23:41 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 15:17:24 +00:00
|
|
|
static void
|
|
|
|
qemuDomainObjPrivateFree(void *data)
|
2010-12-16 15:23:41 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = data;
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
virObjectUnref(priv->qemuCaps);
|
2011-05-04 11:55:38 +00:00
|
|
|
|
2013-03-21 14:40:29 +00:00
|
|
|
virCgroupFree(&priv->cgroup);
|
2010-12-16 15:23:41 +00:00
|
|
|
qemuDomainPCIAddressSetFree(priv->pciaddrs);
|
2013-03-05 15:44:21 +00:00
|
|
|
qemuDomainCCWAddressSetFree(priv->ccwaddrs);
|
2011-01-07 23:36:25 +00:00
|
|
|
virDomainChrSourceDefFree(priv->monConfig);
|
2011-06-06 08:34:33 +00:00
|
|
|
qemuDomainObjFreeJob(priv);
|
2010-12-16 15:23:41 +00:00
|
|
|
VIR_FREE(priv->vcpupids);
|
2010-10-26 14:04:46 +00:00
|
|
|
VIR_FREE(priv->lockState);
|
2011-10-04 07:11:35 +00:00
|
|
|
VIR_FREE(priv->origname);
|
2010-12-16 15:23:41 +00:00
|
|
|
|
2013-07-11 15:11:02 +00:00
|
|
|
virCondDestroy(&priv->unplugFinished);
|
2013-01-02 15:38:52 +00:00
|
|
|
virChrdevFree(priv->devs);
|
2011-10-06 10:24:47 +00:00
|
|
|
|
2010-12-16 15:23:41 +00:00
|
|
|
/* This should never be non-NULL if we get here, but just in case... */
|
|
|
|
if (priv->mon) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_ERROR(_("Unexpected QEMU monitor still active during domain deletion"));
|
2010-12-16 15:23:41 +00:00
|
|
|
qemuMonitorClose(priv->mon);
|
|
|
|
}
|
2011-10-05 17:31:54 +00:00
|
|
|
if (priv->agent) {
|
|
|
|
VIR_ERROR(_("Unexpected QEMU agent still active during domain deletion"));
|
|
|
|
qemuAgentClose(priv->agent);
|
|
|
|
}
|
2012-03-16 06:52:26 +00:00
|
|
|
VIR_FREE(priv->cleanupCallbacks);
|
2010-12-16 15:23:41 +00:00
|
|
|
VIR_FREE(priv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-05 15:17:24 +00:00
|
|
|
static int
|
|
|
|
qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data)
|
2010-12-16 15:23:41 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = data;
|
|
|
|
const char *monitorpath;
|
2012-04-06 17:42:34 +00:00
|
|
|
enum qemuDomainJob job;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
/* priv->monitor_chr is set only for qemu */
|
|
|
|
if (priv->monConfig) {
|
2011-01-07 23:36:25 +00:00
|
|
|
switch (priv->monConfig->type) {
|
2010-12-16 15:23:41 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
2011-01-07 23:36:25 +00:00
|
|
|
monitorpath = priv->monConfig->data.nix.path;
|
2010-12-16 15:23:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2011-01-07 23:36:25 +00:00
|
|
|
monitorpath = priv->monConfig->data.file.path;
|
2010-12-16 15:23:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferEscapeString(buf, " <monitor path='%s'", monitorpath);
|
|
|
|
if (priv->monJSON)
|
|
|
|
virBufferAddLit(buf, " json='1'");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " type='%s'/>\n",
|
2011-01-07 23:36:25 +00:00
|
|
|
virDomainChrTypeToString(priv->monConfig->type));
|
2010-12-16 15:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (priv->nvcpupids) {
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2010-12-16 15:23:41 +00:00
|
|
|
virBufferAddLit(buf, " <vcpus>\n");
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < priv->nvcpupids; i++) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " <vcpu pid='%d'/>\n", priv->vcpupids[i]);
|
2010-12-16 15:23:41 +00:00
|
|
|
}
|
|
|
|
virBufferAddLit(buf, " </vcpus>\n");
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
if (priv->qemuCaps) {
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-05-04 11:55:38 +00:00
|
|
|
virBufferAddLit(buf, " <qemuCaps>\n");
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < QEMU_CAPS_LAST; i++) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (virQEMUCapsGet(priv->qemuCaps, i)) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " <flag name='%s'/>\n",
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsTypeToString(i));
|
2011-05-04 11:55:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, " </qemuCaps>\n");
|
|
|
|
}
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
if (priv->lockState)
|
|
|
|
virBufferAsprintf(buf, " <lockstate>%s</lockstate>\n", priv->lockState);
|
|
|
|
|
2012-04-06 17:42:34 +00:00
|
|
|
job = priv->job.active;
|
|
|
|
if (!qemuDomainTrackJob(job))
|
|
|
|
priv->job.active = QEMU_JOB_NONE;
|
|
|
|
|
2011-06-06 08:28:38 +00:00
|
|
|
if (priv->job.active || priv->job.asyncJob) {
|
2011-06-06 08:30:54 +00:00
|
|
|
virBufferAsprintf(buf, " <job type='%s' async='%s'",
|
2011-06-06 08:28:38 +00:00
|
|
|
qemuDomainJobTypeToString(priv->job.active),
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob));
|
2011-06-06 08:30:54 +00:00
|
|
|
if (priv->job.phase) {
|
|
|
|
virBufferAsprintf(buf, " phase='%s'",
|
|
|
|
qemuDomainAsyncJobPhaseToString(
|
|
|
|
priv->job.asyncJob, priv->job.phase));
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
2011-06-06 08:28:38 +00:00
|
|
|
}
|
2012-04-06 17:42:34 +00:00
|
|
|
priv->job.active = job;
|
2011-06-06 08:28:38 +00:00
|
|
|
|
2011-09-28 10:10:13 +00:00
|
|
|
if (priv->fakeReboot)
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(buf, " <fakereboot/>\n");
|
2011-09-28 10:10:13 +00:00
|
|
|
|
2013-07-19 13:08:29 +00:00
|
|
|
if (priv->qemuDevices && *priv->qemuDevices) {
|
|
|
|
char **tmp = priv->qemuDevices;
|
|
|
|
virBufferAddLit(buf, " <devices>\n");
|
|
|
|
while (*tmp) {
|
|
|
|
virBufferAsprintf(buf, " <device alias='%s'/>\n", *tmp);
|
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, " </devices>\n");
|
|
|
|
}
|
|
|
|
|
2010-12-16 15:23:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-05 15:17:24 +00:00
|
|
|
static int
|
|
|
|
qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
|
2010-12-16 15:23:41 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = data;
|
|
|
|
char *monitorpath;
|
|
|
|
char *tmp;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int n;
|
|
|
|
size_t i;
|
2010-12-16 15:23:41 +00:00
|
|
|
xmlNodePtr *nodes = NULL;
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsPtr qemuCaps = NULL;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (VIR_ALLOC(priv->monConfig) < 0)
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(monitorpath =
|
|
|
|
virXPathString("string(./monitor[1]/@path)", ctxt))) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no monitor path"));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = virXPathString("string(./monitor[1]/@type)", ctxt);
|
|
|
|
if (tmp)
|
2011-01-07 23:36:25 +00:00
|
|
|
priv->monConfig->type = virDomainChrTypeFromString(tmp);
|
2010-12-16 15:23:41 +00:00
|
|
|
else
|
2011-01-07 23:36:25 +00:00
|
|
|
priv->monConfig->type = VIR_DOMAIN_CHR_TYPE_PTY;
|
2010-12-16 15:23:41 +00:00
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
2013-04-26 02:32:41 +00:00
|
|
|
priv->monJSON = virXPathBoolean("count(./monitor[@json = '1']) > 0",
|
|
|
|
ctxt) > 0;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
2011-01-07 23:36:25 +00:00
|
|
|
switch (priv->monConfig->type) {
|
2010-12-16 15:23:41 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
2011-01-07 23:36:25 +00:00
|
|
|
priv->monConfig->data.file.path = monitorpath;
|
2010-12-16 15:23:41 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
2011-01-07 23:36:25 +00:00
|
|
|
priv->monConfig->data.nix.path = monitorpath;
|
2010-12-16 15:23:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
VIR_FREE(monitorpath);
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported monitor type '%s'"),
|
|
|
|
virDomainChrTypeToString(priv->monConfig->type));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes);
|
|
|
|
if (n < 0)
|
|
|
|
goto error;
|
|
|
|
if (n) {
|
|
|
|
priv->nvcpupids = n;
|
2013-07-04 10:14:12 +00:00
|
|
|
if (VIR_REALLOC_N(priv->vcpupids, priv->nvcpupids) < 0)
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2010-12-16 15:23:41 +00:00
|
|
|
char *pidstr = virXMLPropString(nodes[i], "pid");
|
|
|
|
if (!pidstr)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virStrToLong_i(pidstr, NULL, 10, &(priv->vcpupids[i])) < 0) {
|
|
|
|
VIR_FREE(pidstr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(pidstr);
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2011-05-04 11:55:38 +00:00
|
|
|
if ((n = virXPathNodeSet("./qemuCaps/flag", ctxt, &nodes)) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("failed to parse qemu capabilities flags"));
|
2011-05-04 11:55:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n > 0) {
|
2013-02-01 13:48:58 +00:00
|
|
|
if (!(qemuCaps = virQEMUCapsNew()))
|
2011-05-04 11:55:38 +00:00
|
|
|
goto error;
|
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2011-05-04 11:55:38 +00:00
|
|
|
char *str = virXMLPropString(nodes[i], "name");
|
|
|
|
if (str) {
|
2013-02-01 13:48:58 +00:00
|
|
|
int flag = virQEMUCapsTypeFromString(str);
|
2011-05-04 11:55:38 +00:00
|
|
|
if (flag < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown qemu capabilities flag %s"), str);
|
2011-06-03 14:33:25 +00:00
|
|
|
VIR_FREE(str);
|
2011-05-04 11:55:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2011-06-03 14:33:25 +00:00
|
|
|
VIR_FREE(str);
|
2013-02-01 13:48:58 +00:00
|
|
|
virQEMUCapsSet(qemuCaps, flag);
|
2011-05-04 11:55:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-01 13:48:58 +00:00
|
|
|
priv->qemuCaps = qemuCaps;
|
2011-05-04 11:55:38 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2010-10-26 14:04:46 +00:00
|
|
|
priv->lockState = virXPathString("string(./lockstate)", ctxt);
|
2011-05-04 11:55:38 +00:00
|
|
|
|
2011-06-06 08:28:38 +00:00
|
|
|
if ((tmp = virXPathString("string(./job[1]/@type)", ctxt))) {
|
|
|
|
int type;
|
|
|
|
|
|
|
|
if ((type = qemuDomainJobTypeFromString(tmp)) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown job type %s"), tmp);
|
2011-06-06 08:28:38 +00:00
|
|
|
VIR_FREE(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
priv->job.active = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tmp = virXPathString("string(./job[1]/@async)", ctxt))) {
|
|
|
|
int async;
|
|
|
|
|
|
|
|
if ((async = qemuDomainAsyncJobTypeFromString(tmp)) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown async job type %s"), tmp);
|
2011-06-06 08:28:38 +00:00
|
|
|
VIR_FREE(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
priv->job.asyncJob = async;
|
2011-06-06 08:30:54 +00:00
|
|
|
|
|
|
|
if ((tmp = virXPathString("string(./job[1]/@phase)", ctxt))) {
|
|
|
|
priv->job.phase = qemuDomainAsyncJobPhaseFromString(async, tmp);
|
|
|
|
if (priv->job.phase < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown job phase %s"), tmp);
|
2011-06-06 08:30:54 +00:00
|
|
|
VIR_FREE(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
2011-06-06 08:28:38 +00:00
|
|
|
}
|
|
|
|
|
2011-09-28 10:10:13 +00:00
|
|
|
priv->fakeReboot = virXPathBoolean("boolean(./fakereboot)", ctxt) == 1;
|
|
|
|
|
2013-07-19 13:08:29 +00:00
|
|
|
if ((n = virXPathNodeSet("./devices/device", ctxt, &nodes)) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to parse qemu device list"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n > 0) {
|
|
|
|
/* NULL-terminated list */
|
|
|
|
if (VIR_ALLOC_N(priv->qemuDevices, n + 1) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
priv->qemuDevices[i] = virXMLPropString(nodes[i], "alias");
|
|
|
|
if (!priv->qemuDevices[i]) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to parse qemu device list"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2010-12-16 15:23:41 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2011-01-07 23:36:25 +00:00
|
|
|
virDomainChrSourceDefFree(priv->monConfig);
|
2010-12-16 15:23:41 +00:00
|
|
|
priv->monConfig = NULL;
|
|
|
|
VIR_FREE(nodes);
|
2013-07-19 13:08:29 +00:00
|
|
|
virStringFreeList(priv->qemuDevices);
|
|
|
|
priv->qemuDevices = NULL;
|
2013-02-01 13:48:58 +00:00
|
|
|
virObjectUnref(qemuCaps);
|
2010-12-16 15:23:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-05 15:17:24 +00:00
|
|
|
virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks = {
|
|
|
|
.alloc = qemuDomainObjPrivateAlloc,
|
|
|
|
.free = qemuDomainObjPrivateFree,
|
|
|
|
.parse = qemuDomainObjPrivateXMLParse,
|
|
|
|
.format = qemuDomainObjPrivateXMLFormat,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-16 15:23:41 +00:00
|
|
|
static void
|
|
|
|
qemuDomainDefNamespaceFree(void *nsdata)
|
|
|
|
{
|
|
|
|
qemuDomainCmdlineDefPtr cmd = nsdata;
|
|
|
|
|
2013-09-24 15:38:26 +00:00
|
|
|
qemuDomainCmdlineDefFree(cmd);
|
2010-12-16 15:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-10-18 16:22:49 +00:00
|
|
|
qemuDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
|
|
|
|
xmlNodePtr root ATTRIBUTE_UNUSED,
|
2010-12-16 15:23:41 +00:00
|
|
|
xmlXPathContextPtr ctxt,
|
|
|
|
void **data)
|
|
|
|
{
|
|
|
|
qemuDomainCmdlineDefPtr cmd = NULL;
|
2011-10-18 16:22:49 +00:00
|
|
|
bool uses_qemu_ns = false;
|
2010-12-16 15:23:41 +00:00
|
|
|
xmlNodePtr *nodes = NULL;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int n;
|
|
|
|
size_t i;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
2011-10-18 16:22:49 +00:00
|
|
|
if (xmlXPathRegisterNs(ctxt, BAD_CAST "qemu", BAD_CAST QEMU_NAMESPACE_HREF) < 0) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to register xml namespace '%s'"),
|
|
|
|
QEMU_NAMESPACE_HREF);
|
2010-12-16 15:23:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (VIR_ALLOC(cmd) < 0)
|
2010-12-16 15:23:41 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* first handle the extra command-line arguments */
|
|
|
|
n = virXPathNodeSet("./qemu:commandline/qemu:arg", ctxt, &nodes);
|
|
|
|
if (n < 0)
|
|
|
|
goto error;
|
2011-10-18 16:22:49 +00:00
|
|
|
uses_qemu_ns |= n > 0;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
if (n && VIR_ALLOC_N(cmd->args, n) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
cmd->args[cmd->num_args] = virXMLPropString(nodes[i], "value");
|
|
|
|
if (cmd->args[cmd->num_args] == NULL) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("No qemu command-line argument specified"));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
cmd->num_args++;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
|
|
|
/* now handle the extra environment variables */
|
|
|
|
n = virXPathNodeSet("./qemu:commandline/qemu:env", ctxt, &nodes);
|
|
|
|
if (n < 0)
|
|
|
|
goto error;
|
2011-10-18 16:22:49 +00:00
|
|
|
uses_qemu_ns |= n > 0;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
if (n && VIR_ALLOC_N(cmd->env_name, n) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
if (n && VIR_ALLOC_N(cmd->env_value, n) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
tmp = virXMLPropString(nodes[i], "name");
|
|
|
|
if (tmp == NULL) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("No qemu environment name specified"));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (tmp[0] == '\0') {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Empty qemu environment name specified"));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!c_isalpha(tmp[0]) && tmp[0] != '_') {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Invalid environment name, it must begin with a letter or underscore"));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (strspn(tmp, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_") != strlen(tmp)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Invalid environment name, it must contain only alphanumerics and underscore"));
|
2010-12-16 15:23:41 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd->env_name[cmd->num_env] = tmp;
|
|
|
|
|
|
|
|
cmd->env_value[cmd->num_env] = virXMLPropString(nodes[i], "value");
|
|
|
|
/* a NULL value for command is allowed, since it might be empty */
|
|
|
|
cmd->num_env++;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2011-10-18 16:22:49 +00:00
|
|
|
if (uses_qemu_ns)
|
|
|
|
*data = cmd;
|
|
|
|
else
|
|
|
|
VIR_FREE(cmd);
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
qemuDomainDefNamespaceFree(cmd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuDomainDefNamespaceFormatXML(virBufferPtr buf,
|
|
|
|
void *nsdata)
|
|
|
|
{
|
|
|
|
qemuDomainCmdlineDefPtr cmd = nsdata;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2010-12-16 15:23:41 +00:00
|
|
|
|
|
|
|
if (!cmd->num_args && !cmd->num_env)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, " <qemu:commandline>\n");
|
|
|
|
for (i = 0; i < cmd->num_args; i++)
|
|
|
|
virBufferEscapeString(buf, " <qemu:arg value='%s'/>\n",
|
|
|
|
cmd->args[i]);
|
|
|
|
for (i = 0; i < cmd->num_env; i++) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " <qemu:env name='%s'", cmd->env_name[i]);
|
2010-12-16 15:23:41 +00:00
|
|
|
if (cmd->env_value[i])
|
|
|
|
virBufferEscapeString(buf, " value='%s'", cmd->env_value[i]);
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, " </qemu:commandline>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
qemuDomainDefNamespaceHref(void)
|
|
|
|
{
|
|
|
|
return "xmlns:qemu='" QEMU_NAMESPACE_HREF "'";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-05 15:17:24 +00:00
|
|
|
virDomainXMLNamespace virQEMUDriverDomainXMLNamespace = {
|
|
|
|
.parse = qemuDomainDefNamespaceParse,
|
|
|
|
.free = qemuDomainDefNamespaceFree,
|
|
|
|
.format = qemuDomainDefNamespaceFormatXML,
|
|
|
|
.href = qemuDomainDefNamespaceHref,
|
|
|
|
};
|
2010-12-16 15:23:41 +00:00
|
|
|
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2013-03-11 11:12:08 +00:00
|
|
|
static int
|
|
|
|
qemuDomainDefPostParse(virDomainDefPtr def,
|
|
|
|
virCapsPtr caps,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2013-08-02 08:13:33 +00:00
|
|
|
bool addDefaultUSB = true;
|
qemu: fix handling of default/implicit devices for q35
This patch adds in special handling for a few devices that need to be
treated differently for q35 domains:
usb - there is no implicit/default usb controller for the q35
machinetype. This is done because normally the default usb controller
is added to a domain by just adding "-usb" to the qemu commandline,
and it's assumed that this will add a single piix3 usb1 controller at
slot 1 function 2. That's not what happens when the machinetype is
q35, though. Instead, adding -usb to the commandline adds 3 usb
(version 2) controllers to the domain at slot 0x1D.{1,2,7}. Rather
than having
<controller type='usb' index='0'/>
translate into 3 separate devices on the PCI bus, it's cleaner to not
automatically add a default usb device; one can always be added
explicitly if desired. Or we may decide that on q35 machines, 3 usb
controllers will be automatically added when none is given. But for
this initial commit, at least we aren't locking ourselves into
something we later won't want.
video - qemu always initializes the primary video device immediately
after any integrated devices for the machinetype. Unless instructed
otherwise (by using "-device vga..." instead of "-vga" which libvirt
uses in many cases to work around deficiencies and bugs in various
qemu versions) qemu will always pick the first unused slot. In the
case of the "pc" machinetype and its derivatives, this is always slot
2, but on q35 machinetypes, the first free slot is slot 1 (since the
q35's integrated peripheral devices are placed in other slots,
e.g. slot 0x1f). In order to make the PCI address of the video device
predictable, that slot (1 or 2, depending on machinetype) is reserved
even when no video device has been specified.
sata - a q35 machine always has a sata controller implicitly added at
slot 0x1F, function 2. There is no way to avoid this controller, so we
always add it. Note that the xml2xml tests for the pcie-root and q35
cases were changed to use DO_TEST_DIFFERENT() so that we can check for
the sata controller being automatically added. This is especially
important because we can't check for it in the xml2argv output (it has
no effect on that output since it's an implicit device).
ide - q35 has no ide controllers.
isa and smbus controllers - these two are always present in a q35 (at
slot 0x1F functions 0 and 3) but we have no way of modelling them in
our config. We do need to reserve those functions so that the user
doesn't attempt to put anything else there though. (note that the "pc"
machine type also has an ISA controller, which we also ignore).
2013-08-02 08:55:55 +00:00
|
|
|
bool addImplicitSATA = false;
|
2013-04-22 12:16:13 +00:00
|
|
|
bool addPCIRoot = false;
|
2013-07-10 19:19:32 +00:00
|
|
|
bool addPCIeRoot = false;
|
2013-07-30 19:41:14 +00:00
|
|
|
bool addDefaultMemballoon = true;
|
2014-02-17 10:17:58 +00:00
|
|
|
bool addDefaultUSBKBD = false;
|
|
|
|
bool addDefaultUSBMouse = false;
|
2013-04-22 12:16:13 +00:00
|
|
|
|
2013-03-11 11:12:08 +00:00
|
|
|
/* check for emulator and create a default one if needed */
|
|
|
|
if (!def->emulator &&
|
|
|
|
!(def->emulator = virDomainDefGetDefaultEmulator(def, caps)))
|
|
|
|
return -1;
|
|
|
|
|
2013-04-22 12:16:13 +00:00
|
|
|
/* Add implicit PCI root controller if the machine has one */
|
|
|
|
switch (def->os.arch) {
|
|
|
|
case VIR_ARCH_I686:
|
|
|
|
case VIR_ARCH_X86_64:
|
|
|
|
if (!def->os.machine)
|
|
|
|
break;
|
2013-07-10 19:19:32 +00:00
|
|
|
if (STREQ(def->os.machine, "isapc")) {
|
2013-08-02 08:13:33 +00:00
|
|
|
addDefaultUSB = false;
|
2013-04-22 12:16:13 +00:00
|
|
|
break;
|
2013-08-02 08:13:33 +00:00
|
|
|
}
|
2013-07-10 19:19:32 +00:00
|
|
|
if (STRPREFIX(def->os.machine, "pc-q35") ||
|
|
|
|
STREQ(def->os.machine, "q35")) {
|
|
|
|
addPCIeRoot = true;
|
|
|
|
addDefaultUSB = false;
|
qemu: fix handling of default/implicit devices for q35
This patch adds in special handling for a few devices that need to be
treated differently for q35 domains:
usb - there is no implicit/default usb controller for the q35
machinetype. This is done because normally the default usb controller
is added to a domain by just adding "-usb" to the qemu commandline,
and it's assumed that this will add a single piix3 usb1 controller at
slot 1 function 2. That's not what happens when the machinetype is
q35, though. Instead, adding -usb to the commandline adds 3 usb
(version 2) controllers to the domain at slot 0x1D.{1,2,7}. Rather
than having
<controller type='usb' index='0'/>
translate into 3 separate devices on the PCI bus, it's cleaner to not
automatically add a default usb device; one can always be added
explicitly if desired. Or we may decide that on q35 machines, 3 usb
controllers will be automatically added when none is given. But for
this initial commit, at least we aren't locking ourselves into
something we later won't want.
video - qemu always initializes the primary video device immediately
after any integrated devices for the machinetype. Unless instructed
otherwise (by using "-device vga..." instead of "-vga" which libvirt
uses in many cases to work around deficiencies and bugs in various
qemu versions) qemu will always pick the first unused slot. In the
case of the "pc" machinetype and its derivatives, this is always slot
2, but on q35 machinetypes, the first free slot is slot 1 (since the
q35's integrated peripheral devices are placed in other slots,
e.g. slot 0x1f). In order to make the PCI address of the video device
predictable, that slot (1 or 2, depending on machinetype) is reserved
even when no video device has been specified.
sata - a q35 machine always has a sata controller implicitly added at
slot 0x1F, function 2. There is no way to avoid this controller, so we
always add it. Note that the xml2xml tests for the pcie-root and q35
cases were changed to use DO_TEST_DIFFERENT() so that we can check for
the sata controller being automatically added. This is especially
important because we can't check for it in the xml2argv output (it has
no effect on that output since it's an implicit device).
ide - q35 has no ide controllers.
isa and smbus controllers - these two are always present in a q35 (at
slot 0x1F functions 0 and 3) but we have no way of modelling them in
our config. We do need to reserve those functions so that the user
doesn't attempt to put anything else there though. (note that the "pc"
machine type also has an ISA controller, which we also ignore).
2013-08-02 08:55:55 +00:00
|
|
|
addImplicitSATA = true;
|
2013-07-10 19:19:32 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-04-22 12:16:13 +00:00
|
|
|
if (!STRPREFIX(def->os.machine, "pc-0.") &&
|
|
|
|
!STRPREFIX(def->os.machine, "pc-1.") &&
|
2013-04-25 13:17:12 +00:00
|
|
|
!STRPREFIX(def->os.machine, "pc-i440") &&
|
2013-04-22 12:16:13 +00:00
|
|
|
!STREQ(def->os.machine, "pc") &&
|
|
|
|
!STRPREFIX(def->os.machine, "rhel"))
|
|
|
|
break;
|
|
|
|
addPCIRoot = true;
|
|
|
|
break;
|
|
|
|
|
2013-08-02 08:13:33 +00:00
|
|
|
case VIR_ARCH_ARMV7L:
|
|
|
|
addDefaultUSB = false;
|
2013-07-30 19:41:14 +00:00
|
|
|
addDefaultMemballoon = false;
|
2013-08-02 08:13:33 +00:00
|
|
|
break;
|
2014-01-02 10:42:56 +00:00
|
|
|
case VIR_ARCH_AARCH64:
|
|
|
|
addDefaultUSB = false;
|
|
|
|
addDefaultMemballoon = false;
|
|
|
|
break;
|
2013-08-02 08:13:33 +00:00
|
|
|
|
2014-02-17 10:17:58 +00:00
|
|
|
case VIR_ARCH_PPC64:
|
|
|
|
addPCIRoot = true;
|
|
|
|
addDefaultUSBKBD = true;
|
|
|
|
addDefaultUSBMouse = true;
|
|
|
|
break;
|
|
|
|
|
2013-04-22 12:16:13 +00:00
|
|
|
case VIR_ARCH_ALPHA:
|
|
|
|
case VIR_ARCH_PPC:
|
|
|
|
case VIR_ARCH_PPCEMB:
|
|
|
|
case VIR_ARCH_SH4:
|
|
|
|
case VIR_ARCH_SH4EB:
|
|
|
|
addPCIRoot = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-02 08:13:33 +00:00
|
|
|
if (addDefaultUSB &&
|
|
|
|
virDomainDefMaybeAddController(
|
|
|
|
def, VIR_DOMAIN_CONTROLLER_TYPE_USB, 0, -1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
qemu: fix handling of default/implicit devices for q35
This patch adds in special handling for a few devices that need to be
treated differently for q35 domains:
usb - there is no implicit/default usb controller for the q35
machinetype. This is done because normally the default usb controller
is added to a domain by just adding "-usb" to the qemu commandline,
and it's assumed that this will add a single piix3 usb1 controller at
slot 1 function 2. That's not what happens when the machinetype is
q35, though. Instead, adding -usb to the commandline adds 3 usb
(version 2) controllers to the domain at slot 0x1D.{1,2,7}. Rather
than having
<controller type='usb' index='0'/>
translate into 3 separate devices on the PCI bus, it's cleaner to not
automatically add a default usb device; one can always be added
explicitly if desired. Or we may decide that on q35 machines, 3 usb
controllers will be automatically added when none is given. But for
this initial commit, at least we aren't locking ourselves into
something we later won't want.
video - qemu always initializes the primary video device immediately
after any integrated devices for the machinetype. Unless instructed
otherwise (by using "-device vga..." instead of "-vga" which libvirt
uses in many cases to work around deficiencies and bugs in various
qemu versions) qemu will always pick the first unused slot. In the
case of the "pc" machinetype and its derivatives, this is always slot
2, but on q35 machinetypes, the first free slot is slot 1 (since the
q35's integrated peripheral devices are placed in other slots,
e.g. slot 0x1f). In order to make the PCI address of the video device
predictable, that slot (1 or 2, depending on machinetype) is reserved
even when no video device has been specified.
sata - a q35 machine always has a sata controller implicitly added at
slot 0x1F, function 2. There is no way to avoid this controller, so we
always add it. Note that the xml2xml tests for the pcie-root and q35
cases were changed to use DO_TEST_DIFFERENT() so that we can check for
the sata controller being automatically added. This is especially
important because we can't check for it in the xml2argv output (it has
no effect on that output since it's an implicit device).
ide - q35 has no ide controllers.
isa and smbus controllers - these two are always present in a q35 (at
slot 0x1F functions 0 and 3) but we have no way of modelling them in
our config. We do need to reserve those functions so that the user
doesn't attempt to put anything else there though. (note that the "pc"
machine type also has an ISA controller, which we also ignore).
2013-08-02 08:55:55 +00:00
|
|
|
if (addImplicitSATA &&
|
|
|
|
virDomainDefMaybeAddController(
|
|
|
|
def, VIR_DOMAIN_CONTROLLER_TYPE_SATA, 0, -1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-04-22 12:16:13 +00:00
|
|
|
if (addPCIRoot &&
|
|
|
|
virDomainDefMaybeAddController(
|
|
|
|
def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)
|
|
|
|
return -1;
|
|
|
|
|
qemu: add dmi-to-pci-bridge controller
This PCI controller, named "dmi-to-pci-bridge" in the libvirt config,
and implemented with qemu's "i82801b11-bridge" device, connects to a
PCI Express slot (e.g. one of the slots provided by the pcie-root
controller, aka "pcie.0" on the qemu commandline), and provides 31
*non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31.
Any time a machine is defined which has a pcie-root controller
(i.e. any q35-based machinetype), libvirt will automatically add a
dmi-to-pci-bridge controller if one doesn't exist, and also add a
pci-bridge controller. The reasoning here is that any useful domain
will have either an immediate (startup time) or eventual (subsequent
hot-plug) need for a standard PCI slot; since the pcie-root controller
only provides PCIe slots, we need to connect a dmi-to-pci-bridge
controller to it in order to get a non-hot-plug PCI slot that we can
then use to connect a pci-bridge - the slots provided by the
pci-bridge will be both standard PCI and hot-pluggable.
Since pci-bridge devices themselves can not be hot-plugged into a
running system (although you can hot-plug other devices into a
pci-bridge's slots), any new pci-bridge controller that is added can
(and will) be plugged into the dmi-to-pci-bridge as long as it has
empty slots available.
This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST"
to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit
the automatically added dmi-to-pci-bridge and pci-bridge devices, and
the "after" xml can include it - this way we are testing if libvirt is
properly adding these devices.
2013-07-31 01:37:32 +00:00
|
|
|
/* When a machine has a pcie-root, make sure that there is always
|
|
|
|
* a dmi-to-pci-bridge controller added as bus 1, and a pci-bridge
|
|
|
|
* as bus 2, so that standard PCI devices can be connected
|
|
|
|
*/
|
|
|
|
if (addPCIeRoot) {
|
|
|
|
if (virDomainDefMaybeAddController(
|
|
|
|
def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 0,
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) < 0 ||
|
|
|
|
virDomainDefMaybeAddController(
|
|
|
|
def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 1,
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) < 0 ||
|
|
|
|
virDomainDefMaybeAddController(
|
|
|
|
def, VIR_DOMAIN_CONTROLLER_TYPE_PCI, 2,
|
|
|
|
VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) < 0) {
|
2013-07-10 19:19:32 +00:00
|
|
|
return -1;
|
qemu: add dmi-to-pci-bridge controller
This PCI controller, named "dmi-to-pci-bridge" in the libvirt config,
and implemented with qemu's "i82801b11-bridge" device, connects to a
PCI Express slot (e.g. one of the slots provided by the pcie-root
controller, aka "pcie.0" on the qemu commandline), and provides 31
*non-hot-pluggable* PCI (*not* PCIe) slots, numbered 1-31.
Any time a machine is defined which has a pcie-root controller
(i.e. any q35-based machinetype), libvirt will automatically add a
dmi-to-pci-bridge controller if one doesn't exist, and also add a
pci-bridge controller. The reasoning here is that any useful domain
will have either an immediate (startup time) or eventual (subsequent
hot-plug) need for a standard PCI slot; since the pcie-root controller
only provides PCIe slots, we need to connect a dmi-to-pci-bridge
controller to it in order to get a non-hot-plug PCI slot that we can
then use to connect a pci-bridge - the slots provided by the
pci-bridge will be both standard PCI and hot-pluggable.
Since pci-bridge devices themselves can not be hot-plugged into a
running system (although you can hot-plug other devices into a
pci-bridge's slots), any new pci-bridge controller that is added can
(and will) be plugged into the dmi-to-pci-bridge as long as it has
empty slots available.
This patch is also changing the qemuxml2xml-pcie test from a "DO_TEST"
to a "DO_DIFFERENT_TEST". This is so that the "before" xml can omit
the automatically added dmi-to-pci-bridge and pci-bridge devices, and
the "after" xml can include it - this way we are testing if libvirt is
properly adding these devices.
2013-07-31 01:37:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-17 00:33:23 +00:00
|
|
|
|
2013-07-30 19:41:14 +00:00
|
|
|
if (addDefaultMemballoon && !def->memballoon) {
|
2013-08-17 00:33:23 +00:00
|
|
|
virDomainMemballoonDefPtr memballoon;
|
|
|
|
if (VIR_ALLOC(memballoon) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
|
|
|
|
def->memballoon = memballoon;
|
|
|
|
}
|
|
|
|
|
2014-02-17 10:17:58 +00:00
|
|
|
if (addDefaultUSBKBD &&
|
|
|
|
def->ngraphics > 0 &&
|
|
|
|
virDomainDefMaybeAddInput(def,
|
|
|
|
VIR_DOMAIN_INPUT_TYPE_KBD,
|
|
|
|
VIR_DOMAIN_INPUT_BUS_USB) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (addDefaultUSBMouse &&
|
|
|
|
def->ngraphics > 0 &&
|
|
|
|
virDomainDefMaybeAddInput(def,
|
|
|
|
VIR_DOMAIN_INPUT_TYPE_MOUSE,
|
|
|
|
VIR_DOMAIN_INPUT_BUS_USB) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-03-11 11:12:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-30 22:51:30 +00:00
|
|
|
static const char *
|
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
|
|
|
qemuDomainDefaultNetModel(const virDomainDef *def)
|
|
|
|
{
|
2013-07-30 22:51:30 +00:00
|
|
|
if (def->os.arch == VIR_ARCH_S390 ||
|
|
|
|
def->os.arch == VIR_ARCH_S390X)
|
|
|
|
return "virtio";
|
|
|
|
|
2014-02-14 14:09:00 +00:00
|
|
|
if (def->os.arch == VIR_ARCH_ARMV7L ||
|
|
|
|
def->os.arch == VIR_ARCH_AARCH64) {
|
2013-07-30 22:51:30 +00:00
|
|
|
if (STREQ(def->os.machine, "versatilepb"))
|
|
|
|
return "smc91c111";
|
|
|
|
|
2013-11-19 21:49:40 +00:00
|
|
|
if (STREQ(def->os.machine, "virt"))
|
|
|
|
return "virtio";
|
|
|
|
|
2013-07-30 22:51:30 +00:00
|
|
|
/* Incomplete. vexpress (and a few others) use this, but not all
|
|
|
|
* arm boards */
|
|
|
|
return "lan9118";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "rtl8139";
|
|
|
|
}
|
2013-03-11 11:12:08 +00:00
|
|
|
|
2013-02-19 16:33:52 +00:00
|
|
|
static int
|
|
|
|
qemuDomainDeviceDefPostParse(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,
|
2013-02-19 16:33:52 +00:00
|
|
|
virCapsPtr caps ATTRIBUTE_UNUSED,
|
2013-03-11 09:24:29 +00:00
|
|
|
void *opaque)
|
2013-02-19 16:33:52 +00:00
|
|
|
{
|
2013-03-11 09:24:29 +00:00
|
|
|
int ret = -1;
|
|
|
|
virQEMUDriverPtr driver = opaque;
|
|
|
|
virQEMUDriverConfigPtr cfg = NULL;
|
|
|
|
|
2013-02-19 16:33:52 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_NET &&
|
2013-04-05 09:52:49 +00:00
|
|
|
dev->data.net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
|
|
|
|
!dev->data.net->model) {
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(dev->data.net->model,
|
2013-07-30 22:51:30 +00:00
|
|
|
qemuDomainDefaultNetModel(def)) < 0)
|
2013-05-20 09:23:13 +00:00
|
|
|
goto cleanup;
|
2013-02-19 16:33:52 +00:00
|
|
|
}
|
2013-03-11 09:24:29 +00:00
|
|
|
|
2013-03-13 14:28:11 +00:00
|
|
|
/* set default disk types and drivers */
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
virDomainDiskDefPtr disk = dev->data.disk;
|
|
|
|
|
|
|
|
/* both of these require data from the driver config */
|
|
|
|
if (driver && (cfg = virQEMUDriverGetConfig(driver))) {
|
|
|
|
/* assign default storage format and driver according to config */
|
|
|
|
if (cfg->allowDiskFormatProbing) {
|
|
|
|
/* default disk format for drives */
|
|
|
|
if (disk->format == VIR_STORAGE_FILE_NONE &&
|
|
|
|
(disk->type == VIR_DOMAIN_DISK_TYPE_FILE ||
|
|
|
|
disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK))
|
|
|
|
disk->format = VIR_STORAGE_FILE_AUTO;
|
|
|
|
|
|
|
|
/* default disk format for mirrored drive */
|
|
|
|
if (disk->mirror &&
|
|
|
|
disk->mirrorFormat == VIR_STORAGE_FILE_NONE)
|
|
|
|
disk->mirrorFormat = VIR_STORAGE_FILE_AUTO;
|
|
|
|
} else {
|
|
|
|
/* default driver if probing is forbidden */
|
|
|
|
if (!disk->driverName &&
|
2013-05-20 09:23:13 +00:00
|
|
|
VIR_STRDUP(disk->driverName, "qemu") < 0)
|
|
|
|
goto cleanup;
|
2013-03-13 14:28:11 +00:00
|
|
|
|
|
|
|
/* default disk format for drives */
|
|
|
|
if (disk->format == VIR_STORAGE_FILE_NONE &&
|
|
|
|
(disk->type == VIR_DOMAIN_DISK_TYPE_FILE ||
|
|
|
|
disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK))
|
|
|
|
disk->format = VIR_STORAGE_FILE_RAW;
|
|
|
|
|
|
|
|
/* default disk format for mirrored drive */
|
|
|
|
if (disk->mirror &&
|
|
|
|
disk->mirrorFormat == VIR_STORAGE_FILE_NONE)
|
|
|
|
disk->mirrorFormat = VIR_STORAGE_FILE_RAW;
|
|
|
|
}
|
2013-03-11 09:24:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-13 20:39:34 +00:00
|
|
|
/* set the default console type for S390 arches */
|
|
|
|
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 &&
|
|
|
|
(def->os.arch == VIR_ARCH_S390 || def->os.arch == VIR_ARCH_S390X))
|
|
|
|
dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO;
|
|
|
|
|
2013-04-29 16:11:29 +00:00
|
|
|
/* set the default USB model to none for s390 unless an address is found */
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER &&
|
|
|
|
dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
|
|
|
|
dev->data.controller->model == -1 &&
|
|
|
|
dev->data.controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
(def->os.arch == VIR_ARCH_S390 || def->os.arch == VIR_ARCH_S390X))
|
|
|
|
dev->data.controller->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE;
|
|
|
|
|
2013-04-09 17:04:00 +00:00
|
|
|
/* auto generate unix socket path */
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
|
|
|
|
dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
|
|
|
|
dev->data.chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
|
|
|
|
dev->data.chr->source.type == VIR_DOMAIN_CHR_TYPE_UNIX &&
|
|
|
|
!dev->data.chr->source.data.nix.path &&
|
|
|
|
(driver && (cfg = virQEMUDriverGetConfig(driver)))) {
|
|
|
|
|
|
|
|
if (virAsprintf(&dev->data.chr->source.data.nix.path,
|
|
|
|
"%s/channel/target/%s.%s",
|
|
|
|
cfg->libDir, def->name,
|
2013-07-04 10:14:12 +00:00
|
|
|
dev->data.chr->target.name) < 0)
|
2013-05-20 09:23:13 +00:00
|
|
|
goto cleanup;
|
2013-04-09 17:04:00 +00:00
|
|
|
dev->data.chr->source.data.nix.listen = true;
|
|
|
|
}
|
|
|
|
|
2013-03-11 09:24:29 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return ret;
|
2013-02-19 16:33:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virDomainDefParserConfig virQEMUDriverDomainDefParserConfig = {
|
|
|
|
.devicesPostParseCallback = qemuDomainDeviceDefPostParse,
|
2013-03-11 11:12:08 +00:00
|
|
|
.domainPostParseCallback = qemuDomainDefPostParse,
|
2013-02-19 16:33:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-07-19 00:27:31 +00:00
|
|
|
static void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjSaveJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
|
2011-06-06 08:34:33 +00:00
|
|
|
{
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
|
|
|
|
|
if (virDomainObjIsActive(obj)) {
|
2013-03-31 18:03:42 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj) < 0)
|
2013-01-10 21:03:14 +00:00
|
|
|
VIR_WARN("Failed to save status on vm %s", obj->def->name);
|
2011-06-06 08:28:38 +00:00
|
|
|
}
|
2011-06-06 08:34:33 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2011-06-06 08:34:33 +00:00
|
|
|
}
|
|
|
|
|
2011-06-06 08:30:54 +00:00
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjSetJobPhase(virQEMUDriverPtr driver,
|
2011-06-06 08:30:54 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
int phase)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
unsigned long long me = virThreadSelfID();
|
2011-06-06 08:30:54 +00:00
|
|
|
|
|
|
|
if (!priv->job.asyncJob)
|
|
|
|
return;
|
|
|
|
|
2012-04-06 16:55:46 +00:00
|
|
|
VIR_DEBUG("Setting '%s' phase to '%s'",
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
qemuDomainAsyncJobPhaseToString(priv->job.asyncJob, phase));
|
|
|
|
|
|
|
|
if (priv->job.asyncOwner && me != priv->job.asyncOwner) {
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
VIR_WARN("'%s' async job is owned by thread %llu",
|
2012-04-06 16:55:46 +00:00
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
priv->job.asyncOwner);
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:30:54 +00:00
|
|
|
priv->job.phase = phase;
|
2012-04-06 16:55:46 +00:00
|
|
|
priv->job.asyncOwner = me;
|
2011-06-06 08:30:54 +00:00
|
|
|
qemuDomainObjSaveJob(driver, obj);
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
void
|
2011-06-30 09:23:50 +00:00
|
|
|
qemuDomainObjSetAsyncJobMask(virDomainObjPtr obj,
|
|
|
|
unsigned long long allowedJobs)
|
2011-06-06 08:34:33 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
if (!priv->job.asyncJob)
|
|
|
|
return;
|
|
|
|
|
|
|
|
priv->job.mask = allowedJobs | JOB_MASK(QEMU_JOB_DESTROY);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjDiscardAsyncJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
|
2011-06-30 09:23:50 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
|
|
|
if (priv->job.active == QEMU_JOB_ASYNC_NESTED)
|
|
|
|
qemuDomainObjResetJob(priv);
|
|
|
|
qemuDomainObjResetAsyncJob(priv);
|
2011-06-06 08:28:38 +00:00
|
|
|
qemuDomainObjSaveJob(driver, obj);
|
2011-06-30 09:23:50 +00:00
|
|
|
}
|
|
|
|
|
2012-04-06 16:55:46 +00:00
|
|
|
void
|
|
|
|
qemuDomainObjReleaseAsyncJob(virDomainObjPtr obj)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
|
|
|
VIR_DEBUG("Releasing ownership of '%s' async job",
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob));
|
|
|
|
|
|
|
|
if (priv->job.asyncOwner != virThreadSelfID()) {
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
VIR_WARN("'%s' async job is owned by thread %llu",
|
2012-04-06 16:55:46 +00:00
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
priv->job.asyncOwner);
|
|
|
|
}
|
|
|
|
priv->job.asyncOwner = 0;
|
|
|
|
}
|
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
static bool
|
2011-09-29 13:14:13 +00:00
|
|
|
qemuDomainNestedJobAllowed(qemuDomainObjPrivatePtr priv, enum qemuDomainJob job)
|
2011-06-30 09:23:50 +00:00
|
|
|
{
|
|
|
|
return !priv->job.asyncJob || (priv->job.mask & JOB_MASK(job)) != 0;
|
2011-06-06 08:34:33 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 13:14:13 +00:00
|
|
|
bool
|
|
|
|
qemuDomainJobAllowed(qemuDomainObjPrivatePtr priv, enum qemuDomainJob job)
|
|
|
|
{
|
|
|
|
return !priv->job.active && qemuDomainNestedJobAllowed(priv, job);
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:12:02 +00:00
|
|
|
/* Give up waiting for mutex after 30 seconds */
|
|
|
|
#define QEMU_JOB_WAIT_TIME (1000ull * 30)
|
|
|
|
|
2011-06-30 09:21:34 +00:00
|
|
|
/*
|
2013-02-06 18:17:20 +00:00
|
|
|
* obj must be locked before calling
|
2011-06-30 09:21:34 +00:00
|
|
|
*/
|
2011-06-06 08:28:38 +00:00
|
|
|
static int ATTRIBUTE_NONNULL(1)
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjBeginJobInternal(virQEMUDriverPtr driver,
|
2011-06-30 09:23:50 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
enum qemuDomainJob job,
|
|
|
|
enum qemuDomainAsyncJob asyncJob)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
2011-06-01 10:35:18 +00:00
|
|
|
unsigned long long now;
|
2010-12-16 16:12:02 +00:00
|
|
|
unsigned long long then;
|
2011-06-30 09:23:50 +00:00
|
|
|
bool nested = job == QEMU_JOB_ASYNC_NESTED;
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Starting %s: %s (async=%s vm=%p name=%s)",
|
|
|
|
job == QEMU_JOB_ASYNC ? "async job" : "job",
|
|
|
|
qemuDomainJobTypeToString(job),
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
obj, obj->def->name);
|
|
|
|
|
2011-08-12 13:29:37 +00:00
|
|
|
priv->jobs_queued++;
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virTimeMillisNow(&now) < 0) {
|
|
|
|
virObjectUnref(cfg);
|
2010-12-16 16:12:02 +00:00
|
|
|
return -1;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
|
2011-06-01 10:35:18 +00:00
|
|
|
then = now + QEMU_JOB_WAIT_TIME;
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2012-07-11 13:35:46 +00:00
|
|
|
virObjectRef(obj);
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
retry:
|
2013-01-10 21:03:14 +00:00
|
|
|
if (cfg->maxQueuedJobs &&
|
|
|
|
priv->jobs_queued > cfg->maxQueuedJobs) {
|
2011-08-12 13:29:37 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-09-29 13:14:13 +00:00
|
|
|
while (!nested && !qemuDomainNestedJobAllowed(priv, job)) {
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Waiting for async job (vm=%p name=%s)", obj, obj->def->name);
|
2013-01-09 21:00:32 +00:00
|
|
|
if (virCondWaitUntil(&priv->job.asyncCond, &obj->parent.lock, then) < 0)
|
2011-06-30 09:23:50 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
while (priv->job.active) {
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Waiting for job (vm=%p name=%s)", obj, obj->def->name);
|
2013-01-09 21:00:32 +00:00
|
|
|
if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
|
2011-06-30 09:23:50 +00:00
|
|
|
goto error;
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
2011-06-30 09:23:50 +00:00
|
|
|
|
|
|
|
/* No job is active but a new async job could have been started while obj
|
|
|
|
* was unlocked, so we need to recheck it. */
|
2011-09-29 13:14:13 +00:00
|
|
|
if (!nested && !qemuDomainNestedJobAllowed(priv, job))
|
2011-06-30 09:23:50 +00:00
|
|
|
goto retry;
|
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
qemuDomainObjResetJob(priv);
|
2011-06-30 09:23:50 +00:00
|
|
|
|
|
|
|
if (job != QEMU_JOB_ASYNC) {
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Started job: %s (async=%s vm=%p name=%s)",
|
2011-10-13 10:32:38 +00:00
|
|
|
qemuDomainJobTypeToString(job),
|
2013-10-31 11:27:10 +00:00
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
obj, obj->def->name);
|
2011-06-30 09:23:50 +00:00
|
|
|
priv->job.active = job;
|
2012-04-06 16:55:46 +00:00
|
|
|
priv->job.owner = virThreadSelfID();
|
2011-06-30 09:23:50 +00:00
|
|
|
} else {
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Started async job: %s (vm=%p name=%s)",
|
|
|
|
qemuDomainAsyncJobTypeToString(asyncJob),
|
|
|
|
obj, obj->def->name);
|
2011-06-30 09:23:50 +00:00
|
|
|
qemuDomainObjResetAsyncJob(priv);
|
|
|
|
priv->job.asyncJob = asyncJob;
|
2012-04-06 16:55:46 +00:00
|
|
|
priv->job.asyncOwner = virThreadSelfID();
|
2011-06-30 09:23:50 +00:00
|
|
|
priv->job.start = now;
|
|
|
|
}
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2012-04-06 17:42:34 +00:00
|
|
|
if (qemuDomainTrackJob(job))
|
|
|
|
qemuDomainObjSaveJob(driver, obj);
|
2011-06-06 08:28:38 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2010-12-16 16:12:02 +00:00
|
|
|
return 0;
|
2011-06-30 09:23:50 +00:00
|
|
|
|
|
|
|
error:
|
2012-04-06 16:55:46 +00:00
|
|
|
VIR_WARN("Cannot start job (%s, %s) for domain %s;"
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
" current job is (%s, %s) owned by (%llu, %llu)",
|
2012-04-06 16:55:46 +00:00
|
|
|
qemuDomainJobTypeToString(job),
|
|
|
|
qemuDomainAsyncJobTypeToString(asyncJob),
|
|
|
|
obj->def->name,
|
|
|
|
qemuDomainJobTypeToString(priv->job.active),
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
priv->job.owner, priv->job.asyncOwner);
|
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
if (errno == ETIMEDOUT)
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_TIMEOUT,
|
|
|
|
"%s", _("cannot acquire state change lock"));
|
2013-01-10 21:03:14 +00:00
|
|
|
else if (cfg->maxQueuedJobs &&
|
|
|
|
priv->jobs_queued > cfg->maxQueuedJobs)
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot acquire state change lock "
|
|
|
|
"due to max_queued limit"));
|
2011-06-30 09:23:50 +00:00
|
|
|
else
|
|
|
|
virReportSystemError(errno,
|
|
|
|
"%s", _("cannot acquire job mutex"));
|
2011-08-12 13:29:37 +00:00
|
|
|
priv->jobs_queued--;
|
2012-07-11 13:35:46 +00:00
|
|
|
virObjectUnref(obj);
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2011-06-30 09:23:50 +00:00
|
|
|
return -1;
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-06 18:17:20 +00:00
|
|
|
* obj must be locked before calling
|
2011-06-30 09:21:34 +00:00
|
|
|
*
|
|
|
|
* This must be called by anything that will change the VM state
|
|
|
|
* in any way, or anything that will use the QEMU monitor.
|
|
|
|
*
|
|
|
|
* Upon successful return, the object will have its ref count increased,
|
|
|
|
* successful calls must be followed by EndJob eventually
|
|
|
|
*/
|
2012-11-28 16:43:10 +00:00
|
|
|
int qemuDomainObjBeginJob(virQEMUDriverPtr driver,
|
2011-06-06 08:28:38 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
enum qemuDomainJob job)
|
2011-06-30 09:23:50 +00:00
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
return qemuDomainObjBeginJobInternal(driver, obj, job,
|
2011-06-30 09:23:50 +00:00
|
|
|
QEMU_ASYNC_JOB_NONE);
|
|
|
|
}
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
int qemuDomainObjBeginAsyncJob(virQEMUDriverPtr driver,
|
2011-06-06 08:28:38 +00:00
|
|
|
virDomainObjPtr obj,
|
2011-06-30 09:23:50 +00:00
|
|
|
enum qemuDomainAsyncJob asyncJob)
|
2011-06-30 09:21:34 +00:00
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
return qemuDomainObjBeginJobInternal(driver, obj, QEMU_JOB_ASYNC,
|
2011-06-30 09:23:50 +00:00
|
|
|
asyncJob);
|
2011-06-30 09:21:34 +00:00
|
|
|
}
|
|
|
|
|
2013-02-28 11:48:01 +00:00
|
|
|
int
|
|
|
|
qemuDomainObjBeginNestedJob(virQEMUDriverPtr driver,
|
|
|
|
virDomainObjPtr obj,
|
|
|
|
enum qemuDomainAsyncJob asyncJob)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
|
|
|
if (asyncJob != priv->job.asyncJob) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected async job %d"), asyncJob);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->job.asyncOwner != virThreadSelfID()) {
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
VIR_WARN("This thread doesn't seem to be the async job owner: %llu",
|
2013-02-28 11:48:01 +00:00
|
|
|
priv->job.asyncOwner);
|
|
|
|
}
|
|
|
|
|
|
|
|
return qemuDomainObjBeginJobInternal(driver, obj,
|
|
|
|
QEMU_JOB_ASYNC_NESTED,
|
|
|
|
QEMU_ASYNC_JOB_NONE);
|
|
|
|
}
|
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
|
2010-12-16 16:12:02 +00:00
|
|
|
/*
|
2013-02-06 18:17:20 +00:00
|
|
|
* obj must be locked before calling
|
2010-12-16 16:12:02 +00:00
|
|
|
*
|
|
|
|
* To be called after completing the work associated with the
|
|
|
|
* earlier qemuDomainBeginJob() call
|
|
|
|
*
|
2012-07-11 13:35:46 +00:00
|
|
|
* Returns true if @obj was still referenced, false if it was
|
|
|
|
* disposed of.
|
2010-12-16 16:12:02 +00:00
|
|
|
*/
|
2012-11-28 16:43:10 +00:00
|
|
|
bool qemuDomainObjEndJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
2012-04-06 17:42:34 +00:00
|
|
|
enum qemuDomainJob job = priv->job.active;
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2011-08-12 13:29:37 +00:00
|
|
|
priv->jobs_queued--;
|
|
|
|
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Stopping job: %s (async=%s vm=%p name=%s)",
|
2012-04-06 17:42:34 +00:00
|
|
|
qemuDomainJobTypeToString(job),
|
2013-10-31 11:27:10 +00:00
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
obj, obj->def->name);
|
2011-10-13 10:32:38 +00:00
|
|
|
|
2011-06-06 08:34:33 +00:00
|
|
|
qemuDomainObjResetJob(priv);
|
2012-04-06 17:42:34 +00:00
|
|
|
if (qemuDomainTrackJob(job))
|
|
|
|
qemuDomainObjSaveJob(driver, obj);
|
2011-06-06 08:34:33 +00:00
|
|
|
virCondSignal(&priv->job.cond);
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2012-07-11 13:35:46 +00:00
|
|
|
return virObjectUnref(obj);
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
|
|
|
|
2012-07-11 13:35:46 +00:00
|
|
|
bool
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjEndAsyncJob(virQEMUDriverPtr driver, virDomainObjPtr obj)
|
2011-06-30 09:23:50 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
2011-07-03 21:55:47 +00:00
|
|
|
|
2011-08-12 13:29:37 +00:00
|
|
|
priv->jobs_queued--;
|
|
|
|
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Stopping async job: %s (vm=%p name=%s)",
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
obj, obj->def->name);
|
2011-10-13 10:32:38 +00:00
|
|
|
|
2011-06-30 09:23:50 +00:00
|
|
|
qemuDomainObjResetAsyncJob(priv);
|
2011-06-06 08:28:38 +00:00
|
|
|
qemuDomainObjSaveJob(driver, obj);
|
2011-06-30 09:23:50 +00:00
|
|
|
virCondBroadcast(&priv->job.asyncCond);
|
|
|
|
|
2012-07-11 13:35:46 +00:00
|
|
|
return virObjectUnref(obj);
|
2011-06-30 09:23:50 +00:00
|
|
|
}
|
|
|
|
|
2012-11-08 13:49:55 +00:00
|
|
|
void
|
|
|
|
qemuDomainObjAbortAsyncJob(virDomainObjPtr obj)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Requesting abort of async job: %s (vm=%p name=%s)",
|
|
|
|
qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
|
|
|
|
obj, obj->def->name);
|
2012-11-08 13:49:55 +00:00
|
|
|
|
|
|
|
priv->job.asyncAbort = true;
|
|
|
|
}
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
/*
|
|
|
|
* obj must be locked before calling
|
|
|
|
*
|
|
|
|
* To be called immediately before any QEMU monitor API call
|
|
|
|
* Must have already either called qemuDomainObjBeginJob() and checked
|
|
|
|
* that the VM is still active; may not be used for nested async jobs.
|
|
|
|
*
|
|
|
|
* To be followed with qemuDomainObjExitMonitor() once complete
|
|
|
|
*/
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
static int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjEnterMonitorInternal(virQEMUDriverPtr driver,
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
enum qemuDomainAsyncJob asyncJob)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
if (asyncJob != QEMU_ASYNC_JOB_NONE) {
|
2013-02-28 11:48:01 +00:00
|
|
|
if (qemuDomainObjBeginNestedJob(driver, obj, asyncJob) < 0)
|
2011-06-30 09:23:50 +00:00
|
|
|
return -1;
|
|
|
|
if (!virDomainObjIsActive(obj)) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("domain is no longer running"));
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
/* Still referenced by the containing async job. */
|
|
|
|
ignore_value(qemuDomainObjEndJob(driver, obj));
|
2011-06-30 09:23:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-04-10 14:39:33 +00:00
|
|
|
} else if (priv->job.asyncOwner == virThreadSelfID()) {
|
|
|
|
VIR_WARN("This thread seems to be the async job owner; entering"
|
|
|
|
" monitor without asking for a nested job is dangerous");
|
2011-06-30 09:23:50 +00:00
|
|
|
}
|
|
|
|
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Entering monitor (mon=%p vm=%p name=%s)",
|
|
|
|
priv->mon, obj, obj->def->name);
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectLock(priv->mon);
|
2012-07-11 13:35:47 +00:00
|
|
|
virObjectRef(priv->mon);
|
2011-11-29 12:33:23 +00:00
|
|
|
ignore_value(virTimeMillisNow(&priv->monStart));
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(obj);
|
2011-06-30 09:23:50 +00:00
|
|
|
|
|
|
|
return 0;
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
|
|
|
|
2011-06-06 08:28:38 +00:00
|
|
|
static void ATTRIBUTE_NONNULL(1)
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjExitMonitorInternal(virQEMUDriverPtr driver,
|
2011-07-03 21:55:47 +00:00
|
|
|
virDomainObjPtr obj)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
2012-07-11 13:35:47 +00:00
|
|
|
bool hasRefs;
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2012-07-11 13:35:47 +00:00
|
|
|
hasRefs = virObjectUnref(priv->mon);
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2012-07-11 13:35:47 +00:00
|
|
|
if (hasRefs)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(priv->mon);
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectLock(obj);
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Exited monitor (mon=%p vm=%p name=%s)",
|
|
|
|
priv->mon, obj, obj->def->name);
|
2010-12-16 16:12:02 +00:00
|
|
|
|
2011-05-31 16:34:20 +00:00
|
|
|
priv->monStart = 0;
|
2012-07-11 13:35:47 +00:00
|
|
|
if (!hasRefs)
|
2010-12-16 16:12:02 +00:00
|
|
|
priv->mon = NULL;
|
2011-06-30 09:23:50 +00:00
|
|
|
|
2011-07-27 23:13:22 +00:00
|
|
|
if (priv->job.active == QEMU_JOB_ASYNC_NESTED) {
|
|
|
|
qemuDomainObjResetJob(priv);
|
|
|
|
qemuDomainObjSaveJob(driver, obj);
|
|
|
|
virCondSignal(&priv->job.cond);
|
|
|
|
|
2012-07-11 13:35:46 +00:00
|
|
|
virObjectUnref(obj);
|
2011-07-27 23:13:22 +00:00
|
|
|
}
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainObjEnterMonitor(virQEMUDriverPtr driver,
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
virDomainObjPtr obj)
|
2011-07-03 21:55:47 +00:00
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
ignore_value(qemuDomainObjEnterMonitorInternal(driver, obj,
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
QEMU_ASYNC_JOB_NONE));
|
2011-07-03 21:55:47 +00:00
|
|
|
}
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
/* obj must NOT be locked before calling
|
2011-07-03 21:55:47 +00:00
|
|
|
*
|
|
|
|
* Should be paired with an earlier qemuDomainObjEnterMonitor() call
|
|
|
|
*/
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainObjExitMonitor(virQEMUDriverPtr driver,
|
2011-06-06 08:28:38 +00:00
|
|
|
virDomainObjPtr obj)
|
2011-07-03 21:55:47 +00:00
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDomainObjExitMonitorInternal(driver, obj);
|
2011-07-03 21:55:47 +00:00
|
|
|
}
|
2010-12-16 16:12:02 +00:00
|
|
|
|
|
|
|
/*
|
2013-02-06 18:17:20 +00:00
|
|
|
* obj must be locked before calling
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
*
|
|
|
|
* To be called immediately before any QEMU monitor API call.
|
2013-02-06 18:17:20 +00:00
|
|
|
* Must have already either called qemuDomainObjBeginJob()
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
* and checked that the VM is still active, with asyncJob of
|
|
|
|
* QEMU_ASYNC_JOB_NONE; or already called qemuDomainObjBeginAsyncJob,
|
|
|
|
* with the same asyncJob.
|
|
|
|
*
|
|
|
|
* Returns 0 if job was started, in which case this must be followed with
|
2013-02-06 18:17:20 +00:00
|
|
|
* qemuDomainObjExitMonitor(); or -1 if the job could not be
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
* started (probably because the vm exited in the meantime).
|
|
|
|
*/
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainObjEnterMonitorAsync(virQEMUDriverPtr driver,
|
qemu: fix crash when mixing sync and async monitor jobs
Currently, we attempt to run sync job and async job at the same time. It
means that the monitor commands for two jobs can be run in any order.
In the function qemuDomainObjEnterMonitorInternal():
if (priv->job.active == QEMU_JOB_NONE && priv->job.asyncJob) {
if (qemuDomainObjBeginNestedJob(driver, obj) < 0)
We check whether the caller is an async job by priv->job.active and
priv->job.asynJob. But when an async job is running, and a sync job is
also running at the time of the check, then priv->job.active is not
QEMU_JOB_NONE. So we cannot check whether the caller is an async job
in the function qemuDomainObjEnterMonitorInternal(), and must instead
put the burden on the caller to tell us when an async command wants
to do a nested job.
Once the burden is on the caller, then only async monitor enters need
to worry about whether the VM is still running; for sync monitor enter,
the internal return is always 0, so lots of ignore_value can be dropped.
* src/qemu/THREADS.txt: Reflect new rules.
* src/qemu/qemu_domain.h (qemuDomainObjEnterMonitorAsync): New
prototype.
* src/qemu/qemu_process.h (qemuProcessStartCPUs)
(qemuProcessStopCPUs): Add parameter.
* src/qemu/qemu_migration.h (qemuMigrationToFile): Likewise.
(qemuMigrationWaitForCompletion): Make static.
* src/qemu/qemu_domain.c (qemuDomainObjEnterMonitorInternal): Add
parameter.
(qemuDomainObjEnterMonitorAsync): New function.
(qemuDomainObjEnterMonitor, qemuDomainObjEnterMonitorWithDriver):
Update callers.
* src/qemu/qemu_driver.c (qemuDomainSaveInternal)
(qemudDomainCoreDump, doCoreDump, processWatchdogEvent)
(qemudDomainSuspend, qemudDomainResume, qemuDomainSaveImageStartVM)
(qemuDomainSnapshotCreateActive, qemuDomainRevertToSnapshot):
Likewise.
* src/qemu/qemu_process.c (qemuProcessStopCPUs)
(qemuProcessFakeReboot, qemuProcessRecoverMigration)
(qemuProcessRecoverJob, qemuProcessStart): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationToFile)
(qemuMigrationWaitForCompletion, qemuMigrationUpdateJobStatus)
(qemuMigrationJobStart, qemuDomainMigrateGraphicsRelocate)
(doNativeMigrate, doTunnelMigrate, qemuMigrationPerformJob)
(qemuMigrationPerformPhase, qemuMigrationFinish)
(qemuMigrationConfirm): Likewise.
* src/qemu/qemu_hotplug.c: Drop unneeded ignore_value.
2011-07-28 23:18:24 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
enum qemuDomainAsyncJob asyncJob)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
return qemuDomainObjEnterMonitorInternal(driver, obj, asyncJob);
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
|
|
|
|
2011-10-05 17:31:54 +00:00
|
|
|
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
/*
|
|
|
|
* obj must be locked before calling
|
|
|
|
*
|
|
|
|
* To be called immediately before any QEMU agent API call.
|
|
|
|
* Must have already called qemuDomainObjBeginJob() and checked
|
|
|
|
* that the VM is still active.
|
|
|
|
*
|
|
|
|
* To be followed with qemuDomainObjExitAgent() once complete
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
qemuDomainObjEnterAgent(virDomainObjPtr obj)
|
2011-10-05 17:31:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
|
|
|
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Entering agent (agent=%p vm=%p name=%s)",
|
|
|
|
priv->agent, obj, obj->def->name);
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectLock(priv->agent);
|
2012-07-11 13:35:47 +00:00
|
|
|
virObjectRef(priv->agent);
|
2011-10-05 17:31:54 +00:00
|
|
|
ignore_value(virTimeMillisNow(&priv->agentStart));
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(obj);
|
2011-10-05 17:31:54 +00:00
|
|
|
}
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
|
|
|
|
/* obj must NOT be locked before calling
|
|
|
|
*
|
|
|
|
* Should be paired with an earlier qemuDomainObjEnterAgent() call
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
qemuDomainObjExitAgent(virDomainObjPtr obj)
|
2011-10-05 17:31:54 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
2012-07-11 13:35:47 +00:00
|
|
|
bool hasRefs;
|
2011-10-05 17:31:54 +00:00
|
|
|
|
2012-07-11 13:35:47 +00:00
|
|
|
hasRefs = virObjectUnref(priv->agent);
|
2011-10-05 17:31:54 +00:00
|
|
|
|
2012-07-11 13:35:47 +00:00
|
|
|
if (hasRefs)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(priv->agent);
|
2011-10-05 17:31:54 +00:00
|
|
|
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectLock(obj);
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Exited agent (agent=%p vm=%p name=%s)",
|
|
|
|
priv->agent, obj, obj->def->name);
|
2011-10-05 17:31:54 +00:00
|
|
|
|
|
|
|
priv->agentStart = 0;
|
2012-07-11 13:35:47 +00:00
|
|
|
if (!hasRefs)
|
2011-10-05 17:31:54 +00:00
|
|
|
priv->agent = NULL;
|
|
|
|
}
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
void qemuDomainObjEnterRemote(virDomainObjPtr obj)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Entering remote (vm=%p name=%s)",
|
|
|
|
obj, obj->def->name);
|
2012-07-11 13:35:46 +00:00
|
|
|
virObjectRef(obj);
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(obj);
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
void qemuDomainObjExitRemote(virDomainObjPtr obj)
|
2010-12-16 16:12:02 +00:00
|
|
|
{
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectLock(obj);
|
2013-10-31 11:27:10 +00:00
|
|
|
VIR_DEBUG("Exited remote (vm=%p name=%s)",
|
|
|
|
obj, obj->def->name);
|
2012-07-11 13:35:46 +00:00
|
|
|
virObjectUnref(obj);
|
2010-12-16 16:12:02 +00:00
|
|
|
}
|
2011-01-31 10:47:03 +00:00
|
|
|
|
|
|
|
|
2013-06-11 13:03:17 +00:00
|
|
|
virDomainDefPtr
|
|
|
|
qemuDomainDefCopy(virQEMUDriverPtr driver,
|
|
|
|
virDomainDefPtr src,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
virDomainDefPtr ret = NULL;
|
|
|
|
virCapsPtr caps = NULL;
|
2013-09-03 11:36:22 +00:00
|
|
|
char *xml = NULL;
|
2013-06-11 13:03:17 +00:00
|
|
|
|
|
|
|
if (qemuDomainDefFormatBuf(driver, src, flags, &buf) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
xml = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(ret = virDomainDefParseString(xml, caps, driver->xmlopt,
|
|
|
|
QEMU_EXPECTED_VIRT_TYPES,
|
|
|
|
VIR_DOMAIN_XML_INACTIVE)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
|
|
|
virObjectUnref(caps);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-05-04 19:00:13 +00:00
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainDefFormatBuf(virQEMUDriverPtr driver,
|
2012-05-04 19:00:13 +00:00
|
|
|
virDomainDefPtr def,
|
|
|
|
unsigned int flags,
|
|
|
|
virBuffer *buf)
|
2011-01-31 10:47:03 +00:00
|
|
|
{
|
2012-05-04 19:00:13 +00:00
|
|
|
int ret = -1;
|
2011-01-31 10:47:03 +00:00
|
|
|
virCPUDefPtr cpu = NULL;
|
2011-12-19 14:41:16 +00:00
|
|
|
virCPUDefPtr def_cpu = def->cpu;
|
2012-05-04 19:23:17 +00:00
|
|
|
virDomainControllerDefPtr *controllers = NULL;
|
|
|
|
int ncontrollers = 0;
|
2013-02-01 17:04:15 +00:00
|
|
|
virCapsPtr caps = NULL;
|
|
|
|
|
|
|
|
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
|
|
|
goto cleanup;
|
2011-01-31 10:47:03 +00:00
|
|
|
|
|
|
|
/* Update guest CPU requirements according to host CPU */
|
2011-12-19 14:41:16 +00:00
|
|
|
if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) &&
|
|
|
|
def_cpu &&
|
|
|
|
(def_cpu->mode != VIR_CPU_MODE_CUSTOM || def_cpu->model)) {
|
2013-02-01 17:04:15 +00:00
|
|
|
if (!caps->host.cpu ||
|
|
|
|
!caps->host.cpu->model) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot get host CPU capabilities"));
|
2011-01-31 10:47:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-12-19 14:41:16 +00:00
|
|
|
if (!(cpu = virCPUDefCopy(def_cpu)) ||
|
2013-02-01 17:04:15 +00:00
|
|
|
cpuUpdate(cpu, caps->host.cpu) < 0)
|
2011-01-31 10:47:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
def->cpu = cpu;
|
|
|
|
}
|
|
|
|
|
2012-10-08 09:58:05 +00:00
|
|
|
if ((flags & VIR_DOMAIN_XML_MIGRATABLE)) {
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-04-25 17:22:39 +00:00
|
|
|
int toremove = 0;
|
2013-04-22 12:16:13 +00:00
|
|
|
virDomainControllerDefPtr usb = NULL, pci = NULL;
|
2012-05-04 19:23:17 +00:00
|
|
|
|
|
|
|
/* If only the default USB controller is present, we can remove it
|
|
|
|
* and make the XML compatible with older versions of libvirt which
|
|
|
|
* didn't support USB controllers in the XML but always added the
|
|
|
|
* default one to qemu anyway.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
|
|
|
|
if (usb) {
|
|
|
|
usb = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
usb = def->controllers[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (usb && usb->idx == 0 && usb->model == -1) {
|
|
|
|
VIR_DEBUG("Removing default USB controller from domain '%s'"
|
|
|
|
" for migration compatibility", def->name);
|
2013-04-25 17:22:39 +00:00
|
|
|
toremove++;
|
2013-04-22 12:16:13 +00:00
|
|
|
} else {
|
|
|
|
usb = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove the default PCI controller if there is only one present
|
|
|
|
* and its model is pci-root */
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
|
|
|
|
if (pci) {
|
|
|
|
pci = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pci = def->controllers[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pci && pci->idx == 0 &&
|
|
|
|
pci->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) {
|
2013-07-10 19:19:32 +00:00
|
|
|
VIR_DEBUG("Removing default pci-root from domain '%s'"
|
2013-04-22 12:16:13 +00:00
|
|
|
" for migration compatibility", def->name);
|
2013-04-25 17:22:39 +00:00
|
|
|
toremove++;
|
2013-04-22 12:16:13 +00:00
|
|
|
} else {
|
|
|
|
pci = NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-25 17:22:39 +00:00
|
|
|
if (toremove) {
|
2012-05-04 19:23:17 +00:00
|
|
|
controllers = def->controllers;
|
|
|
|
ncontrollers = def->ncontrollers;
|
2013-04-25 17:22:39 +00:00
|
|
|
if (VIR_ALLOC_N(def->controllers, ncontrollers - toremove) < 0) {
|
2012-05-04 19:23:17 +00:00
|
|
|
controllers = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->ncontrollers = 0;
|
|
|
|
for (i = 0; i < ncontrollers; i++) {
|
2013-04-22 12:16:13 +00:00
|
|
|
if (controllers[i] != usb && controllers[i] != pci)
|
2012-05-04 19:23:17 +00:00
|
|
|
def->controllers[def->ncontrollers++] = controllers[i];
|
|
|
|
}
|
|
|
|
}
|
2013-04-22 12:16:13 +00:00
|
|
|
|
|
|
|
|
2012-05-04 19:23:17 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 19:00:13 +00:00
|
|
|
ret = virDomainDefFormatInternal(def, flags, buf);
|
2011-01-31 10:47:03 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
def->cpu = def_cpu;
|
|
|
|
virCPUDefFree(cpu);
|
2012-05-04 19:23:17 +00:00
|
|
|
if (controllers) {
|
|
|
|
VIR_FREE(def->controllers);
|
|
|
|
def->controllers = controllers;
|
|
|
|
def->ncontrollers = ncontrollers;
|
|
|
|
}
|
2013-02-01 17:04:15 +00:00
|
|
|
virObjectUnref(caps);
|
2011-01-31 10:47:03 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2011-05-04 10:59:20 +00:00
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
char *qemuDomainDefFormatXML(virQEMUDriverPtr driver,
|
2012-05-04 19:00:13 +00:00
|
|
|
virDomainDefPtr def,
|
2012-10-08 09:58:05 +00:00
|
|
|
unsigned int flags)
|
2012-05-04 19:00:13 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2012-10-08 09:58:05 +00:00
|
|
|
if (qemuDomainDefFormatBuf(driver, def, flags, &buf) < 0) {
|
2012-05-04 19:00:13 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virReportOOMError();
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
char *qemuDomainFormatXML(virQEMUDriverPtr driver,
|
2011-05-27 10:30:26 +00:00
|
|
|
virDomainObjPtr vm,
|
2012-10-08 09:58:05 +00:00
|
|
|
unsigned int flags)
|
2011-05-27 10:30:26 +00:00
|
|
|
{
|
|
|
|
virDomainDefPtr def;
|
|
|
|
|
|
|
|
if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef)
|
|
|
|
def = vm->newDef;
|
|
|
|
else
|
|
|
|
def = vm->def;
|
|
|
|
|
2012-10-08 09:58:05 +00:00
|
|
|
return qemuDomainDefFormatXML(driver, def, flags);
|
2011-05-27 10:30:26 +00:00
|
|
|
}
|
|
|
|
|
2012-03-09 15:42:46 +00:00
|
|
|
char *
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainDefFormatLive(virQEMUDriverPtr driver,
|
2012-03-09 15:42:46 +00:00
|
|
|
virDomainDefPtr def,
|
2012-05-04 19:23:17 +00:00
|
|
|
bool inactive,
|
|
|
|
bool compatible)
|
2012-03-09 15:42:46 +00:00
|
|
|
{
|
|
|
|
unsigned int flags = QEMU_DOMAIN_FORMAT_LIVE_FLAGS;
|
|
|
|
|
|
|
|
if (inactive)
|
|
|
|
flags |= VIR_DOMAIN_XML_INACTIVE;
|
2012-10-08 09:58:05 +00:00
|
|
|
if (compatible)
|
|
|
|
flags |= VIR_DOMAIN_XML_MIGRATABLE;
|
2012-03-09 15:42:46 +00:00
|
|
|
|
2012-10-08 09:58:05 +00:00
|
|
|
return qemuDomainDefFormatXML(driver, def, flags);
|
2012-03-09 15:42:46 +00:00
|
|
|
}
|
|
|
|
|
2011-05-27 10:30:26 +00:00
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainObjTaint(virQEMUDriverPtr driver,
|
2011-05-04 10:59:20 +00:00
|
|
|
virDomainObjPtr obj,
|
2011-05-05 11:48:07 +00:00
|
|
|
enum virDomainTaintFlags taint,
|
|
|
|
int logFD)
|
2011-05-04 10:59:20 +00:00
|
|
|
{
|
2011-05-05 11:48:07 +00:00
|
|
|
virErrorPtr orig_err = NULL;
|
|
|
|
|
2011-05-04 10:59:20 +00:00
|
|
|
if (virDomainObjTaint(obj, taint)) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
|
|
|
|
|
|
VIR_WARN("Domain id=%d name='%s' uuid=%s is tainted: %s",
|
|
|
|
obj->def->id,
|
|
|
|
obj->def->name,
|
|
|
|
uuidstr,
|
|
|
|
virDomainTaintTypeToString(taint));
|
2011-05-05 11:48:07 +00:00
|
|
|
|
|
|
|
/* We don't care about errors logging taint info, so
|
|
|
|
* preserve original error, and clear any error that
|
|
|
|
* is raised */
|
|
|
|
orig_err = virSaveLastError();
|
|
|
|
if (qemuDomainAppendLog(driver, obj, logFD,
|
|
|
|
"Domain id=%d is tainted: %s\n",
|
|
|
|
obj->def->id,
|
|
|
|
virDomainTaintTypeToString(taint)) < 0)
|
|
|
|
virResetLastError();
|
|
|
|
if (orig_err) {
|
|
|
|
virSetError(orig_err);
|
|
|
|
virFreeError(orig_err);
|
|
|
|
}
|
2011-05-04 10:59:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainObjCheckTaint(virQEMUDriverPtr driver,
|
2011-05-05 11:48:07 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
int logFD)
|
2011-05-04 10:59:20 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2014-02-04 15:42:13 +00:00
|
|
|
qemuDomainObjPrivatePtr priv = obj->privateData;
|
2011-05-04 10:59:20 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (cfg->privileged &&
|
|
|
|
(!cfg->clearEmulatorCapabilities ||
|
|
|
|
cfg->user == 0 ||
|
|
|
|
cfg->group == 0))
|
2011-05-05 11:48:07 +00:00
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, logFD);
|
2011-05-04 10:59:20 +00:00
|
|
|
|
2014-02-04 15:42:13 +00:00
|
|
|
if (priv->hookRun)
|
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HOOK, logFD);
|
|
|
|
|
2011-05-04 10:59:20 +00:00
|
|
|
if (obj->def->namespaceData) {
|
|
|
|
qemuDomainCmdlineDefPtr qemucmd = obj->def->namespaceData;
|
|
|
|
if (qemucmd->num_args || qemucmd->num_env)
|
2011-05-05 11:48:07 +00:00
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_CUSTOM_ARGV, logFD);
|
2011-05-04 10:59:20 +00:00
|
|
|
}
|
|
|
|
|
2011-08-18 10:56:56 +00:00
|
|
|
if (obj->def->cpu && obj->def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
|
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HOST_CPU, logFD);
|
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < obj->def->ndisks; i++)
|
2011-05-05 11:48:07 +00:00
|
|
|
qemuDomainObjCheckDiskTaint(driver, obj, obj->def->disks[i], logFD);
|
2011-05-04 10:59:20 +00:00
|
|
|
|
2013-05-21 07:21:20 +00:00
|
|
|
for (i = 0; i < obj->def->nnets; i++)
|
2011-05-05 11:48:07 +00:00
|
|
|
qemuDomainObjCheckNetTaint(driver, obj, obj->def->nets[i], logFD);
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
virObjectUnref(cfg);
|
2011-05-04 10:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainObjCheckDiskTaint(virQEMUDriverPtr driver,
|
2011-05-04 10:59:20 +00:00
|
|
|
virDomainObjPtr obj,
|
2011-05-05 11:48:07 +00:00
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
int logFD)
|
2011-05-04 10:59:20 +00:00
|
|
|
{
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
|
|
2012-10-15 21:47:42 +00:00
|
|
|
if ((!disk->format || disk->format == VIR_STORAGE_FILE_AUTO) &&
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->allowDiskFormatProbing)
|
2011-05-05 11:48:07 +00:00
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_DISK_PROBING, logFD);
|
2012-01-31 04:52:00 +00:00
|
|
|
|
2012-02-01 00:54:08 +00:00
|
|
|
if (disk->rawio == 1)
|
2012-01-31 04:52:00 +00:00
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HIGH_PRIVILEGES, logFD);
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
virObjectUnref(cfg);
|
2011-05-04 10:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDomainObjCheckNetTaint(virQEMUDriverPtr driver,
|
2011-05-04 10:59:20 +00:00
|
|
|
virDomainObjPtr obj,
|
2011-05-05 11:48:07 +00:00
|
|
|
virDomainNetDefPtr net,
|
|
|
|
int logFD)
|
2011-05-04 10:59:20 +00:00
|
|
|
{
|
config: report error when script given for inappropriate interface type
This fixes https://bugzilla.redhat.com/show_bug.cgi?id=638633
Although scripts are not used by interfaces of type other than
"ethernet" in qemu, due to the fact that the parser stores the script
name in a union that is only valid when type is ethernet or bridge,
there is no way for anyone except the parser itself to catch the
problem of specifying an interface script for an inappropriate
interface type (by the time the parsed data gets back to the code that
called the parser, all evidence that a script was specified is
forgotten).
Since the parser itself should be agnostic to which type of interface
allows scripts (an example of why: a script specified for an interface
of type bridge is valid for xen domains, but not for qemu domains),
the solution here is to move the script out of the union(s) in the
DomainNetDef, always populate it when specified (regardless of
interface type), and let the driver decide whether or not it is
appropriate.
Currently the qemu, xen, libxml, and uml drivers recognize the script
parameter and do something with it (the uml driver only to report that
it isn't supported). Those drivers have been updated to log a
CONFIG_UNSUPPORTED error when a script is specified for an interface
type that's inappropriate for that particular hypervisor.
(NB: There was earlier discussion of solving this problem by adding a
VALIDATE flag to all libvirt APIs that accept XML, which would cause
the XML to be validated against the RNG files. One statement during
that discussion was that the RNG shouldn't contain hypervisor-specific
things, though, and a proper solution to this problem would require
that (again, because a script for an interface of type "bridge" is
accepted by xen, but not by qemu).
2012-01-06 17:59:47 +00:00
|
|
|
/* script is only useful for NET_TYPE_ETHERNET (qemu) and
|
|
|
|
* NET_TYPE_BRIDGE (xen), but could be (incorrectly) specified for
|
|
|
|
* any interface type. In any case, it's adding user sauce into
|
|
|
|
* the soup, so it should taint the domain.
|
|
|
|
*/
|
|
|
|
if (net->script != NULL)
|
2011-05-05 11:48:07 +00:00
|
|
|
qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_SHELL_SCRIPTS, logFD);
|
2011-05-04 10:59:20 +00:00
|
|
|
}
|
2011-05-05 11:38:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
2013-01-10 21:03:14 +00:00
|
|
|
qemuDomainOpenLogHelper(virQEMUDriverConfigPtr cfg,
|
2011-05-05 11:38:04 +00:00
|
|
|
virDomainObjPtr vm,
|
2011-07-06 22:42:06 +00:00
|
|
|
int oflags,
|
2011-05-05 11:38:04 +00:00
|
|
|
mode_t mode)
|
|
|
|
{
|
|
|
|
char *logfile;
|
|
|
|
int fd = -1;
|
2012-09-21 09:37:53 +00:00
|
|
|
bool trunc = false;
|
2011-05-05 11:38:04 +00:00
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&logfile, "%s/%s.log", cfg->logDir, vm->def->name) < 0)
|
2011-05-05 11:38:04 +00:00
|
|
|
return -1;
|
|
|
|
|
2012-09-21 09:37:53 +00:00
|
|
|
/* To make SELinux happy we always need to open in append mode.
|
|
|
|
* So we fake O_TRUNC by calling ftruncate after open instead
|
|
|
|
*/
|
|
|
|
if (oflags & O_TRUNC) {
|
|
|
|
oflags &= ~O_TRUNC;
|
|
|
|
oflags |= O_APPEND;
|
|
|
|
trunc = true;
|
|
|
|
}
|
|
|
|
|
2011-07-06 22:42:06 +00:00
|
|
|
if ((fd = open(logfile, oflags, mode)) < 0) {
|
2011-05-05 11:38:04 +00:00
|
|
|
virReportSystemError(errno, _("failed to create logfile %s"),
|
|
|
|
logfile);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (virSetCloseExec(fd) < 0) {
|
|
|
|
virReportSystemError(errno, _("failed to set close-on-exec flag on %s"),
|
|
|
|
logfile);
|
2012-09-21 09:37:53 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (trunc &&
|
|
|
|
ftruncate(fd, 0) < 0) {
|
|
|
|
virReportSystemError(errno, _("failed to truncate %s"),
|
|
|
|
logfile);
|
2011-05-05 11:38:04 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(logfile);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainCreateLog(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
2011-07-06 22:42:06 +00:00
|
|
|
bool append)
|
2011-05-05 11:38:04 +00:00
|
|
|
{
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2011-07-06 22:42:06 +00:00
|
|
|
int oflags;
|
2013-01-10 21:03:14 +00:00
|
|
|
int ret;
|
2011-05-05 11:38:04 +00:00
|
|
|
|
2011-07-06 22:42:06 +00:00
|
|
|
oflags = O_CREAT | O_WRONLY;
|
2011-05-05 11:38:04 +00:00
|
|
|
/* Only logrotate files in /var/log, so only append if running privileged */
|
2013-01-10 21:03:14 +00:00
|
|
|
if (cfg->privileged || append)
|
2011-07-06 22:42:06 +00:00
|
|
|
oflags |= O_APPEND;
|
2011-05-05 11:38:04 +00:00
|
|
|
else
|
2011-07-06 22:42:06 +00:00
|
|
|
oflags |= O_TRUNC;
|
2011-05-05 11:38:04 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
ret = qemuDomainOpenLogHelper(cfg, vm, oflags, S_IRUSR | S_IWUSR);
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return ret;
|
2011-05-05 11:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainOpenLog(virQEMUDriverPtr driver, virDomainObjPtr vm, off_t pos)
|
2011-05-05 11:38:04 +00:00
|
|
|
{
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2011-05-05 11:38:04 +00:00
|
|
|
int fd;
|
|
|
|
off_t off;
|
|
|
|
int whence;
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
fd = qemuDomainOpenLogHelper(cfg, vm, O_RDONLY, 0);
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
if (fd < 0)
|
2011-05-05 11:38:04 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (pos < 0) {
|
|
|
|
off = 0;
|
|
|
|
whence = SEEK_END;
|
|
|
|
} else {
|
|
|
|
off = pos;
|
|
|
|
whence = SEEK_SET;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lseek(fd, off, whence) < 0) {
|
|
|
|
if (whence == SEEK_END)
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("unable to seek to end of log for %s"),
|
|
|
|
vm->def->name);
|
|
|
|
else
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("unable to seek to %lld from start for %s"),
|
|
|
|
(long long)off, vm->def->name);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
int qemuDomainAppendLog(virQEMUDriverPtr driver,
|
2011-05-05 11:40:50 +00:00
|
|
|
virDomainObjPtr obj,
|
|
|
|
int logFD,
|
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
int fd = logFD;
|
|
|
|
va_list argptr;
|
|
|
|
char *message = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
va_start(argptr, fmt);
|
|
|
|
|
|
|
|
if ((fd == -1) &&
|
|
|
|
(fd = qemuDomainCreateLog(driver, obj, true)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virVasprintf(&message, fmt, argptr) < 0)
|
2011-05-05 11:40:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
if (safewrite(fd, message, strlen(message)) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to write to domain logfile %s"),
|
|
|
|
obj->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
va_end(argptr);
|
|
|
|
|
|
|
|
if (fd != logFD)
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
|
2011-06-22 11:32:04 +00:00
|
|
|
VIR_FREE(message);
|
2011-05-05 11:40:50 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
/* Locate an appropriate 'qemu-img' binary. */
|
|
|
|
const char *
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuFindQemuImgBinary(virQEMUDriverPtr driver)
|
2011-09-21 19:08:51 +00:00
|
|
|
{
|
2013-01-23 12:19:15 +00:00
|
|
|
if (!driver->qemuImgBinary)
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("unable to find kvm-img or qemu-img"));
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
return driver->qemuImgBinary;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
|
|
|
|
virDomainSnapshotObjPtr snapshot,
|
|
|
|
char *snapshotDir)
|
|
|
|
{
|
|
|
|
char *newxml = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
char *snapDir = NULL;
|
|
|
|
char *snapFile = NULL;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
|
|
|
newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def,
|
2012-03-09 15:42:46 +00:00
|
|
|
QEMU_DOMAIN_FORMAT_LIVE_FLAGS, 1);
|
|
|
|
if (newxml == NULL)
|
2011-09-21 19:08:51 +00:00
|
|
|
return -1;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&snapDir, "%s/%s", snapshotDir, vm->def->name) < 0)
|
2011-09-21 19:08:51 +00:00
|
|
|
goto cleanup;
|
|
|
|
if (virFileMakePath(snapDir) < 0) {
|
|
|
|
virReportSystemError(errno, _("cannot create snapshot directory '%s'"),
|
|
|
|
snapDir);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&snapFile, "%s/%s.xml", snapDir, snapshot->def->name) < 0)
|
2011-09-21 19:08:51 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-10-29 12:15:55 +00:00
|
|
|
ret = virXMLSaveFile(snapFile, NULL, "snapshot-edit", newxml);
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(snapFile);
|
|
|
|
VIR_FREE(snapDir);
|
|
|
|
VIR_FREE(newxml);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The domain is expected to be locked and inactive. Return -1 on normal
|
|
|
|
* failure, 1 if we skipped a disk due to try_all. */
|
2012-03-17 15:54:44 +00:00
|
|
|
static int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainSnapshotForEachQcow2Raw(virQEMUDriverPtr driver,
|
2012-03-17 15:54:44 +00:00
|
|
|
virDomainDefPtr def,
|
|
|
|
const char *name,
|
|
|
|
const char *op,
|
|
|
|
bool try_all,
|
|
|
|
int ndisks)
|
2011-09-21 19:08:51 +00:00
|
|
|
{
|
|
|
|
const char *qemuimgarg[] = { NULL, "snapshot", NULL, NULL, NULL, NULL };
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-09-21 19:08:51 +00:00
|
|
|
bool skipped = false;
|
|
|
|
|
|
|
|
qemuimgarg[0] = qemuFindQemuImgBinary(driver);
|
|
|
|
if (qemuimgarg[0] == NULL) {
|
|
|
|
/* qemuFindQemuImgBinary set the error */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuimgarg[2] = op;
|
2012-03-17 15:54:44 +00:00
|
|
|
qemuimgarg[3] = name;
|
2011-09-21 19:08:51 +00:00
|
|
|
|
2012-03-17 15:54:44 +00:00
|
|
|
for (i = 0; i < ndisks; i++) {
|
2011-09-21 19:08:51 +00:00
|
|
|
/* FIXME: we also need to handle LVM here */
|
2011-10-04 23:13:48 +00:00
|
|
|
if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
2012-10-15 21:47:42 +00:00
|
|
|
if (def->disks[i]->format > 0 &&
|
|
|
|
def->disks[i]->format != VIR_STORAGE_FILE_QCOW2) {
|
2011-09-21 19:08:51 +00:00
|
|
|
if (try_all) {
|
|
|
|
/* Continue on even in the face of error, since other
|
|
|
|
* disks in this VM may have the same snapshot name.
|
|
|
|
*/
|
|
|
|
VIR_WARN("skipping snapshot action on %s",
|
2011-10-04 23:13:48 +00:00
|
|
|
def->disks[i]->dst);
|
2011-09-21 19:08:51 +00:00
|
|
|
skipped = true;
|
|
|
|
continue;
|
2012-03-17 15:54:44 +00:00
|
|
|
} else if (STREQ(op, "-c") && i) {
|
|
|
|
/* We must roll back partial creation by deleting
|
|
|
|
* all earlier snapshots. */
|
|
|
|
qemuDomainSnapshotForEachQcow2Raw(driver, def, name,
|
|
|
|
"-d", false, i);
|
2011-09-21 19:08:51 +00:00
|
|
|
}
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("Disk device '%s' does not support"
|
|
|
|
" snapshotting"),
|
|
|
|
def->disks[i]->dst);
|
2011-09-21 19:08:51 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-10-04 23:13:48 +00:00
|
|
|
qemuimgarg[4] = def->disks[i]->src;
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
if (virRun(qemuimgarg, NULL) < 0) {
|
|
|
|
if (try_all) {
|
|
|
|
VIR_WARN("skipping snapshot action on %s",
|
2011-10-04 23:13:48 +00:00
|
|
|
def->disks[i]->dst);
|
2011-09-21 19:08:51 +00:00
|
|
|
skipped = true;
|
|
|
|
continue;
|
2012-03-17 15:54:44 +00:00
|
|
|
} else if (STREQ(op, "-c") && i) {
|
|
|
|
/* We must roll back partial creation by deleting
|
|
|
|
* all earlier snapshots. */
|
|
|
|
qemuDomainSnapshotForEachQcow2Raw(driver, def, name,
|
|
|
|
"-d", false, i);
|
2011-09-21 19:08:51 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return skipped ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2012-03-17 15:54:44 +00:00
|
|
|
/* The domain is expected to be locked and inactive. Return -1 on normal
|
|
|
|
* failure, 1 if we skipped a disk due to try_all. */
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainSnapshotForEachQcow2(virQEMUDriverPtr driver,
|
2012-03-17 15:54:44 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainSnapshotObjPtr snap,
|
|
|
|
const char *op,
|
|
|
|
bool try_all)
|
|
|
|
{
|
|
|
|
/* Prefer action on the disks in use at the time the snapshot was
|
|
|
|
* created; but fall back to current definition if dealing with a
|
|
|
|
* snapshot created prior to libvirt 0.9.5. */
|
|
|
|
virDomainDefPtr def = snap->def->dom;
|
|
|
|
|
|
|
|
if (!def)
|
|
|
|
def = vm->def;
|
|
|
|
return qemuDomainSnapshotForEachQcow2Raw(driver, def, snap->def->name,
|
|
|
|
op, try_all, def->ndisks);
|
|
|
|
}
|
|
|
|
|
2011-09-21 19:08:51 +00:00
|
|
|
/* Discard one snapshot (or its metadata), without reparenting any children. */
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
|
2011-09-21 19:08:51 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainSnapshotObjPtr snap,
|
|
|
|
bool update_current,
|
|
|
|
bool metadata_only)
|
|
|
|
{
|
|
|
|
char *snapFile = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
qemuDomainObjPrivatePtr priv;
|
|
|
|
virDomainSnapshotObjPtr parentsnap = NULL;
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
if (!metadata_only) {
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
/* Ignore any skipped disks */
|
|
|
|
if (qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-d",
|
|
|
|
true) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
priv = vm->privateData;
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDomainObjEnterMonitor(driver, vm);
|
2011-09-21 19:08:51 +00:00
|
|
|
/* we continue on even in the face of error */
|
|
|
|
qemuMonitorDeleteSnapshot(priv->mon, snap->def->name);
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDomainObjExitMonitor(driver, vm);
|
2011-09-21 19:08:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&snapFile, "%s/%s/%s.xml", cfg->snapshotDir,
|
2013-07-04 10:14:12 +00:00
|
|
|
vm->def->name, snap->def->name) < 0)
|
2011-09-21 19:08:51 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (snap == vm->current_snapshot) {
|
|
|
|
if (update_current && snap->def->parent) {
|
snapshot: make virDomainSnapshotObjList opaque
We were failing to react to allocation failure when initializing
a snapshot object list. Changing things to store a pointer
instead of a complete object adds one more possible point of
allocation failure, but at the same time, will make it easier to
react to failure now, as well as making it easier for a future
patch to split all virDomainSnapshotPtr handling into a separate
file, as I continue to add even more snapshot code.
Luckily, there was only one client outside of domain_conf.c that
was actually peeking inside the object, and a new wrapper function
was easy.
* src/conf/domain_conf.h (_virDomainObj): Use a pointer.
(virDomainSnapshotObjListInit): Rename.
(virDomainSnapshotObjListFree, virDomainSnapshotForEach): New
declarations.
(_virDomainSnapshotObjList): Move definitions...
* src/conf/domain_conf.c: ...here.
(virDomainSnapshotObjListInit, virDomainSnapshotObjListDeinit):
Rename...
(virDomainSnapshotObjListNew, virDomainSnapshotObjListFree): ...to
these.
(virDomainSnapshotForEach): New function.
(virDomainObjDispose, virDomainListPopulate): Adjust callers.
* src/qemu/qemu_domain.c (qemuDomainSnapshotDiscard)
(qemuDomainSnapshotDiscardAllMetadata): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsAllowed): Likewise.
* src/qemu/qemu_driver.c (qemuDomainSnapshotLoad)
(qemuDomainUndefineFlags, qemuDomainSnapshotCreateXML)
(qemuDomainSnapshotListNames, qemuDomainSnapshotNum)
(qemuDomainListAllSnapshots)
(qemuDomainSnapshotListChildrenNames)
(qemuDomainSnapshotNumChildren)
(qemuDomainSnapshotListAllChildren)
(qemuDomainSnapshotLookupByName, qemuDomainSnapshotGetParent)
(qemuDomainSnapshotGetXMLDesc, qemuDomainSnapshotIsCurrent)
(qemuDomainSnapshotHasMetadata, qemuDomainRevertToSnapshot)
(qemuDomainSnapshotDelete): Likewise.
* src/libvirt_private.syms (domain_conf.h): Export new function.
2012-08-14 06:22:39 +00:00
|
|
|
parentsnap = virDomainSnapshotFindByName(vm->snapshots,
|
2011-09-21 19:08:51 +00:00
|
|
|
snap->def->parent);
|
|
|
|
if (!parentsnap) {
|
|
|
|
VIR_WARN("missing parent snapshot matching name '%s'",
|
|
|
|
snap->def->parent);
|
|
|
|
} else {
|
|
|
|
parentsnap->def->current = true;
|
|
|
|
if (qemuDomainSnapshotWriteMetadata(vm, parentsnap,
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->snapshotDir) < 0) {
|
2011-09-21 19:08:51 +00:00
|
|
|
VIR_WARN("failed to set parent snapshot '%s' as current",
|
|
|
|
snap->def->parent);
|
|
|
|
parentsnap->def->current = false;
|
|
|
|
parentsnap = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vm->current_snapshot = parentsnap;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlink(snapFile) < 0)
|
|
|
|
VIR_WARN("Failed to unlink %s", snapFile);
|
snapshot: make virDomainSnapshotObjList opaque
We were failing to react to allocation failure when initializing
a snapshot object list. Changing things to store a pointer
instead of a complete object adds one more possible point of
allocation failure, but at the same time, will make it easier to
react to failure now, as well as making it easier for a future
patch to split all virDomainSnapshotPtr handling into a separate
file, as I continue to add even more snapshot code.
Luckily, there was only one client outside of domain_conf.c that
was actually peeking inside the object, and a new wrapper function
was easy.
* src/conf/domain_conf.h (_virDomainObj): Use a pointer.
(virDomainSnapshotObjListInit): Rename.
(virDomainSnapshotObjListFree, virDomainSnapshotForEach): New
declarations.
(_virDomainSnapshotObjList): Move definitions...
* src/conf/domain_conf.c: ...here.
(virDomainSnapshotObjListInit, virDomainSnapshotObjListDeinit):
Rename...
(virDomainSnapshotObjListNew, virDomainSnapshotObjListFree): ...to
these.
(virDomainSnapshotForEach): New function.
(virDomainObjDispose, virDomainListPopulate): Adjust callers.
* src/qemu/qemu_domain.c (qemuDomainSnapshotDiscard)
(qemuDomainSnapshotDiscardAllMetadata): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsAllowed): Likewise.
* src/qemu/qemu_driver.c (qemuDomainSnapshotLoad)
(qemuDomainUndefineFlags, qemuDomainSnapshotCreateXML)
(qemuDomainSnapshotListNames, qemuDomainSnapshotNum)
(qemuDomainListAllSnapshots)
(qemuDomainSnapshotListChildrenNames)
(qemuDomainSnapshotNumChildren)
(qemuDomainSnapshotListAllChildren)
(qemuDomainSnapshotLookupByName, qemuDomainSnapshotGetParent)
(qemuDomainSnapshotGetXMLDesc, qemuDomainSnapshotIsCurrent)
(qemuDomainSnapshotHasMetadata, qemuDomainRevertToSnapshot)
(qemuDomainSnapshotDelete): Likewise.
* src/libvirt_private.syms (domain_conf.h): Export new function.
2012-08-14 06:22:39 +00:00
|
|
|
virDomainSnapshotObjListRemove(vm->snapshots, snap);
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(snapFile);
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2011-09-21 19:08:51 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Hash iterator callback to discard multiple snapshots. */
|
|
|
|
void qemuDomainSnapshotDiscardAll(void *payload,
|
|
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr snap = payload;
|
2012-11-28 17:29:44 +00:00
|
|
|
virQEMUSnapRemovePtr curr = data;
|
2011-09-21 19:08:51 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (snap->def->current)
|
|
|
|
curr->current = true;
|
|
|
|
err = qemuDomainSnapshotDiscard(curr->driver, curr->vm, snap, false,
|
|
|
|
curr->metadata_only);
|
|
|
|
if (err && !curr->err)
|
|
|
|
curr->err = err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainSnapshotDiscardAllMetadata(virQEMUDriverPtr driver,
|
2011-09-21 19:08:51 +00:00
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
2012-11-28 17:29:44 +00:00
|
|
|
virQEMUSnapRemove rem;
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
rem.driver = driver;
|
|
|
|
rem.vm = vm;
|
|
|
|
rem.metadata_only = true;
|
|
|
|
rem.err = 0;
|
snapshot: make virDomainSnapshotObjList opaque
We were failing to react to allocation failure when initializing
a snapshot object list. Changing things to store a pointer
instead of a complete object adds one more possible point of
allocation failure, but at the same time, will make it easier to
react to failure now, as well as making it easier for a future
patch to split all virDomainSnapshotPtr handling into a separate
file, as I continue to add even more snapshot code.
Luckily, there was only one client outside of domain_conf.c that
was actually peeking inside the object, and a new wrapper function
was easy.
* src/conf/domain_conf.h (_virDomainObj): Use a pointer.
(virDomainSnapshotObjListInit): Rename.
(virDomainSnapshotObjListFree, virDomainSnapshotForEach): New
declarations.
(_virDomainSnapshotObjList): Move definitions...
* src/conf/domain_conf.c: ...here.
(virDomainSnapshotObjListInit, virDomainSnapshotObjListDeinit):
Rename...
(virDomainSnapshotObjListNew, virDomainSnapshotObjListFree): ...to
these.
(virDomainSnapshotForEach): New function.
(virDomainObjDispose, virDomainListPopulate): Adjust callers.
* src/qemu/qemu_domain.c (qemuDomainSnapshotDiscard)
(qemuDomainSnapshotDiscardAllMetadata): Likewise.
* src/qemu/qemu_migration.c (qemuMigrationIsAllowed): Likewise.
* src/qemu/qemu_driver.c (qemuDomainSnapshotLoad)
(qemuDomainUndefineFlags, qemuDomainSnapshotCreateXML)
(qemuDomainSnapshotListNames, qemuDomainSnapshotNum)
(qemuDomainListAllSnapshots)
(qemuDomainSnapshotListChildrenNames)
(qemuDomainSnapshotNumChildren)
(qemuDomainSnapshotListAllChildren)
(qemuDomainSnapshotLookupByName, qemuDomainSnapshotGetParent)
(qemuDomainSnapshotGetXMLDesc, qemuDomainSnapshotIsCurrent)
(qemuDomainSnapshotHasMetadata, qemuDomainRevertToSnapshot)
(qemuDomainSnapshotDelete): Likewise.
* src/libvirt_private.syms (domain_conf.h): Export new function.
2012-08-14 06:22:39 +00:00
|
|
|
virDomainSnapshotForEach(vm->snapshots, qemuDomainSnapshotDiscardAll,
|
|
|
|
&rem);
|
2011-09-21 19:08:51 +00:00
|
|
|
|
|
|
|
return rem.err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-06 18:17:20 +00:00
|
|
|
* The caller must hold a lock the vm and there must
|
2011-09-21 19:08:51 +00:00
|
|
|
* be no remaining references to vm.
|
|
|
|
*/
|
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainRemoveInactive(virQEMUDriverPtr driver,
|
2011-09-21 19:08:51 +00:00
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
2011-09-21 22:08:42 +00:00
|
|
|
char *snapDir;
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2011-09-21 22:08:42 +00:00
|
|
|
|
2011-09-21 19:08:51 +00:00
|
|
|
/* Remove any snapshot metadata prior to removing the domain */
|
|
|
|
if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0) {
|
|
|
|
VIR_WARN("unable to remove all snapshots for domain %s",
|
|
|
|
vm->def->name);
|
|
|
|
}
|
2013-01-10 21:03:14 +00:00
|
|
|
else if (virAsprintf(&snapDir, "%s/%s", cfg->snapshotDir,
|
2011-09-21 22:08:42 +00:00
|
|
|
vm->def->name) < 0) {
|
|
|
|
VIR_WARN("unable to remove snapshot directory %s/%s",
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->snapshotDir, vm->def->name);
|
2011-09-21 22:08:42 +00:00
|
|
|
} else {
|
|
|
|
if (rmdir(snapDir) < 0 && errno != ENOENT)
|
|
|
|
VIR_WARN("unable to remove snapshot directory %s", snapDir);
|
|
|
|
VIR_FREE(snapDir);
|
|
|
|
}
|
2013-01-11 16:04:47 +00:00
|
|
|
virDomainObjListRemove(driver->domains, vm);
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2011-09-21 19:08:51 +00:00
|
|
|
}
|
2011-09-28 10:10:13 +00:00
|
|
|
|
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainSetFakeReboot(virQEMUDriverPtr driver,
|
2011-09-28 10:10:13 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
bool value)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2011-09-28 10:10:13 +00:00
|
|
|
|
|
|
|
if (priv->fakeReboot == value)
|
2013-02-01 17:04:15 +00:00
|
|
|
goto cleanup;
|
2011-09-28 10:10:13 +00:00
|
|
|
|
|
|
|
priv->fakeReboot = value;
|
|
|
|
|
2013-03-31 18:03:42 +00:00
|
|
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
2011-09-28 10:10:13 +00:00
|
|
|
VIR_WARN("Failed to save status on vm %s", vm->def->name);
|
2013-01-10 21:03:14 +00:00
|
|
|
|
2013-02-01 17:04:15 +00:00
|
|
|
cleanup:
|
2013-01-10 21:03:14 +00:00
|
|
|
virObjectUnref(cfg);
|
2011-09-28 10:10:13 +00:00
|
|
|
}
|
2011-10-18 08:51:06 +00:00
|
|
|
|
2013-08-07 07:11:15 +00:00
|
|
|
static int
|
|
|
|
qemuDomainCheckRemoveOptionalDisk(virQEMUDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
2013-11-22 14:38:05 +00:00
|
|
|
virObjectEventPtr event = NULL;
|
2013-08-07 07:11:15 +00:00
|
|
|
virDomainDiskDefPtr del_disk = NULL;
|
|
|
|
|
|
|
|
virUUIDFormat(vm->def->uuid, uuid);
|
|
|
|
|
|
|
|
VIR_DEBUG("Dropping disk '%s' on domain '%s' (UUID '%s') "
|
|
|
|
"due to inaccessible source '%s'",
|
|
|
|
disk->dst, vm->def->name, uuid, disk->src);
|
|
|
|
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ||
|
|
|
|
disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
|
|
|
|
|
|
|
|
event = virDomainEventDiskChangeNewFromObj(vm, disk->src, NULL,
|
|
|
|
disk->info.alias,
|
|
|
|
VIR_DOMAIN_EVENT_DISK_CHANGE_MISSING_ON_START);
|
|
|
|
VIR_FREE(disk->src);
|
|
|
|
} else {
|
|
|
|
event = virDomainEventDiskChangeNewFromObj(vm, disk->src, NULL,
|
|
|
|
disk->info.alias,
|
|
|
|
VIR_DOMAIN_EVENT_DISK_DROP_MISSING_ON_START);
|
|
|
|
|
|
|
|
if (!(del_disk = virDomainDiskRemoveByName(vm->def, disk->src))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("no source device %s"), disk->src);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virDomainDiskDefFree(del_disk);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event)
|
|
|
|
qemuDomainEventQueue(driver, event);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-26 12:37:21 +00:00
|
|
|
static int
|
|
|
|
qemuDomainCheckDiskStartupPolicy(virQEMUDriverPtr driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
bool cold_boot)
|
|
|
|
{
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
int startupPolicy = disk->startupPolicy;
|
|
|
|
|
|
|
|
virUUIDFormat(vm->def->uuid, uuid);
|
|
|
|
|
|
|
|
switch ((enum virDomainStartupPolicy) startupPolicy) {
|
|
|
|
case VIR_DOMAIN_STARTUP_POLICY_OPTIONAL:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_STARTUP_POLICY_MANDATORY:
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_STARTUP_POLICY_REQUISITE:
|
2013-07-31 07:55:05 +00:00
|
|
|
if (cold_boot)
|
2013-07-26 12:37:21 +00:00
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_STARTUP_POLICY_DEFAULT:
|
|
|
|
case VIR_DOMAIN_STARTUP_POLICY_LAST:
|
|
|
|
/* this should never happen */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-07 07:11:15 +00:00
|
|
|
if (qemuDomainCheckRemoveOptionalDisk(driver, vm, disk) < 0)
|
|
|
|
goto error;
|
2013-07-26 12:37:21 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-10-18 08:51:06 +00:00
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainCheckDiskPresence(virQEMUDriverPtr driver,
|
2011-10-18 08:51:06 +00:00
|
|
|
virDomainObjPtr vm,
|
2012-03-14 10:08:52 +00:00
|
|
|
bool cold_boot)
|
2011-10-18 08:51:06 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-10-18 08:51:06 +00:00
|
|
|
virDomainDiskDefPtr disk;
|
|
|
|
|
2013-07-31 07:55:05 +00:00
|
|
|
VIR_DEBUG("Checking for disk presence");
|
2013-08-07 07:11:15 +00:00
|
|
|
for (i = vm->def->ndisks; i > 0; i--) {
|
|
|
|
disk = vm->def->disks[i - 1];
|
2011-10-18 08:51:06 +00:00
|
|
|
|
2013-07-31 07:55:05 +00:00
|
|
|
if (!disk->src)
|
2011-10-18 08:51:06 +00:00
|
|
|
continue;
|
|
|
|
|
2014-02-07 17:42:27 +00:00
|
|
|
if (qemuDomainDetermineDiskChain(driver, vm, disk, false) >= 0 &&
|
2013-07-31 07:55:05 +00:00
|
|
|
qemuDiskChainCheckBroken(disk) >= 0)
|
2011-10-18 08:51:06 +00:00
|
|
|
continue;
|
2013-07-31 07:55:05 +00:00
|
|
|
|
2013-08-07 07:11:15 +00:00
|
|
|
if (disk->startupPolicy &&
|
|
|
|
qemuDomainCheckDiskStartupPolicy(driver, vm, disk,
|
|
|
|
cold_boot) >= 0) {
|
|
|
|
virResetLastError();
|
|
|
|
continue;
|
2011-10-18 08:51:06 +00:00
|
|
|
}
|
|
|
|
|
2013-07-31 07:55:05 +00:00
|
|
|
goto error;
|
2011-10-18 08:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2013-07-31 07:55:05 +00:00
|
|
|
error:
|
2011-10-18 08:51:06 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2012-03-16 06:52:26 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The vm must be locked when any of the following cleanup functions is
|
|
|
|
* called.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemuDomainCleanupAdd(virDomainObjPtr vm,
|
|
|
|
qemuDomainCleanupCallback cb)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-03-16 06:52:26 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("vm=%s, cb=%p", vm->def->name, cb);
|
|
|
|
|
|
|
|
for (i = 0; i < priv->ncleanupCallbacks; i++) {
|
|
|
|
if (priv->cleanupCallbacks[i] == cb)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_RESIZE_N(priv->cleanupCallbacks,
|
|
|
|
priv->ncleanupCallbacks_max,
|
2013-07-04 10:14:12 +00:00
|
|
|
priv->ncleanupCallbacks, 1) < 0)
|
2012-03-16 06:52:26 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
priv->cleanupCallbacks[priv->ncleanupCallbacks++] = cb;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
qemuDomainCleanupRemove(virDomainObjPtr vm,
|
|
|
|
qemuDomainCleanupCallback cb)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-03-16 06:52:26 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("vm=%s, cb=%p", vm->def->name, cb);
|
|
|
|
|
|
|
|
for (i = 0; i < priv->ncleanupCallbacks; i++) {
|
2013-10-15 17:07:42 +00:00
|
|
|
if (priv->cleanupCallbacks[i] == cb)
|
|
|
|
VIR_DELETE_ELEMENT_INPLACE(priv->cleanupCallbacks,
|
|
|
|
i, priv->ncleanupCallbacks);
|
2012-03-16 06:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_SHRINK_N(priv->cleanupCallbacks,
|
|
|
|
priv->ncleanupCallbacks_max,
|
|
|
|
priv->ncleanupCallbacks_max - priv->ncleanupCallbacks);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainCleanupRun(virQEMUDriverPtr driver,
|
2012-03-16 06:52:26 +00:00
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-03-16 06:52:26 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("driver=%p, vm=%s", driver, vm->def->name);
|
|
|
|
|
|
|
|
/* run cleanup callbacks in reverse order */
|
Convert 'int i' to 'size_t i' in src/qemu files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
for (i = 0; i < priv->ncleanupCallbacks; i++) {
|
|
|
|
if (priv->cleanupCallbacks[priv->ncleanupCallbacks - (i + 1)])
|
2012-03-16 06:52:26 +00:00
|
|
|
priv->cleanupCallbacks[i](driver, vm);
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(priv->cleanupCallbacks);
|
|
|
|
priv->ncleanupCallbacks = 0;
|
|
|
|
priv->ncleanupCallbacks_max = 0;
|
|
|
|
}
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
|
2013-07-29 12:51:15 +00:00
|
|
|
int
|
|
|
|
qemuDiskChainCheckBroken(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
char *brokenFile = NULL;
|
|
|
|
|
|
|
|
if (!disk->src || !disk->backingChain)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (virStorageFileChainGetBroken(disk->backingChain, &brokenFile) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (brokenFile) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Backing file '%s' of image '%s' is missing."),
|
|
|
|
brokenFile, disk->src);
|
|
|
|
VIR_FREE(brokenFile);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-07 17:42:27 +00:00
|
|
|
static void
|
|
|
|
qemuDomainGetImageIds(virQEMUDriverConfigPtr cfg,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
uid_t *uid, gid_t *gid)
|
|
|
|
{
|
|
|
|
virSecurityLabelDefPtr vmlabel;
|
|
|
|
virSecurityDeviceLabelDefPtr disklabel;
|
|
|
|
|
|
|
|
if (uid)
|
|
|
|
*uid = -1;
|
|
|
|
if (gid)
|
|
|
|
*gid = -1;
|
|
|
|
|
|
|
|
if (cfg) {
|
|
|
|
if (uid)
|
|
|
|
*uid = cfg->user;
|
|
|
|
|
|
|
|
if (gid)
|
|
|
|
*gid = cfg->group;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm && (vmlabel = virDomainDefGetSecurityLabelDef(vm->def, "dac")))
|
|
|
|
virParseOwnershipIds(vmlabel->label, uid, gid);
|
|
|
|
|
|
|
|
if ((disklabel = virDomainDiskDefGetSecurityLabelDef(disk, "dac")))
|
|
|
|
virParseOwnershipIds(disklabel->label, uid, gid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDomainDetermineDiskChain(virQEMUDriverPtr driver,
|
2014-02-07 17:42:27 +00:00
|
|
|
virDomainObjPtr vm,
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
bool force)
|
|
|
|
{
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
|
int ret = 0;
|
2014-02-07 17:42:27 +00:00
|
|
|
uid_t uid;
|
|
|
|
gid_t gid;
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
|
2013-04-04 19:37:57 +00:00
|
|
|
if (!disk->src ||
|
|
|
|
disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK ||
|
|
|
|
disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME)
|
2013-01-10 21:03:14 +00:00
|
|
|
goto cleanup;
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
|
|
|
|
if (disk->backingChain) {
|
|
|
|
if (force) {
|
|
|
|
virStorageFileFreeMetadata(disk->backingChain);
|
|
|
|
disk->backingChain = NULL;
|
|
|
|
} else {
|
2013-01-10 21:03:14 +00:00
|
|
|
goto cleanup;
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-07 17:42:27 +00:00
|
|
|
|
|
|
|
qemuDomainGetImageIds(cfg, vm, disk, &uid, &gid);
|
|
|
|
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
disk->backingChain = virStorageFileGetMetadata(disk->src, disk->format,
|
2014-02-07 17:42:27 +00:00
|
|
|
uid, gid,
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->allowDiskFormatProbing);
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
if (!disk->backingChain)
|
2013-01-10 21:03:14 +00:00
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return ret;
|
storage: cache backing chain while qemu domain is live
Technically, we should not be re-probing any file that qemu might
be currently writing to. As such, we should cache the backing
file chain prior to starting qemu. This patch adds the cache,
but does not use it until the next patch.
Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet. So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.
* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.
2012-10-09 22:08:14 +00:00
|
|
|
}
|
2013-06-28 14:16:44 +00:00
|
|
|
|
2013-07-19 13:08:29 +00:00
|
|
|
int
|
|
|
|
qemuDomainUpdateDeviceList(virQEMUDriverPtr driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char **aliases;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitor(driver, vm);
|
|
|
|
if (qemuMonitorGetDeviceAliases(priv->mon, &aliases) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(driver, vm);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitor(driver, vm);
|
|
|
|
|
|
|
|
virStringFreeList(priv->qemuDevices);
|
|
|
|
priv->qemuDevices = aliases;
|
|
|
|
return 0;
|
|
|
|
}
|
qemu: Introduce qemuDomainDefCheckABIStability
https://bugzilla.redhat.com/show_bug.cgi?id=994364
Whenever we check for ABI stability, we have new xml (e.g. provided by
user, or obtained from snapshot, whatever) which we compare to old xml
and see if ABI won't break. However, if the new xml was produced via
virDomainGetXMLDesc(..., VIR_DOMAIN_XML_MIGRATABLE) it lacks some
devices, e.g. 'pci-root' controller. Hence, the ABI stability check
fails even though it is stable. Moreover, we can't simply fix
virDomainDefCheckABIStability because removing the correct devices is
task for the driver. For instance, qemu driver wants to remove the usb
controller too, while LXC driver doesn't. That's why we need special
qemu wrapper over virDomainDefCheckABIStability which removes the
correct devices from domain XML, produces MIGRATABLE xml and calls the
check ABI stability function.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2013-10-10 08:53:56 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
qemuDomainDefCheckABIStability(virQEMUDriverPtr driver,
|
|
|
|
virDomainDefPtr src,
|
|
|
|
virDomainDefPtr dst)
|
|
|
|
{
|
|
|
|
virDomainDefPtr migratableDefSrc = NULL;
|
|
|
|
virDomainDefPtr migratableDefDst = NULL;
|
|
|
|
const int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_UPDATE_CPU | VIR_DOMAIN_XML_MIGRATABLE;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (!(migratableDefSrc = qemuDomainDefCopy(driver, src, flags)) ||
|
|
|
|
!(migratableDefDst = qemuDomainDefCopy(driver, dst, flags)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virDomainDefCheckABIStability(migratableDefSrc, migratableDefDst);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainDefFree(migratableDefSrc);
|
|
|
|
virDomainDefFree(migratableDefDst);
|
|
|
|
return ret;
|
|
|
|
}
|