2007-02-14 01:40:09 +00:00
|
|
|
/*
|
2009-05-21 14:16:55 +00:00
|
|
|
* qemu_conf.c: QEMU configuration management
|
2007-02-14 01:40:09 +00:00
|
|
|
*
|
2012-06-18 08:22:07 +00:00
|
|
|
* Copyright (C) 2006-2012 Red Hat, Inc.
|
2007-02-14 01:40:09 +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/>.
|
2007-02-14 01:40:09 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-11-26 11:50:16 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2008-10-10 16:52:20 +00:00
|
|
|
#include <stdlib.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2007-02-23 17:15:18 +00:00
|
|
|
#include <sys/wait.h>
|
2007-04-10 23:17:46 +00:00
|
|
|
#include <arpa/inet.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2007-06-27 00:12:29 +00:00
|
|
|
#include "qemu_conf.h"
|
2012-06-18 08:22:07 +00:00
|
|
|
#include "qemu_command.h"
|
2010-12-16 15:07:07 +00:00
|
|
|
#include "qemu_capabilities.h"
|
2009-11-03 22:41:23 +00:00
|
|
|
#include "qemu_bridge_filter.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 16:35:35 +00:00
|
|
|
#include "virconf.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2008-12-20 13:09:45 +00:00
|
|
|
#include "datatypes.h"
|
2012-12-13 18:13:21 +00:00
|
|
|
#include "virxml.h"
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#include "nodeinfo.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2009-12-18 15:24:14 +00:00
|
|
|
#include "cpu/cpu.h"
|
2010-06-21 18:18:31 +00:00
|
|
|
#include "domain_nwfilter.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2013-01-10 21:03:14 +00:00
|
|
|
#include "virstring.h"
|
2013-01-14 16:50:08 +00:00
|
|
|
#include "viratomic.h"
|
2010-11-16 14:54:17 +00:00
|
|
|
#include "configmake.h"
|
2008-07-11 19:34:11 +00:00
|
|
|
|
2009-01-23 16:22:20 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
static virClassPtr virQEMUDriverConfigClass;
|
|
|
|
static void virQEMUDriverConfigDispose(void *obj);
|
|
|
|
|
|
|
|
static int virQEMUConfigOnceInit(void)
|
|
|
|
{
|
|
|
|
if (!(virQEMUDriverConfigClass = virClassNew(virClassForObject(),
|
|
|
|
"virQEMUDriverConfig",
|
|
|
|
sizeof(virQEMUDriverConfig),
|
|
|
|
virQEMUDriverConfigDispose)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virQEMUConfig)
|
|
|
|
|
|
|
|
|
2012-03-19 13:28:10 +00:00
|
|
|
struct _qemuDriverCloseDef {
|
|
|
|
virConnectPtr conn;
|
|
|
|
qemuDriverCloseCallback cb;
|
|
|
|
};
|
|
|
|
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDriverLock(virQEMUDriverPtr driver)
|
2010-12-16 16:11:48 +00:00
|
|
|
{
|
|
|
|
virMutexLock(&driver->lock);
|
|
|
|
}
|
2012-11-28 16:43:10 +00:00
|
|
|
void qemuDriverUnlock(virQEMUDriverPtr driver)
|
2010-12-16 16:11:48 +00:00
|
|
|
{
|
|
|
|
virMutexUnlock(&driver->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
|
|
|
|
{
|
|
|
|
virQEMUDriverConfigPtr cfg;
|
|
|
|
|
|
|
|
if (virQEMUConfigInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(cfg = virObjectNew(virQEMUDriverConfigClass)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
cfg->privileged = privileged;
|
|
|
|
cfg->uri = privileged ? "qemu:///system" : "qemu:///session";
|
|
|
|
|
|
|
|
if (privileged) {
|
|
|
|
if (virGetUserID(QEMU_USER, &cfg->user) < 0)
|
|
|
|
goto error;
|
|
|
|
if (virGetGroupID(QEMU_GROUP, &cfg->group) < 0)
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
cfg->user = 0;
|
|
|
|
cfg->group = 0;
|
|
|
|
}
|
|
|
|
cfg->dynamicOwnership = privileged;
|
|
|
|
|
|
|
|
cfg->cgroupControllers =
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_CPU) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_DEVICES) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_MEMORY) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_BLKIO) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_CPUSET) |
|
|
|
|
(1 << VIR_CGROUP_CONTROLLER_CPUACCT);
|
|
|
|
|
|
|
|
|
|
|
|
if (privileged) {
|
|
|
|
if (virAsprintf(&cfg->logDir,
|
|
|
|
"%s/log/libvirt/qemu", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if ((cfg->configBaseDir = strdup(SYSCONFDIR "/libvirt")) == NULL)
|
|
|
|
goto no_memory;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->stateDir,
|
|
|
|
"%s/run/libvirt/qemu", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->libDir,
|
|
|
|
"%s/lib/libvirt/qemu", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->cacheDir,
|
|
|
|
"%s/cache/libvirt/qemu", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->saveDir,
|
|
|
|
"%s/lib/libvirt/qemu/save", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->snapshotDir,
|
|
|
|
"%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->autoDumpPath,
|
|
|
|
"%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
char *rundir;
|
|
|
|
char *cachedir;
|
|
|
|
|
|
|
|
cachedir = virGetUserCacheDirectory();
|
|
|
|
if (!cachedir)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->logDir,
|
|
|
|
"%s/qemu/log", cachedir) < 0) {
|
|
|
|
VIR_FREE(cachedir);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
if (virAsprintf(&cfg->cacheDir, "%s/qemu/cache", cachedir) < 0) {
|
|
|
|
VIR_FREE(cachedir);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
VIR_FREE(cachedir);
|
2010-01-13 17:41:36 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
rundir = virGetUserRuntimeDirectory();
|
|
|
|
if (!rundir)
|
|
|
|
goto error;
|
|
|
|
if (virAsprintf(&cfg->stateDir, "%s/qemu/run", rundir) < 0) {
|
|
|
|
VIR_FREE(rundir);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
VIR_FREE(rundir);
|
|
|
|
|
|
|
|
if (!(cfg->configBaseDir = virGetUserConfigDirectory()))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->libDir, "%s/qemu/lib", cfg->configBaseDir) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->saveDir, "%s/qemu/save", cfg->configBaseDir) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->snapshotDir, "%s/qemu/snapshot", cfg->configBaseDir) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->autoDumpPath, "%s/qemu/dump", cfg->configBaseDir) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->configDir, "%s/qemu", cfg->configBaseDir) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(&cfg->autostartDir, "%s/qemu/autostart", cfg->configBaseDir) < 0)
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
2012-06-18 08:22:07 +00:00
|
|
|
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (!(cfg->vncListen = strdup("127.0.0.1")))
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (!(cfg->vncTLSx509certdir
|
|
|
|
= strdup(SYSCONFDIR "/pki/libvirt-vnc")))
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (!(cfg->spiceListen = strdup("127.0.0.1")))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (!(cfg->spiceTLSx509certdir
|
2012-11-29 11:25:07 +00:00
|
|
|
= strdup(SYSCONFDIR "/pki/libvirt-spice")))
|
|
|
|
goto no_memory;
|
2010-03-05 20:31:50 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->remotePortMin = QEMU_REMOTE_PORT_MIN;
|
|
|
|
cfg->remotePortMax = QEMU_REMOTE_PORT_MAX;
|
|
|
|
|
2010-04-23 09:34:17 +00:00
|
|
|
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
/* For privileged driver, try and find hugepage mount automatically.
|
|
|
|
* Non-privileged driver requires admin to create a dir for the
|
|
|
|
* user, chown it, and then let user configure it manually */
|
2013-01-10 21:03:14 +00:00
|
|
|
if (privileged &&
|
|
|
|
!(cfg->hugetlbfsMount = virFileFindMountPoint("hugetlbfs"))) {
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
if (errno != ENOENT) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
_("unable to find hugetlbfs mountpoint"));
|
2013-01-10 21:03:14 +00:00
|
|
|
goto error;
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->clearEmulatorCapabilities = true;
|
|
|
|
|
|
|
|
cfg->securityDefaultConfined = true;
|
|
|
|
cfg->securityRequireConfined = false;
|
|
|
|
|
|
|
|
cfg->keepAliveInterval = 5;
|
|
|
|
cfg->keepAliveCount = 5;
|
|
|
|
cfg->seccompSandbox = -1;
|
|
|
|
|
|
|
|
return cfg;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
error:
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void virQEMUDriverConfigDispose(void *obj)
|
|
|
|
{
|
|
|
|
virQEMUDriverConfigPtr cfg = obj;
|
|
|
|
|
|
|
|
|
|
|
|
virStringFreeList(cfg->cgroupDeviceACL);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->configBaseDir);
|
|
|
|
VIR_FREE(cfg->configDir);
|
|
|
|
VIR_FREE(cfg->autostartDir);
|
|
|
|
VIR_FREE(cfg->logDir);
|
|
|
|
VIR_FREE(cfg->stateDir);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->libDir);
|
|
|
|
VIR_FREE(cfg->cacheDir);
|
|
|
|
VIR_FREE(cfg->saveDir);
|
|
|
|
VIR_FREE(cfg->snapshotDir);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->vncTLSx509certdir);
|
|
|
|
VIR_FREE(cfg->vncListen);
|
|
|
|
VIR_FREE(cfg->vncPassword);
|
|
|
|
VIR_FREE(cfg->vncSASLdir);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->spiceTLSx509certdir);
|
|
|
|
VIR_FREE(cfg->spiceListen);
|
|
|
|
VIR_FREE(cfg->spicePassword);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->hugetlbfsMount);
|
|
|
|
VIR_FREE(cfg->hugepagePath);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->saveImageFormat);
|
|
|
|
VIR_FREE(cfg->dumpImageFormat);
|
|
|
|
VIR_FREE(cfg->autoDumpPath);
|
|
|
|
|
|
|
|
virStringFreeList(cfg->securityDriverNames);
|
|
|
|
|
|
|
|
VIR_FREE(cfg->lockManagerName);
|
|
|
|
}
|
|
|
|
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 14:05:18 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
virConfPtr conf = NULL;
|
|
|
|
virConfValuePtr p;
|
|
|
|
int ret = -1;
|
|
|
|
int i;
|
2011-09-16 11:50:56 +00:00
|
|
|
|
2007-10-12 16:05:44 +00:00
|
|
|
/* Just check the file is readable before opening it, otherwise
|
|
|
|
* libvirt emits an error.
|
|
|
|
*/
|
2012-10-17 09:23:12 +00:00
|
|
|
if (access(filename, R_OK) == -1) {
|
2010-06-30 18:14:37 +00:00
|
|
|
VIR_INFO("Could not read qemu config file %s", filename);
|
2013-01-10 21:03:14 +00:00
|
|
|
return 0;
|
2010-06-30 18:14:37 +00:00
|
|
|
}
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2012-11-29 11:25:07 +00:00
|
|
|
if (!(conf = virConfReadFile(filename, 0)))
|
|
|
|
goto cleanup;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2012-11-27 16:59:34 +00:00
|
|
|
#define CHECK_TYPE(name,typ) \
|
|
|
|
if (p && p->type != (typ)) { \
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
"%s: %s: expected type " #typ, \
|
|
|
|
filename, (name)); \
|
2012-11-29 11:25:07 +00:00
|
|
|
goto cleanup; \
|
2012-11-27 16:59:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define GET_VALUE_LONG(NAME, VAR) \
|
|
|
|
p = virConfGetValue(conf, NAME); \
|
|
|
|
CHECK_TYPE(NAME, VIR_CONF_LONG); \
|
|
|
|
if (p) \
|
|
|
|
VAR = p->l;
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
#define GET_VALUE_BOOL(NAME, VAR) \
|
|
|
|
p = virConfGetValue(conf, NAME); \
|
|
|
|
CHECK_TYPE(NAME, VIR_CONF_LONG); \
|
|
|
|
if (p) \
|
|
|
|
VAR = p->l != 0;
|
|
|
|
|
2012-11-27 16:59:34 +00:00
|
|
|
#define GET_VALUE_STR(NAME, VAR) \
|
|
|
|
p = virConfGetValue(conf, NAME); \
|
|
|
|
CHECK_TYPE(NAME, VIR_CONF_STRING); \
|
|
|
|
if (p && p->str) { \
|
|
|
|
VIR_FREE(VAR); \
|
2012-11-29 11:25:07 +00:00
|
|
|
if (!(VAR = strdup(p->str))) \
|
|
|
|
goto no_memory; \
|
2012-11-27 16:59:34 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_BOOL("vnc_auto_unix_socket", cfg->vncAutoUnixSocket);
|
|
|
|
GET_VALUE_BOOL("vnc_tls", cfg->vncTLS);
|
|
|
|
GET_VALUE_BOOL("vnc_tls_x509_verify", cfg->vncTLSx509verify);
|
|
|
|
GET_VALUE_STR("vnc_tls_x509_cert_dir", cfg->vncTLSx509certdir);
|
|
|
|
GET_VALUE_STR("vnc_listen", cfg->vncListen);
|
|
|
|
GET_VALUE_STR("vnc_password", cfg->vncPassword);
|
|
|
|
GET_VALUE_BOOL("vnc_sasl", cfg->vncSASL);
|
|
|
|
GET_VALUE_STR("vnc_sasl_dir", cfg->vncSASLdir);
|
|
|
|
GET_VALUE_BOOL("vnc_allow_host_audio", cfg->vncAllowHostAudio);
|
2009-01-29 17:50:00 +00:00
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
p = virConfGetValue(conf, "security_driver");
|
2012-08-15 22:10:38 +00:00
|
|
|
if (p && p->type == VIR_CONF_LIST) {
|
|
|
|
size_t len;
|
|
|
|
virConfValuePtr pp;
|
|
|
|
|
2012-10-11 16:31:20 +00:00
|
|
|
/* Calc length and check items */
|
2012-08-15 22:10:38 +00:00
|
|
|
for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
|
|
|
|
if (pp->type != VIR_CONF_STRING) {
|
2012-11-29 11:25:07 +00:00
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX, "%s",
|
|
|
|
_("security_driver must be a list of strings"));
|
|
|
|
goto cleanup;
|
2012-08-15 22:10:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (VIR_ALLOC_N(cfg->securityDriverNames, len + 1) < 0)
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
2012-08-15 22:10:38 +00:00
|
|
|
|
|
|
|
for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
|
2013-01-10 21:03:14 +00:00
|
|
|
if (!(cfg->securityDriverNames[i] = strdup(pp->str)))
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
2012-08-15 22:10:38 +00:00
|
|
|
}
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->securityDriverNames[len] = NULL;
|
2012-08-15 22:10:38 +00:00
|
|
|
} else {
|
2012-10-17 09:23:12 +00:00
|
|
|
CHECK_TYPE("security_driver", VIR_CONF_STRING);
|
2012-08-15 22:10:38 +00:00
|
|
|
if (p && p->str) {
|
2013-01-10 21:03:14 +00:00
|
|
|
if (VIR_ALLOC_N(cfg->securityDriverNames, 2) < 0 ||
|
|
|
|
!(cfg->securityDriverNames[0] = strdup(p->str)))
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->securityDriverNames[1] = NULL;
|
2012-08-15 22:10:38 +00:00
|
|
|
}
|
2009-03-03 12:03:44 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_BOOL("security_default_confined", cfg->securityDefaultConfined);
|
|
|
|
GET_VALUE_BOOL("security_require_confined", cfg->securityRequireConfined);
|
2010-03-05 20:31:50 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_BOOL("spice_tls", cfg->spiceTLS);
|
|
|
|
GET_VALUE_STR("spice_tls_x509_cert_dir", cfg->spiceTLSx509certdir);
|
|
|
|
GET_VALUE_STR("spice_listen", cfg->spiceListen);
|
|
|
|
GET_VALUE_STR("spice_password", cfg->spicePassword);
|
2010-03-05 20:31:50 +00:00
|
|
|
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_LONG("remote_display_port_min", cfg->remotePortMin);
|
|
|
|
if (cfg->remotePortMin < QEMU_REMOTE_PORT_MIN) {
|
2012-11-27 16:59:34 +00:00
|
|
|
/* if the port is too low, we can't get the display name
|
|
|
|
* to tell to vnc (usually subtract 5900, e.g. localhost:1
|
|
|
|
* for port 5901) */
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: remote_display_port_min: port must be greater "
|
|
|
|
"than or equal to %d"),
|
|
|
|
filename, QEMU_REMOTE_PORT_MIN);
|
2012-11-29 11:25:07 +00:00
|
|
|
goto cleanup;
|
2012-06-18 08:22:07 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_LONG("remote_display_port_max", cfg->remotePortMax);
|
|
|
|
if (cfg->remotePortMax > QEMU_REMOTE_PORT_MAX ||
|
|
|
|
cfg->remotePortMax < cfg->remotePortMin) {
|
2012-11-27 16:59:34 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: remote_display_port_max: port must be between "
|
|
|
|
"the minimal port and %d"),
|
|
|
|
filename, QEMU_REMOTE_PORT_MAX);
|
2012-11-29 11:25:07 +00:00
|
|
|
goto cleanup;
|
2012-06-18 08:22:07 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
if (cfg->remotePortMin > cfg->remotePortMax) {
|
2012-06-18 08:22:07 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2012-11-27 16:59:34 +00:00
|
|
|
_("%s: remote_display_port_min: min port must not be "
|
|
|
|
"greater than max port"), filename);
|
2012-11-29 11:25:07 +00:00
|
|
|
goto cleanup;
|
2012-06-18 08:22:07 +00:00
|
|
|
}
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
p = virConfGetValue(conf, "user");
|
|
|
|
CHECK_TYPE("user", VIR_CONF_STRING);
|
2013-01-10 21:03:14 +00:00
|
|
|
if (p && p->str &&
|
|
|
|
virGetUserID(p->str, &cfg->user) < 0)
|
2012-11-29 11:25:07 +00:00
|
|
|
goto cleanup;
|
2010-01-13 17:41:36 +00:00
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
p = virConfGetValue(conf, "group");
|
|
|
|
CHECK_TYPE("group", VIR_CONF_STRING);
|
2013-01-10 21:03:14 +00:00
|
|
|
if (p && p->str &&
|
|
|
|
virGetGroupID(p->str, &cfg->group) < 0)
|
2012-11-29 11:25:07 +00:00
|
|
|
goto cleanup;
|
2009-07-15 21:25:01 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_BOOL("dynamic_ownership", cfg->dynamicOwnership);
|
2010-01-13 17:41:36 +00:00
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
p = virConfGetValue(conf, "cgroup_controllers");
|
|
|
|
CHECK_TYPE("cgroup_controllers", VIR_CONF_LIST);
|
2009-07-22 15:08:04 +00:00
|
|
|
if (p) {
|
|
|
|
virConfValuePtr pp;
|
|
|
|
for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
|
|
|
|
int ctl;
|
|
|
|
if (pp->type != VIR_CONF_STRING) {
|
2012-11-29 11:25:07 +00:00
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX, "%s",
|
|
|
|
_("cgroup_controllers must be a "
|
|
|
|
"list of strings"));
|
|
|
|
goto cleanup;
|
2009-07-22 15:08:04 +00:00
|
|
|
}
|
2012-11-29 11:25:07 +00:00
|
|
|
|
|
|
|
if ((ctl = virCgroupControllerTypeFromString(pp->str)) < 0) {
|
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("Unknown cgroup controller '%s'"), pp->str);
|
|
|
|
goto cleanup;
|
2009-07-22 15:08:04 +00:00
|
|
|
}
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->cgroupControllers |= (1 << ctl);
|
2009-07-22 15:08:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
|
2013-01-10 21:03:14 +00:00
|
|
|
if (cfg->cgroupControllers & (1 << i)) {
|
2009-07-22 15:08:04 +00:00
|
|
|
VIR_INFO("Configured cgroup controller '%s'",
|
|
|
|
virCgroupControllerTypeToString(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
p = virConfGetValue(conf, "cgroup_device_acl");
|
|
|
|
CHECK_TYPE("cgroup_device_acl", VIR_CONF_LIST);
|
2009-07-22 15:08:04 +00:00
|
|
|
if (p) {
|
|
|
|
int len = 0;
|
|
|
|
virConfValuePtr pp;
|
|
|
|
for (pp = p->list; pp; pp = pp->next)
|
|
|
|
len++;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (VIR_ALLOC_N(cfg->cgroupDeviceACL, 1+len) < 0)
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2009-07-22 15:08:04 +00:00
|
|
|
for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
|
|
|
|
if (pp->type != VIR_CONF_STRING) {
|
2012-11-29 11:25:07 +00:00
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX, "%s",
|
|
|
|
_("cgroup_device_acl must be a "
|
|
|
|
"list of strings"));
|
|
|
|
goto cleanup;
|
2009-07-22 15:08:04 +00:00
|
|
|
}
|
2013-01-10 21:03:14 +00:00
|
|
|
if (!(cfg->cgroupDeviceACL[i] = strdup(pp->str)))
|
2012-11-29 11:25:07 +00:00
|
|
|
goto no_memory;
|
2009-07-22 15:08:04 +00:00
|
|
|
}
|
2013-01-10 21:03:14 +00:00
|
|
|
cfg->cgroupDeviceACL[i] = NULL;
|
2009-07-22 15:08:04 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_STR("save_image_format", cfg->saveImageFormat);
|
|
|
|
GET_VALUE_STR("dump_image_format", cfg->dumpImageFormat);
|
|
|
|
GET_VALUE_STR("auto_dump_path", cfg->autoDumpPath);
|
|
|
|
GET_VALUE_BOOL("auto_dump_bypass_cache", cfg->autoDumpBypassCache);
|
|
|
|
GET_VALUE_BOOL("auto_start_bypass_cache", cfg->autoStartBypassCache);
|
2009-11-03 22:41:23 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_STR("hugetlbfs_mount", cfg->hugetlbfsMount);
|
2009-11-03 22:41:23 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_BOOL("mac_filter", cfg->macFilter);
|
|
|
|
|
|
|
|
GET_VALUE_BOOL("relaxed_acs_check", cfg->relaxedACS);
|
|
|
|
GET_VALUE_BOOL("clear_emulator_capabilities", cfg->clearEmulatorCapabilities);
|
|
|
|
GET_VALUE_BOOL("allow_disk_format_probing", cfg->allowDiskFormatProbing);
|
|
|
|
GET_VALUE_BOOL("set_process_name", cfg->setProcessName);
|
|
|
|
GET_VALUE_LONG("max_processes", cfg->maxProcesses);
|
|
|
|
GET_VALUE_LONG("max_files", cfg->maxFiles);
|
2010-10-26 14:04:46 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_STR("lock_manager", cfg->lockManagerName);
|
|
|
|
|
|
|
|
GET_VALUE_LONG("max_queued", cfg->maxQueuedJobs);
|
|
|
|
|
|
|
|
GET_VALUE_LONG("keepalive_interval", cfg->keepAliveInterval);
|
|
|
|
GET_VALUE_LONG("keepalive_count", cfg->keepAliveCount);
|
|
|
|
|
|
|
|
GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox);
|
2012-09-17 07:59:53 +00:00
|
|
|
|
2012-11-29 11:25:07 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2012-10-17 09:23:12 +00:00
|
|
|
virConfFree(conf);
|
2012-11-29 11:25:07 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
2007-10-12 16:05:44 +00:00
|
|
|
}
|
2013-01-10 21:03:14 +00:00
|
|
|
#undef GET_VALUE_BOOL
|
2012-11-27 16:59:34 +00:00
|
|
|
#undef GET_VALUE_LONG
|
|
|
|
#undef GET_VALUE_STRING
|
2012-03-19 13:28:10 +00:00
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
virQEMUDriverConfigPtr virQEMUDriverGetConfig(virQEMUDriverPtr driver)
|
|
|
|
{
|
|
|
|
return virObjectRef(driver->config);
|
|
|
|
}
|
|
|
|
|
2012-03-19 13:28:10 +00:00
|
|
|
static void
|
|
|
|
qemuDriverCloseCallbackFree(void *payload,
|
|
|
|
const void *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
VIR_FREE(payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDriverCloseCallbackInit(virQEMUDriverPtr driver)
|
2012-03-19 13:28:10 +00:00
|
|
|
{
|
|
|
|
driver->closeCallbacks = virHashCreate(5, qemuDriverCloseCallbackFree);
|
|
|
|
if (!driver->closeCallbacks)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDriverCloseCallbackShutdown(virQEMUDriverPtr driver)
|
2012-03-19 13:28:10 +00:00
|
|
|
{
|
|
|
|
virHashFree(driver->closeCallbacks);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDriverCloseCallbackSet(virQEMUDriverPtr driver,
|
2012-03-19 13:28:10 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
virConnectPtr conn,
|
|
|
|
qemuDriverCloseCallback cb)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
qemuDriverCloseDefPtr closeDef;
|
|
|
|
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
|
|
|
VIR_DEBUG("vm=%s, uuid=%s, conn=%p, cb=%p",
|
|
|
|
vm->def->name, uuidstr, conn, cb);
|
|
|
|
|
|
|
|
closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
|
|
|
|
if (closeDef) {
|
|
|
|
if (closeDef->conn != conn) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Close callback for domain %s already registered"
|
|
|
|
" with another connection %p"),
|
|
|
|
vm->def->name, closeDef->conn);
|
2012-03-19 13:28:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (closeDef->cb && closeDef->cb != cb) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Another close callback is already defined for"
|
|
|
|
" domain %s"), vm->def->name);
|
2012-03-19 13:28:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
closeDef->cb = cb;
|
|
|
|
} else {
|
|
|
|
if (VIR_ALLOC(closeDef) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
closeDef->conn = conn;
|
|
|
|
closeDef->cb = cb;
|
|
|
|
if (virHashAddEntry(driver->closeCallbacks, uuidstr, closeDef) < 0) {
|
|
|
|
VIR_FREE(closeDef);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDriverCloseCallbackUnset(virQEMUDriverPtr driver,
|
2012-03-19 13:28:10 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
qemuDriverCloseCallback cb)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
qemuDriverCloseDefPtr closeDef;
|
|
|
|
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
|
|
|
VIR_DEBUG("vm=%s, uuid=%s, cb=%p",
|
|
|
|
vm->def->name, uuidstr, cb);
|
|
|
|
|
|
|
|
closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
|
|
|
|
if (!closeDef)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (closeDef->cb && closeDef->cb != cb) {
|
2012-07-18 15:22:03 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Trying to remove mismatching close callback for"
|
|
|
|
" domain %s"), vm->def->name);
|
2012-03-19 13:28:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virHashRemoveEntry(driver->closeCallbacks, uuidstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDriverCloseCallback
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDriverCloseCallbackGet(virQEMUDriverPtr driver,
|
2012-03-19 13:28:10 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
qemuDriverCloseDefPtr closeDef;
|
|
|
|
qemuDriverCloseCallback cb = NULL;
|
|
|
|
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
|
|
|
VIR_DEBUG("vm=%s, uuid=%s, conn=%p",
|
|
|
|
vm->def->name, uuidstr, conn);
|
|
|
|
|
|
|
|
closeDef = virHashLookup(driver->closeCallbacks, uuidstr);
|
|
|
|
if (closeDef && (!conn || closeDef->conn == conn))
|
|
|
|
cb = closeDef->cb;
|
|
|
|
|
|
|
|
VIR_DEBUG("cb=%p", cb);
|
|
|
|
return cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct qemuDriverCloseCallbackData {
|
2012-11-28 16:43:10 +00:00
|
|
|
virQEMUDriverPtr driver;
|
2012-03-19 13:28:10 +00:00
|
|
|
virConnectPtr conn;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
qemuDriverCloseCallbackRun(void *payload,
|
|
|
|
const void *name,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct qemuDriverCloseCallbackData *data = opaque;
|
|
|
|
qemuDriverCloseDefPtr closeDef = payload;
|
|
|
|
unsigned char uuid[VIR_UUID_BUFLEN];
|
2013-01-23 17:22:27 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2012-03-19 13:28:10 +00:00
|
|
|
virDomainObjPtr dom;
|
|
|
|
|
|
|
|
VIR_DEBUG("conn=%p, thisconn=%p, uuid=%s, cb=%p",
|
2013-01-23 17:22:27 +00:00
|
|
|
closeDef->conn, data->conn, (const char *)name, closeDef->cb);
|
2012-03-19 13:28:10 +00:00
|
|
|
|
|
|
|
if (data->conn != closeDef->conn || !closeDef->cb)
|
|
|
|
return;
|
|
|
|
|
2013-01-23 17:22:27 +00:00
|
|
|
if (virUUIDParse(name, uuid) < 0) {
|
|
|
|
VIR_WARN("Failed to parse %s", (const char *)name);
|
2012-03-19 13:28:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-01-23 17:22:27 +00:00
|
|
|
/* We need to reformat uuidstr, because closeDef->cb
|
|
|
|
* might cause the current hash entry to be removed,
|
|
|
|
* which means 'name' will have been free()d
|
|
|
|
*/
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
2012-03-19 13:28:10 +00:00
|
|
|
|
2013-01-11 16:04:47 +00:00
|
|
|
if (!(dom = virDomainObjListFindByUUID(data->driver->domains, uuid))) {
|
2012-03-19 13:28:10 +00:00
|
|
|
VIR_DEBUG("No domain object with UUID %s", uuidstr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dom = closeDef->cb(data->driver, dom, data->conn);
|
|
|
|
if (dom)
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(dom);
|
2012-03-19 13:28:10 +00:00
|
|
|
|
|
|
|
virHashRemoveEntry(data->driver->closeCallbacks, uuidstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-11-28 16:43:10 +00:00
|
|
|
qemuDriverCloseCallbackRunAll(virQEMUDriverPtr driver,
|
2012-03-19 13:28:10 +00:00
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
struct qemuDriverCloseCallbackData data = {
|
|
|
|
driver, conn
|
|
|
|
};
|
|
|
|
VIR_DEBUG("conn=%p", conn);
|
|
|
|
|
|
|
|
virHashForEach(driver->closeCallbacks, qemuDriverCloseCallbackRun, &data);
|
|
|
|
}
|
2013-01-02 14:37:07 +00:00
|
|
|
|
|
|
|
/* Construct the hash key for sharedDisks as "major:minor" */
|
|
|
|
char *
|
|
|
|
qemuGetSharedDiskKey(const char *disk_path)
|
|
|
|
{
|
|
|
|
int maj, min;
|
|
|
|
char *key = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virGetDeviceID(disk_path, &maj, &min)) < 0) {
|
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to get minor number of device '%s'"),
|
|
|
|
disk_path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&key, "%d:%d", maj, min) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Increase ref count if the entry already exists, otherwise
|
|
|
|
* add a new entry.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemuAddSharedDisk(virHashTablePtr sharedDisks,
|
|
|
|
const char *disk_path)
|
|
|
|
{
|
|
|
|
size_t *ref = NULL;
|
|
|
|
char *key = NULL;
|
|
|
|
|
|
|
|
if (!(key = qemuGetSharedDiskKey(disk_path)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((ref = virHashLookup(sharedDisks, key))) {
|
|
|
|
if (virHashUpdateEntry(sharedDisks, key, ++ref) < 0) {
|
|
|
|
VIR_FREE(key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virHashAddEntry(sharedDisks, key, (void *)0x1)) {
|
|
|
|
VIR_FREE(key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(key);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Decrease the ref count if the entry already exists, otherwise
|
|
|
|
* remove the entry.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qemuRemoveSharedDisk(virHashTablePtr sharedDisks,
|
|
|
|
const char *disk_path)
|
|
|
|
{
|
|
|
|
size_t *ref = NULL;
|
|
|
|
char *key = NULL;
|
|
|
|
|
|
|
|
if (!(key = qemuGetSharedDiskKey(disk_path)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(ref = virHashLookup(sharedDisks, key))) {
|
|
|
|
VIR_FREE(key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ref != (void *)0x1) {
|
|
|
|
if (virHashUpdateEntry(sharedDisks, key, --ref) < 0) {
|
|
|
|
VIR_FREE(key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virHashRemoveEntry(sharedDisks, key) < 0) {
|
|
|
|
VIR_FREE(key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(key);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-14 16:50:08 +00:00
|
|
|
|
|
|
|
int qemuDriverAllocateID(virQEMUDriverPtr driver)
|
|
|
|
{
|
|
|
|
return virAtomicIntInc(&driver->nextvmid);
|
|
|
|
}
|