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
|
|
|
*
|
2013-02-06 18:17:20 +00:00
|
|
|
* Copyright (C) 2006-2013 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-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"
|
2013-07-18 10:39:55 +00:00
|
|
|
#include "storage_conf.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)
|
|
|
|
{
|
2013-02-15 12:05:12 +00:00
|
|
|
virQEMUDriverConfigClass = virClassNew(virClassForObject(),
|
|
|
|
"virQEMUDriverConfig",
|
|
|
|
sizeof(virQEMUDriverConfig),
|
|
|
|
virQEMUDriverConfigDispose);
|
2013-01-10 21:03:14 +00:00
|
|
|
|
2013-07-15 14:53:13 +00:00
|
|
|
if (!virQEMUDriverConfigClass)
|
2013-02-15 12:05:12 +00:00
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virQEMUConfig)
|
|
|
|
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
static void
|
|
|
|
qemuDriverLock(virQEMUDriverPtr driver)
|
2010-12-16 16:11:48 +00:00
|
|
|
{
|
|
|
|
virMutexLock(&driver->lock);
|
|
|
|
}
|
2013-02-06 18:17:20 +00:00
|
|
|
static void
|
|
|
|
qemuDriverUnlock(virQEMUDriverPtr driver)
|
2010-12-16 16:11:48 +00:00
|
|
|
{
|
|
|
|
virMutexUnlock(&driver->lock);
|
|
|
|
}
|
|
|
|
|
2013-09-24 15:38:26 +00:00
|
|
|
void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < def->num_args; i++)
|
|
|
|
VIR_FREE(def->args[i]);
|
|
|
|
for (i = 0; i < def->num_env; i++) {
|
|
|
|
VIR_FREE(def->env_name[i]);
|
|
|
|
VIR_FREE(def->env_value[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(def->args);
|
|
|
|
VIR_FREE(def->env_name);
|
|
|
|
VIR_FREE(def->env_value);
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
2010-12-16 16:11:48 +00:00
|
|
|
|
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 {
|
2013-03-02 14:19:47 +00:00
|
|
|
cfg->user = (uid_t)-1;
|
|
|
|
cfg->group = (gid_t)-1;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
cfg->dynamicOwnership = privileged;
|
|
|
|
|
2013-03-21 13:27:13 +00:00
|
|
|
cfg->cgroupControllers = -1; /* -1 == auto-detect */
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
if (privileged) {
|
|
|
|
if (virAsprintf(&cfg->logDir,
|
|
|
|
"%s/log/libvirt/qemu", LOCALSTATEDIR) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->configBaseDir, SYSCONFDIR "/libvirt") < 0)
|
|
|
|
goto error;
|
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)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
if (virAsprintf(&cfg->libDir,
|
|
|
|
"%s/lib/libvirt/qemu", LOCALSTATEDIR) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
if (virAsprintf(&cfg->cacheDir,
|
|
|
|
"%s/cache/libvirt/qemu", LOCALSTATEDIR) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->saveDir,
|
|
|
|
"%s/lib/libvirt/qemu/save", LOCALSTATEDIR) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->snapshotDir,
|
|
|
|
"%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->autoDumpPath,
|
|
|
|
"%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
} else {
|
|
|
|
char *rundir;
|
|
|
|
char *cachedir;
|
|
|
|
|
|
|
|
cachedir = virGetUserCacheDirectory();
|
|
|
|
if (!cachedir)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->logDir,
|
|
|
|
"%s/qemu/log", cachedir) < 0) {
|
|
|
|
VIR_FREE(cachedir);
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
if (virAsprintf(&cfg->cacheDir, "%s/qemu/cache", cachedir) < 0) {
|
|
|
|
VIR_FREE(cachedir);
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
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);
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(rundir);
|
|
|
|
|
|
|
|
if (!(cfg->configBaseDir = virGetUserConfigDirectory()))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->libDir, "%s/qemu/lib", cfg->configBaseDir) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->saveDir, "%s/qemu/save", cfg->configBaseDir) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->snapshotDir, "%s/qemu/snapshot", cfg->configBaseDir) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->autoDumpPath, "%s/qemu/dump", cfg->configBaseDir) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&cfg->configDir, "%s/qemu", cfg->configBaseDir) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
if (virAsprintf(&cfg->autostartDir, "%s/qemu/autostart", cfg->configBaseDir) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2012-06-18 08:22:07 +00:00
|
|
|
|
|
|
|
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->vncListen, "127.0.0.1") < 0)
|
|
|
|
goto error;
|
2012-11-29 11:25:07 +00:00
|
|
|
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->vncTLSx509certdir, SYSCONFDIR "/pki/libvirt-vnc") < 0)
|
|
|
|
goto error;
|
2007-10-12 16:05:44 +00:00
|
|
|
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->spiceListen, "127.0.0.1") < 0)
|
|
|
|
goto error;
|
2013-01-10 21:03:14 +00:00
|
|
|
|
2013-11-19 22:45:43 +00:00
|
|
|
if (VIR_STRDUP(cfg->spiceTLSx509certdir,
|
|
|
|
SYSCONFDIR "/pki/libvirt-spice") < 0)
|
2013-05-20 09:23:13 +00:00
|
|
|
goto error;
|
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;
|
|
|
|
|
2013-04-30 14:26:43 +00:00
|
|
|
cfg->webSocketPortMin = QEMU_WEBSOCKET_PORT_MIN;
|
|
|
|
cfg->webSocketPortMax = QEMU_WEBSOCKET_PORT_MAX;
|
|
|
|
|
2013-10-15 13:26:52 +00:00
|
|
|
cfg->migrationPortMin = QEMU_MIGRATION_PORT_MIN;
|
|
|
|
cfg->migrationPortMax = QEMU_MIGRATION_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-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->bridgeHelperName, "/usr/libexec/qemu-bridge-helper") < 0)
|
|
|
|
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
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
2012-02-24 14:13:06 +00:00
|
|
|
VIR_FREE(cfg->spiceSASLdir);
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
VIR_FREE(cfg->hugetlbfsMount);
|
|
|
|
VIR_FREE(cfg->hugepagePath);
|
2013-03-25 14:25:30 +00:00
|
|
|
VIR_FREE(cfg->bridgeHelperName);
|
2013-01-10 21:03:14 +00:00
|
|
|
|
|
|
|
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;
|
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-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); \
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(VAR, p->str) < 0) \
|
|
|
|
goto cleanup; \
|
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);
|
2013-08-17 19:30:47 +00:00
|
|
|
GET_VALUE_BOOL("nographics_allow_host_audio", cfg->nogfxAllowHostAudio);
|
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)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto cleanup;
|
2012-08-15 22:10:38 +00:00
|
|
|
|
|
|
|
for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->securityDriverNames[i], pp->str) < 0)
|
|
|
|
goto cleanup;
|
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-05-20 09:23:13 +00:00
|
|
|
if (VIR_ALLOC_N(cfg->securityDriverNames, 2) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto cleanup;
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->securityDriverNames[0], p->str) < 0)
|
|
|
|
goto cleanup;
|
2012-11-29 11:25:07 +00:00
|
|
|
|
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);
|
2012-02-24 14:13:06 +00:00
|
|
|
GET_VALUE_BOOL("spice_sasl", cfg->spiceSASL);
|
|
|
|
GET_VALUE_STR("spice_sasl_dir", cfg->spiceSASLdir);
|
2013-01-10 21:03:14 +00:00
|
|
|
GET_VALUE_STR("spice_listen", cfg->spiceListen);
|
|
|
|
GET_VALUE_STR("spice_password", cfg->spicePassword);
|
2010-03-05 20:31:50 +00:00
|
|
|
|
|
|
|
|
2013-04-30 14:26:43 +00:00
|
|
|
GET_VALUE_LONG("remote_websocket_port_min", cfg->webSocketPortMin);
|
|
|
|
if (cfg->webSocketPortMin < QEMU_WEBSOCKET_PORT_MIN) {
|
|
|
|
/* if the port is too low, we can't get the display name
|
|
|
|
* to tell to vnc (usually subtract 5700, e.g. localhost:1
|
|
|
|
* for port 5701) */
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: remote_websocket_port_min: port must be greater "
|
|
|
|
"than or equal to %d"),
|
|
|
|
filename, QEMU_WEBSOCKET_PORT_MIN);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
GET_VALUE_LONG("remote_websocket_port_max", cfg->webSocketPortMax);
|
|
|
|
if (cfg->webSocketPortMax > QEMU_WEBSOCKET_PORT_MAX ||
|
|
|
|
cfg->webSocketPortMax < cfg->webSocketPortMin) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: remote_websocket_port_max: port must be between "
|
|
|
|
"the minimal port and %d"),
|
|
|
|
filename, QEMU_WEBSOCKET_PORT_MAX);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cfg->webSocketPortMin > cfg->webSocketPortMax) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: remote_websocket_port_min: min port must not be "
|
|
|
|
"greater than max port"), filename);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-10-15 13:26:52 +00:00
|
|
|
GET_VALUE_LONG("migration_port_min", cfg->migrationPortMin);
|
|
|
|
if (cfg->migrationPortMin <= 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: migration_port_min: port must be greater than 0"),
|
|
|
|
filename);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
GET_VALUE_LONG("migration_port_max", cfg->migrationPortMax);
|
|
|
|
if (cfg->migrationPortMax > 65535 ||
|
|
|
|
cfg->migrationPortMax < cfg->migrationPortMin) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: migration_port_max: port must be between "
|
|
|
|
"the minimal port %d and 65535"),
|
|
|
|
filename, cfg->migrationPortMin);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
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) {
|
2013-03-21 13:27:13 +00:00
|
|
|
cfg->cgroupControllers = 0;
|
2009-07-22 15:08:04 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto cleanup;
|
2012-11-29 11:25:07 +00:00
|
|
|
|
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-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(cfg->cgroupDeviceACL[i], pp->str) < 0)
|
|
|
|
goto cleanup;
|
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);
|
2013-10-09 16:05:43 +00:00
|
|
|
GET_VALUE_STR("snapshot_image_format", cfg->snapshotImageFormat);
|
|
|
|
|
2013-01-10 21:03:14 +00:00
|
|
|
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);
|
2013-03-25 14:25:30 +00:00
|
|
|
GET_VALUE_STR("bridge_helper", cfg->bridgeHelperName);
|
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
|
|
|
|
2013-10-09 09:32:55 +00:00
|
|
|
GET_VALUE_STR("migration_address", cfg->migrationAddress);
|
|
|
|
|
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;
|
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)
|
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
virQEMUDriverConfigPtr conf;
|
|
|
|
qemuDriverLock(driver);
|
|
|
|
conf = virObjectRef(driver->config);
|
|
|
|
qemuDriverUnlock(driver);
|
|
|
|
return conf;
|
2013-01-10 21:03:14 +00:00
|
|
|
}
|
|
|
|
|
2013-03-31 18:03:42 +00:00
|
|
|
virDomainXMLOptionPtr
|
2013-03-11 09:24:29 +00:00
|
|
|
virQEMUDriverCreateXMLConf(virQEMUDriverPtr driver)
|
2013-03-05 15:17:24 +00:00
|
|
|
{
|
2013-03-11 09:24:29 +00:00
|
|
|
virQEMUDriverDomainDefParserConfig.priv = driver;
|
2013-02-19 16:33:52 +00:00
|
|
|
return virDomainXMLOptionNew(&virQEMUDriverDomainDefParserConfig,
|
2013-02-19 16:29:39 +00:00
|
|
|
&virQEMUDriverPrivateDataCallbacks,
|
|
|
|
&virQEMUDriverDomainXMLNamespace);
|
2013-03-05 15:17:24 +00:00
|
|
|
}
|
|
|
|
|
2013-02-01 17:04:15 +00:00
|
|
|
|
|
|
|
virCapsPtr virQEMUDriverCreateCapabilities(virQEMUDriverPtr driver)
|
|
|
|
{
|
2013-10-18 12:13:21 +00:00
|
|
|
size_t i, j;
|
2013-02-01 17:04:15 +00:00
|
|
|
virCapsPtr caps;
|
|
|
|
virSecurityManagerPtr *sec_managers = NULL;
|
|
|
|
/* Security driver data */
|
2013-10-18 12:13:21 +00:00
|
|
|
const char *doi, *model, *lbl, *type;
|
2013-02-01 17:04:15 +00:00
|
|
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
2013-10-18 12:13:21 +00:00
|
|
|
const int virtTypes[] = {VIR_DOMAIN_VIRT_KVM,
|
|
|
|
VIR_DOMAIN_VIRT_QEMU,};
|
2013-02-01 17:04:15 +00:00
|
|
|
|
|
|
|
/* Basic host arch / guest machine capabilities */
|
2013-02-19 09:56:06 +00:00
|
|
|
if (!(caps = virQEMUCapsInit(driver->qemuCapsCache)))
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-02-01 17:04:15 +00:00
|
|
|
|
|
|
|
if (virGetHostUUID(caps->host.host_uuid)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot get the host uuid"));
|
2013-02-19 09:56:06 +00:00
|
|
|
goto error;
|
2013-02-01 17:04:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* access sec drivers and create a sec model for each one */
|
2013-02-19 09:56:06 +00:00
|
|
|
if (!(sec_managers = virSecurityManagerGetNested(driver->securityManager)))
|
|
|
|
goto error;
|
2013-02-01 17:04:15 +00:00
|
|
|
|
|
|
|
/* calculate length */
|
|
|
|
for (i = 0; sec_managers[i]; i++)
|
|
|
|
;
|
|
|
|
caps->host.nsecModels = i;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
|
2013-07-04 10:14:12 +00:00
|
|
|
goto error;
|
2013-02-01 17:04:15 +00:00
|
|
|
|
|
|
|
for (i = 0; sec_managers[i]; i++) {
|
2013-10-18 12:13:21 +00:00
|
|
|
virCapsHostSecModelPtr sm = &caps->host.secModels[i];
|
2013-02-01 17:04:15 +00:00
|
|
|
doi = virSecurityManagerGetDOI(sec_managers[i]);
|
|
|
|
model = virSecurityManagerGetModel(sec_managers[i]);
|
2013-10-18 12:13:21 +00:00
|
|
|
if (VIR_STRDUP(sm->model, model) < 0 ||
|
|
|
|
VIR_STRDUP(sm->doi, doi) < 0)
|
2013-05-20 09:23:13 +00:00
|
|
|
goto error;
|
2013-10-18 12:13:21 +00:00
|
|
|
|
|
|
|
for (j = 0; j < ARRAY_CARDINALITY(virtTypes); j++) {
|
|
|
|
lbl = virSecurityManagerGetBaseLabel(sec_managers[i], virtTypes[j]);
|
|
|
|
type = virDomainVirtTypeToString(virtTypes[j]);
|
|
|
|
if (lbl &&
|
|
|
|
virCapabilitiesHostSecModelAddBaseLabel(sm, type, lbl) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-02-01 17:04:15 +00:00
|
|
|
VIR_DEBUG("Initialized caps for security driver \"%s\" with "
|
|
|
|
"DOI \"%s\"", model, doi);
|
|
|
|
}
|
|
|
|
VIR_FREE(sec_managers);
|
|
|
|
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return caps;
|
|
|
|
|
2013-02-19 09:56:06 +00:00
|
|
|
error:
|
2013-02-01 17:04:15 +00:00
|
|
|
VIR_FREE(sec_managers);
|
|
|
|
virObjectUnref(caps);
|
|
|
|
virObjectUnref(cfg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virQEMUDriverGetCapabilities:
|
|
|
|
*
|
|
|
|
* Get a reference to the virCapsPtr instance for the
|
|
|
|
* driver. If @refresh is true, the capabilities will be
|
|
|
|
* rebuilt first
|
|
|
|
*
|
|
|
|
* The caller must release the reference with virObjetUnref
|
|
|
|
*
|
|
|
|
* Returns: a reference to a virCapsPtr instance or NULL
|
|
|
|
*/
|
|
|
|
virCapsPtr virQEMUDriverGetCapabilities(virQEMUDriverPtr driver,
|
|
|
|
bool refresh)
|
|
|
|
{
|
2013-02-06 18:17:20 +00:00
|
|
|
virCapsPtr ret = NULL;
|
2013-02-01 17:04:15 +00:00
|
|
|
if (refresh) {
|
|
|
|
virCapsPtr caps = NULL;
|
|
|
|
if ((caps = virQEMUDriverCreateCapabilities(driver)) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDriverLock(driver);
|
2013-02-01 17:04:15 +00:00
|
|
|
virObjectUnref(driver->caps);
|
|
|
|
driver->caps = caps;
|
2013-02-06 18:17:20 +00:00
|
|
|
} else {
|
|
|
|
qemuDriverLock(driver);
|
2013-02-01 17:04:15 +00:00
|
|
|
}
|
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
ret = virObjectRef(driver->caps);
|
|
|
|
qemuDriverUnlock(driver);
|
|
|
|
return ret;
|
2013-02-01 17:04:15 +00:00
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
struct _qemuSharedDeviceEntry {
|
2013-02-20 07:43:55 +00:00
|
|
|
size_t ref;
|
|
|
|
char **domains; /* array of domain names */
|
|
|
|
};
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
/* Construct the hash key for sharedDevices as "major:minor" */
|
2013-01-02 14:37:07 +00:00
|
|
|
char *
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuGetSharedDeviceKey(const char *device_path)
|
2013-01-02 14:37:07 +00:00
|
|
|
{
|
|
|
|
int maj, min;
|
|
|
|
char *key = NULL;
|
|
|
|
int rc;
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if ((rc = virGetDeviceID(device_path, &maj, &min)) < 0) {
|
2013-01-02 14:37:07 +00:00
|
|
|
virReportSystemError(-rc,
|
|
|
|
_("Unable to get minor number of device '%s'"),
|
2013-05-03 18:07:35 +00:00
|
|
|
device_path);
|
2013-01-02 14:37:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&key, "%d:%d", maj, min) < 0)
|
2013-01-02 14:37:07 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
/* Check if a shared device's setting conflicts with the conf
|
2013-02-19 12:27:41 +00:00
|
|
|
* used by other domain(s). Currently only checks the sgio
|
|
|
|
* setting. Note that this should only be called for disk with
|
2013-05-03 18:07:44 +00:00
|
|
|
* block source if the device type is disk.
|
2013-02-19 12:27:41 +00:00
|
|
|
*
|
|
|
|
* Returns 0 if no conflicts, otherwise returns -1.
|
|
|
|
*/
|
|
|
|
static int
|
2013-05-03 18:07:44 +00:00
|
|
|
qemuCheckSharedDevice(virHashTablePtr sharedDevices,
|
|
|
|
virDomainDeviceDefPtr dev)
|
2013-02-19 12:27:41 +00:00
|
|
|
{
|
2013-05-03 18:07:44 +00:00
|
|
|
virDomainDiskDefPtr disk = NULL;
|
|
|
|
virDomainHostdevDefPtr hostdev = NULL;
|
2013-02-19 12:27:41 +00:00
|
|
|
char *sysfs_path = NULL;
|
|
|
|
char *key = NULL;
|
2013-05-03 18:07:44 +00:00
|
|
|
char *hostdev_name = NULL;
|
|
|
|
char *hostdev_path = NULL;
|
|
|
|
char *device_path = NULL;
|
2013-02-20 07:43:55 +00:00
|
|
|
int val;
|
2013-02-19 12:27:41 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
disk = dev->data.disk;
|
|
|
|
|
|
|
|
/* The only conflicts between shared disk we care about now
|
|
|
|
* is sgio setting, which is only valid for device='lun'.
|
|
|
|
*/
|
|
|
|
if (disk->device != VIR_DOMAIN_DISK_DEVICE_LUN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
device_path = disk->src;
|
|
|
|
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
|
|
|
|
hostdev = dev->data.hostdev;
|
|
|
|
|
|
|
|
if (!(hostdev_name = virSCSIDeviceGetDevName(hostdev->source.subsys.u.scsi.adapter,
|
|
|
|
hostdev->source.subsys.u.scsi.bus,
|
|
|
|
hostdev->source.subsys.u.scsi.target,
|
|
|
|
hostdev->source.subsys.u.scsi.unit)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&hostdev_path, "/dev/%s", hostdev_name) < 0)
|
2013-05-03 18:07:44 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
device_path = hostdev_path;
|
|
|
|
} else {
|
2013-02-19 12:27:41 +00:00
|
|
|
return 0;
|
2013-05-03 18:07:44 +00:00
|
|
|
}
|
2013-02-19 12:27:41 +00:00
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
if (!(sysfs_path = virGetUnprivSGIOSysfsPath(device_path, NULL))) {
|
2013-02-19 12:27:41 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It can't be conflict if unpriv_sgio is not supported
|
|
|
|
* by kernel.
|
|
|
|
*/
|
|
|
|
if (!virFileExists(sysfs_path))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
if (!(key = qemuGetSharedDeviceKey(device_path))) {
|
2013-02-19 12:27:41 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It can't be conflict if no other domain is
|
|
|
|
* is sharing it.
|
|
|
|
*/
|
2013-05-03 18:07:35 +00:00
|
|
|
if (!(virHashLookup(sharedDevices, key)))
|
2013-02-19 12:27:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
if (virGetDeviceUnprivSGIO(device_path, NULL, &val) < 0) {
|
2013-02-19 12:27:41 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val == 0 &&
|
2013-05-03 18:07:39 +00:00
|
|
|
(disk->sgio == VIR_DOMAIN_DEVICE_SGIO_FILTERED ||
|
|
|
|
disk->sgio == VIR_DOMAIN_DEVICE_SGIO_DEFAULT)) ||
|
2013-02-19 12:27:41 +00:00
|
|
|
(val == 1 &&
|
2013-05-03 18:07:39 +00:00
|
|
|
disk->sgio == VIR_DOMAIN_DEVICE_SGIO_UNFILTERED))
|
2013-02-19 12:27:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
if (disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("sgio of shared disk 'pool=%s' 'volume=%s' conflicts "
|
|
|
|
"with other active domains"),
|
|
|
|
disk->srcpool->pool,
|
|
|
|
disk->srcpool->volume);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("sgio of shared disk '%s' conflicts with other "
|
|
|
|
"active domains"), disk->src);
|
|
|
|
}
|
2013-04-04 19:38:02 +00:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
2013-05-03 18:07:44 +00:00
|
|
|
_("sgio of shared scsi host device '%s-%d-%d-%d' conflicts "
|
|
|
|
"with other active domains"),
|
|
|
|
hostdev->source.subsys.u.scsi.adapter,
|
|
|
|
hostdev->source.subsys.u.scsi.bus,
|
|
|
|
hostdev->source.subsys.u.scsi.target,
|
|
|
|
hostdev->source.subsys.u.scsi.unit);
|
2013-04-04 19:38:02 +00:00
|
|
|
}
|
|
|
|
|
2013-02-19 12:27:41 +00:00
|
|
|
ret = -1;
|
|
|
|
cleanup:
|
2013-05-03 18:07:44 +00:00
|
|
|
VIR_FREE(hostdev_name);
|
|
|
|
VIR_FREE(hostdev_path);
|
2013-02-19 12:27:41 +00:00
|
|
|
VIR_FREE(sysfs_path);
|
|
|
|
VIR_FREE(key);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-02-20 07:43:55 +00:00
|
|
|
bool
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryDomainExists(qemuSharedDeviceEntryPtr entry,
|
|
|
|
const char *name,
|
|
|
|
int *idx)
|
2013-02-20 07:43:55 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < entry->ref; i++) {
|
|
|
|
if (STREQ(entry->domains[i], name)) {
|
|
|
|
if (idx)
|
|
|
|
*idx = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryFree(void *payload, const void *name ATTRIBUTE_UNUSED)
|
2013-02-20 07:43:55 +00:00
|
|
|
{
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryPtr entry = payload;
|
2013-02-20 07:43:55 +00:00
|
|
|
size_t i;
|
|
|
|
|
2013-03-12 08:10:41 +00:00
|
|
|
if (!entry)
|
|
|
|
return;
|
|
|
|
|
2013-02-20 07:43:55 +00:00
|
|
|
for (i = 0; i < entry->ref; i++) {
|
|
|
|
VIR_FREE(entry->domains[i]);
|
|
|
|
}
|
|
|
|
VIR_FREE(entry->domains);
|
|
|
|
VIR_FREE(entry);
|
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
static qemuSharedDeviceEntryPtr
|
2013-10-08 17:07:53 +00:00
|
|
|
qemuSharedDeviceEntryCopy(const qemuSharedDeviceEntry *entry)
|
2013-02-20 07:43:55 +00:00
|
|
|
{
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryPtr ret = NULL;
|
2013-02-20 07:43:55 +00:00
|
|
|
size_t i;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (VIR_ALLOC(ret) < 0)
|
2013-02-20 07:43:55 +00:00
|
|
|
return NULL;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (VIR_ALLOC_N(ret->domains, entry->ref) < 0)
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < entry->ref; i++) {
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_STRDUP(ret->domains[i], entry->domains[i]) < 0)
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
ret->ref++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
cleanup:
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryFree(ret, NULL);
|
2013-02-20 07:43:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:37 +00:00
|
|
|
/* qemuAddSharedDevice:
|
2013-02-20 07:43:55 +00:00
|
|
|
* @driver: Pointer to qemu driver struct
|
2013-05-03 18:07:37 +00:00
|
|
|
* @dev: The device def
|
2013-02-20 07:43:55 +00:00
|
|
|
* @name: The domain name
|
|
|
|
*
|
|
|
|
* Increase ref count and add the domain name into the list which
|
2013-05-03 18:07:37 +00:00
|
|
|
* records all the domains that use the shared device if the entry
|
2013-02-20 07:43:55 +00:00
|
|
|
* already exists, otherwise add a new entry.
|
2013-01-02 14:37:07 +00:00
|
|
|
*/
|
|
|
|
int
|
2013-05-03 18:07:37 +00:00
|
|
|
qemuAddSharedDevice(virQEMUDriverPtr driver,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
const char *name)
|
2013-01-02 14:37:07 +00:00
|
|
|
{
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntry *entry = NULL;
|
|
|
|
qemuSharedDeviceEntry *new_entry = NULL;
|
2013-05-03 18:07:37 +00:00
|
|
|
virDomainDiskDefPtr disk = NULL;
|
|
|
|
virDomainHostdevDefPtr hostdev = NULL;
|
|
|
|
char *dev_name = NULL;
|
|
|
|
char *dev_path = NULL;
|
2013-01-02 14:37:07 +00:00
|
|
|
char *key = NULL;
|
2013-02-06 14:18:34 +00:00
|
|
|
int ret = -1;
|
2013-01-02 14:37:07 +00:00
|
|
|
|
2013-05-03 18:07:37 +00:00
|
|
|
/* Currently the only conflicts we have to care about for
|
|
|
|
* the shared disk and shared host device is "sgio" setting,
|
|
|
|
* which is only valid for block disk and scsi host device.
|
2013-02-19 12:27:40 +00:00
|
|
|
*/
|
2013-05-03 18:07:37 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
disk = dev->data.disk;
|
|
|
|
|
2013-07-18 10:39:55 +00:00
|
|
|
if (!disk->shared || !virDomainDiskSourceIsBlockType(disk))
|
2013-05-03 18:07:37 +00:00
|
|
|
return 0;
|
|
|
|
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
|
|
|
|
hostdev = dev->data.hostdev;
|
|
|
|
|
|
|
|
if (!hostdev->shareable ||
|
|
|
|
!(hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI))
|
|
|
|
return 0;
|
|
|
|
} else {
|
2013-02-19 12:27:40 +00:00
|
|
|
return 0;
|
2013-05-03 18:07:37 +00:00
|
|
|
}
|
2013-02-19 12:27:40 +00:00
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDriverLock(driver);
|
2013-05-03 18:07:44 +00:00
|
|
|
if (qemuCheckSharedDevice(driver->sharedDevices, dev) < 0)
|
|
|
|
goto cleanup;
|
2013-02-19 12:27:41 +00:00
|
|
|
|
2013-05-03 18:07:44 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
2013-05-03 18:07:37 +00:00
|
|
|
if (!(key = qemuGetSharedDeviceKey(disk->src)))
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (!(dev_name = virSCSIDeviceGetDevName(hostdev->source.subsys.u.scsi.adapter,
|
|
|
|
hostdev->source.subsys.u.scsi.bus,
|
|
|
|
hostdev->source.subsys.u.scsi.target,
|
|
|
|
hostdev->source.subsys.u.scsi.unit)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&dev_path, "/dev/%s", dev_name) < 0)
|
2013-05-03 18:07:37 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(key = qemuGetSharedDeviceKey(dev_path)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-01-02 14:37:07 +00:00
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if ((entry = virHashLookup(driver->sharedDevices, key))) {
|
2013-05-03 18:07:37 +00:00
|
|
|
/* Nothing to do if the shared scsi host device is already
|
|
|
|
* recorded in the table.
|
2013-02-20 07:43:55 +00:00
|
|
|
*/
|
2013-05-03 18:07:35 +00:00
|
|
|
if (qemuSharedDeviceEntryDomainExists(entry, name, NULL)) {
|
2013-02-20 07:43:55 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if (!(new_entry = qemuSharedDeviceEntryCopy(entry)))
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_EXPAND_N(new_entry->domains, new_entry->ref, 1) < 0 ||
|
|
|
|
VIR_STRDUP(new_entry->domains[new_entry->ref - 1], name) < 0) {
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryFree(new_entry, NULL);
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if (virHashUpdateEntry(driver->sharedDevices, key, new_entry) < 0) {
|
|
|
|
qemuSharedDeviceEntryFree(new_entry, NULL);
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-01-02 14:37:07 +00:00
|
|
|
} else {
|
2013-05-20 09:23:13 +00:00
|
|
|
if (VIR_ALLOC(entry) < 0 ||
|
|
|
|
VIR_ALLOC_N(entry->domains, 1) < 0 ||
|
|
|
|
VIR_STRDUP(entry->domains[0], name) < 0) {
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryFree(entry, NULL);
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->ref = 1;
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if (virHashAddEntry(driver->sharedDevices, key, entry))
|
2013-02-06 14:18:34 +00:00
|
|
|
goto cleanup;
|
2013-01-02 14:37:07 +00:00
|
|
|
}
|
|
|
|
|
2013-02-06 14:18:34 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDriverUnlock(driver);
|
2013-05-03 18:07:37 +00:00
|
|
|
VIR_FREE(dev_name);
|
|
|
|
VIR_FREE(dev_path);
|
2013-01-02 14:37:07 +00:00
|
|
|
VIR_FREE(key);
|
2013-02-06 14:18:34 +00:00
|
|
|
return ret;
|
2013-01-02 14:37:07 +00:00
|
|
|
}
|
|
|
|
|
2013-05-03 18:07:37 +00:00
|
|
|
/* qemuRemoveSharedDevice:
|
2013-02-20 07:43:55 +00:00
|
|
|
* @driver: Pointer to qemu driver struct
|
2013-05-03 18:07:37 +00:00
|
|
|
* @device: The device def
|
2013-02-20 07:43:55 +00:00
|
|
|
* @name: The domain name
|
|
|
|
*
|
|
|
|
* Decrease ref count and remove the domain name from the list which
|
2013-05-03 18:07:37 +00:00
|
|
|
* records all the domains that use the shared device if ref is not
|
|
|
|
* 1, otherwise remove the entry.
|
2013-01-02 14:37:07 +00:00
|
|
|
*/
|
|
|
|
int
|
2013-05-03 18:07:37 +00:00
|
|
|
qemuRemoveSharedDevice(virQEMUDriverPtr driver,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
const char *name)
|
2013-01-02 14:37:07 +00:00
|
|
|
{
|
2013-05-03 18:07:35 +00:00
|
|
|
qemuSharedDeviceEntryPtr entry = NULL;
|
|
|
|
qemuSharedDeviceEntryPtr new_entry = NULL;
|
2013-05-03 18:07:37 +00:00
|
|
|
virDomainDiskDefPtr disk = NULL;
|
|
|
|
virDomainHostdevDefPtr hostdev = NULL;
|
2013-01-02 14:37:07 +00:00
|
|
|
char *key = NULL;
|
2013-05-03 18:07:37 +00:00
|
|
|
char *dev_name = NULL;
|
|
|
|
char *dev_path = NULL;
|
2013-02-06 14:18:34 +00:00
|
|
|
int ret = -1;
|
2013-02-20 07:43:55 +00:00
|
|
|
int idx;
|
2013-01-02 14:37:07 +00:00
|
|
|
|
2013-05-03 18:07:37 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
disk = dev->data.disk;
|
|
|
|
|
2013-07-18 10:39:55 +00:00
|
|
|
if (!disk->shared || !virDomainDiskSourceIsBlockType(disk))
|
2013-05-03 18:07:37 +00:00
|
|
|
return 0;
|
|
|
|
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
|
|
|
|
hostdev = dev->data.hostdev;
|
|
|
|
|
|
|
|
if (!hostdev->shareable ||
|
|
|
|
!(hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI))
|
|
|
|
return 0;
|
|
|
|
} else {
|
2013-02-19 12:27:40 +00:00
|
|
|
return 0;
|
2013-05-03 18:07:37 +00:00
|
|
|
}
|
2013-02-19 12:27:40 +00:00
|
|
|
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDriverLock(driver);
|
2013-05-03 18:07:37 +00:00
|
|
|
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
if (!(key = qemuGetSharedDeviceKey(disk->src)))
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (!(dev_name = virSCSIDeviceGetDevName(hostdev->source.subsys.u.scsi.adapter,
|
|
|
|
hostdev->source.subsys.u.scsi.bus,
|
|
|
|
hostdev->source.subsys.u.scsi.target,
|
|
|
|
hostdev->source.subsys.u.scsi.unit)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&dev_path, "/dev/%s", dev_name) < 0)
|
2013-05-03 18:07:37 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(key = qemuGetSharedDeviceKey(dev_path)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-01-02 14:37:07 +00:00
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if (!(entry = virHashLookup(driver->sharedDevices, key)))
|
2013-02-06 14:18:34 +00:00
|
|
|
goto cleanup;
|
2013-01-02 14:37:07 +00:00
|
|
|
|
2013-02-20 07:43:55 +00:00
|
|
|
/* Nothing to do if the shared disk is not recored in
|
|
|
|
* the table.
|
|
|
|
*/
|
2013-05-03 18:07:35 +00:00
|
|
|
if (!qemuSharedDeviceEntryDomainExists(entry, name, &idx)) {
|
2013-02-20 07:43:55 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->ref != 1) {
|
2013-05-03 18:07:35 +00:00
|
|
|
if (!(new_entry = qemuSharedDeviceEntryCopy(entry)))
|
2013-02-20 07:43:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (idx != new_entry->ref - 1)
|
|
|
|
memmove(&new_entry->domains[idx],
|
|
|
|
&new_entry->domains[idx + 1],
|
|
|
|
sizeof(*new_entry->domains) * (new_entry->ref - idx - 1));
|
|
|
|
|
|
|
|
VIR_SHRINK_N(new_entry->domains, new_entry->ref, 1);
|
|
|
|
|
2013-05-03 18:07:35 +00:00
|
|
|
if (virHashUpdateEntry(driver->sharedDevices, key, new_entry) < 0){
|
|
|
|
qemuSharedDeviceEntryFree(new_entry, NULL);
|
2013-02-06 14:18:34 +00:00
|
|
|
goto cleanup;
|
2013-02-20 07:43:55 +00:00
|
|
|
}
|
2013-01-02 14:37:07 +00:00
|
|
|
} else {
|
2013-05-03 18:07:35 +00:00
|
|
|
if (virHashRemoveEntry(driver->sharedDevices, key) < 0)
|
2013-02-06 14:18:34 +00:00
|
|
|
goto cleanup;
|
2013-01-02 14:37:07 +00:00
|
|
|
}
|
|
|
|
|
2013-02-06 14:18:34 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2013-02-06 18:17:20 +00:00
|
|
|
qemuDriverUnlock(driver);
|
2013-05-03 18:07:37 +00:00
|
|
|
VIR_FREE(dev_name);
|
|
|
|
VIR_FREE(dev_path);
|
2013-01-02 14:37:07 +00:00
|
|
|
VIR_FREE(key);
|
2013-02-06 14:18:34 +00:00
|
|
|
return ret;
|
2013-01-02 14:37:07 +00:00
|
|
|
}
|
2013-01-14 16:50:08 +00:00
|
|
|
|
2013-05-03 18:07:41 +00:00
|
|
|
int
|
2013-05-03 18:07:42 +00:00
|
|
|
qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
|
2013-05-03 18:07:41 +00:00
|
|
|
{
|
2013-05-03 18:07:42 +00:00
|
|
|
virDomainDiskDefPtr disk = NULL;
|
|
|
|
virDomainHostdevDefPtr hostdev = NULL;
|
2013-05-03 18:07:41 +00:00
|
|
|
char *sysfs_path = NULL;
|
2013-05-03 18:07:42 +00:00
|
|
|
char *path = NULL;
|
|
|
|
char *hostdev_name = NULL;
|
|
|
|
char *hostdev_path = NULL;
|
2013-05-03 18:07:41 +00:00
|
|
|
int val = -1;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* "sgio" is only valid for block disk; cdrom
|
|
|
|
* and floopy disk can have empty source.
|
|
|
|
*/
|
2013-05-03 18:07:42 +00:00
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
|
disk = dev->data.disk;
|
|
|
|
|
2013-07-18 10:39:55 +00:00
|
|
|
if (disk->device != VIR_DOMAIN_DISK_DEVICE_LUN ||
|
2013-08-19 12:55:24 +00:00
|
|
|
!virDomainDiskSourceIsBlockType(disk))
|
2013-05-03 18:07:42 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
path = disk->src;
|
|
|
|
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
|
|
|
|
hostdev = dev->data.hostdev;
|
|
|
|
|
|
|
|
if (!hostdev->shareable ||
|
|
|
|
!(hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(hostdev_name = virSCSIDeviceGetDevName(hostdev->source.subsys.u.scsi.adapter,
|
|
|
|
hostdev->source.subsys.u.scsi.bus,
|
|
|
|
hostdev->source.subsys.u.scsi.target,
|
|
|
|
hostdev->source.subsys.u.scsi.unit)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-04 10:14:12 +00:00
|
|
|
if (virAsprintf(&hostdev_path, "/dev/%s", hostdev_name) < 0)
|
2013-05-03 18:07:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
path = hostdev_path;
|
|
|
|
} else {
|
2013-05-03 18:07:41 +00:00
|
|
|
return 0;
|
2013-05-03 18:07:42 +00:00
|
|
|
}
|
2013-05-03 18:07:41 +00:00
|
|
|
|
2013-05-03 18:07:42 +00:00
|
|
|
sysfs_path = virGetUnprivSGIOSysfsPath(path, NULL);
|
|
|
|
if (sysfs_path == NULL) {
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-05-03 18:07:41 +00:00
|
|
|
|
|
|
|
/* By default, filter the SG_IO commands, i.e. set unpriv_sgio to 0. */
|
2013-05-03 18:07:42 +00:00
|
|
|
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK)
|
|
|
|
val = (disk->sgio == VIR_DOMAIN_DEVICE_SGIO_UNFILTERED);
|
|
|
|
else
|
|
|
|
val = (hostdev->source.subsys.u.scsi.sgio ==
|
|
|
|
VIR_DOMAIN_DEVICE_SGIO_UNFILTERED);
|
2013-05-03 18:07:41 +00:00
|
|
|
|
|
|
|
/* Do not do anything if unpriv_sgio is not supported by the kernel and the
|
|
|
|
* whitelist is enabled. But if requesting unfiltered access, always call
|
|
|
|
* virSetDeviceUnprivSGIO, to report an error for unsupported unpriv_sgio.
|
|
|
|
*/
|
|
|
|
if ((virFileExists(sysfs_path) || val == 1) &&
|
2013-05-03 18:07:42 +00:00
|
|
|
virSetDeviceUnprivSGIO(path, NULL, val) < 0)
|
2013-05-03 18:07:41 +00:00
|
|
|
ret = -1;
|
|
|
|
|
2013-05-03 18:07:42 +00:00
|
|
|
cleanup:
|
2013-05-03 18:07:41 +00:00
|
|
|
VIR_FREE(sysfs_path);
|
2013-05-03 18:07:42 +00:00
|
|
|
VIR_FREE(hostdev_name);
|
|
|
|
VIR_FREE(hostdev_path);
|
2013-05-03 18:07:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2013-02-06 14:18:34 +00:00
|
|
|
|
2013-01-14 16:50:08 +00:00
|
|
|
int qemuDriverAllocateID(virQEMUDriverPtr driver)
|
|
|
|
{
|
|
|
|
return virAtomicIntInc(&driver->nextvmid);
|
|
|
|
}
|
2013-04-04 19:38:00 +00:00
|
|
|
|
2013-07-18 11:00:19 +00:00
|
|
|
static int
|
|
|
|
qemuAddISCSIPoolSourceHost(virDomainDiskDefPtr def,
|
|
|
|
virStoragePoolDefPtr pooldef)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char **tokens = NULL;
|
|
|
|
|
|
|
|
/* Only support one host */
|
|
|
|
if (pooldef->source.nhost != 1) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Expected exactly 1 host for the storage pool"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* iscsi pool only supports one host */
|
|
|
|
def->nhosts = 1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(def->hosts, def->nhosts) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (VIR_STRDUP(def->hosts[0].name, pooldef->source.hosts[0].name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virAsprintf(&def->hosts[0].port, "%d",
|
|
|
|
pooldef->source.hosts[0].port ?
|
|
|
|
pooldef->source.hosts[0].port :
|
|
|
|
3260) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* iscsi volume has name like "unit:0:0:1" */
|
|
|
|
if (!(tokens = virStringSplit(def->srcpool->volume, ":", 0)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virStringListLength(tokens) != 4) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected iscsi volume name '%s'"),
|
|
|
|
def->srcpool->volume);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* iscsi pool has only one source device path */
|
|
|
|
if (virAsprintf(&def->src, "%s/%s",
|
|
|
|
pooldef->source.devices[0].path,
|
|
|
|
tokens[3]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Storage pool have not supported these 2 attributes yet,
|
|
|
|
* use the defaults.
|
|
|
|
*/
|
|
|
|
def->hosts[0].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
|
|
|
|
def->hosts[0].socket = NULL;
|
|
|
|
|
|
|
|
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_ISCSI;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virStringFreeList(tokens);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-19 18:38:45 +00:00
|
|
|
static int
|
|
|
|
qemuTranslateDiskSourcePoolAuth(virDomainDiskDefPtr def,
|
|
|
|
virStoragePoolDefPtr pooldef)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/* Only necessary when authentication set */
|
|
|
|
if (pooldef->source.authType == VIR_STORAGE_POOL_AUTH_NONE) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the authentication information from the storage pool
|
|
|
|
* into the virDomainDiskDef
|
|
|
|
*/
|
|
|
|
if (pooldef->source.authType == VIR_STORAGE_POOL_AUTH_CHAP) {
|
|
|
|
if (VIR_STRDUP(def->auth.username,
|
|
|
|
pooldef->source.auth.chap.username) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (pooldef->source.auth.chap.secret.uuidUsable) {
|
|
|
|
def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_UUID;
|
|
|
|
memcpy(def->auth.secret.uuid,
|
|
|
|
pooldef->source.auth.chap.secret.uuid,
|
|
|
|
VIR_UUID_BUFLEN);
|
|
|
|
} else {
|
|
|
|
if (VIR_STRDUP(def->auth.secret.usage,
|
|
|
|
pooldef->source.auth.chap.secret.usage) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_USAGE;
|
|
|
|
}
|
|
|
|
} else if (pooldef->source.authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
|
|
|
|
if (VIR_STRDUP(def->auth.username,
|
|
|
|
pooldef->source.auth.cephx.username) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (pooldef->source.auth.cephx.secret.uuidUsable) {
|
|
|
|
def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_UUID;
|
|
|
|
memcpy(def->auth.secret.uuid,
|
|
|
|
pooldef->source.auth.cephx.secret.uuid,
|
|
|
|
VIR_UUID_BUFLEN);
|
|
|
|
} else {
|
|
|
|
if (VIR_STRDUP(def->auth.secret.usage,
|
|
|
|
pooldef->source.auth.cephx.secret.usage) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_USAGE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
qemuDiskGetActualType(virDomainDiskDefPtr def)
|
|
|
|
{
|
|
|
|
if (def->type == VIR_DOMAIN_DISK_TYPE_VOLUME)
|
|
|
|
return def->srcpool->actualtype;
|
|
|
|
|
|
|
|
return def->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-04 19:38:00 +00:00
|
|
|
int
|
|
|
|
qemuTranslateDiskSourcePool(virConnectPtr conn,
|
|
|
|
virDomainDiskDefPtr def)
|
|
|
|
{
|
2013-07-18 11:00:19 +00:00
|
|
|
virStoragePoolDefPtr pooldef = NULL;
|
2013-04-04 19:38:00 +00:00
|
|
|
virStoragePoolPtr pool = NULL;
|
|
|
|
virStorageVolPtr vol = NULL;
|
2013-07-18 11:00:19 +00:00
|
|
|
char *poolxml = NULL;
|
2013-04-04 19:38:00 +00:00
|
|
|
virStorageVolInfo info;
|
|
|
|
int ret = -1;
|
2013-07-24 08:38:20 +00:00
|
|
|
virErrorPtr savedError = NULL;
|
2013-04-04 19:38:00 +00:00
|
|
|
|
|
|
|
if (def->type != VIR_DOMAIN_DISK_TYPE_VOLUME)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!def->srcpool)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(pool = virStoragePoolLookupByName(conn, def->srcpool->pool)))
|
|
|
|
return -1;
|
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
if (virStoragePoolIsActive(pool) != 1) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("storage pool '%s' containing volume '%s' "
|
|
|
|
"is not active"),
|
|
|
|
def->srcpool->pool, def->srcpool->volume);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-04-04 19:38:00 +00:00
|
|
|
if (!(vol = virStorageVolLookupByName(pool, def->srcpool->volume)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virStorageVolGetInfo(vol, &info) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
if (!(poolxml = virStoragePoolGetXMLDesc(pool, 0)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(pooldef = virStoragePoolDefParseString(poolxml)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
def->srcpool->pooltype = pooldef->type;
|
|
|
|
def->srcpool->voltype = info.type;
|
|
|
|
|
|
|
|
if (def->srcpool->mode && pooldef->type != VIR_STORAGE_POOL_ISCSI) {
|
2013-04-04 19:38:00 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2013-11-20 09:37:31 +00:00
|
|
|
_("disk source mode is only valid when "
|
|
|
|
"storage pool is of iscsi type"));
|
2013-04-04 19:38:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-11-25 15:12:54 +00:00
|
|
|
VIR_FREE(def->src);
|
|
|
|
virDomainDiskHostDefFree(def->nhosts, def->hosts);
|
|
|
|
virDomainDiskAuthClear(def);
|
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
switch ((enum virStoragePoolType) pooldef->type) {
|
|
|
|
case VIR_STORAGE_POOL_DIR:
|
|
|
|
case VIR_STORAGE_POOL_FS:
|
|
|
|
case VIR_STORAGE_POOL_NETFS:
|
|
|
|
case VIR_STORAGE_POOL_LOGICAL:
|
|
|
|
case VIR_STORAGE_POOL_DISK:
|
|
|
|
case VIR_STORAGE_POOL_SCSI:
|
2013-04-04 19:38:00 +00:00
|
|
|
if (!(def->src = virStorageVolGetPath(vol)))
|
|
|
|
goto cleanup;
|
2013-11-20 09:37:31 +00:00
|
|
|
|
|
|
|
if (def->startupPolicy && info.type != VIR_STORAGE_VOL_FILE) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("'startupPolicy' is only valid for "
|
|
|
|
"'file' type volume"));
|
2013-07-18 11:00:19 +00:00
|
|
|
goto cleanup;
|
2013-11-20 09:37:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (info.type) {
|
|
|
|
case VIR_STORAGE_VOL_FILE:
|
|
|
|
def->srcpool->actualtype = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_VOL_DIR:
|
|
|
|
def->srcpool->actualtype = VIR_DOMAIN_DISK_TYPE_DIR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_VOL_BLOCK:
|
|
|
|
def->srcpool->actualtype = VIR_DOMAIN_DISK_TYPE_BLOCK;
|
|
|
|
break;
|
2013-07-18 11:00:19 +00:00
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
case VIR_STORAGE_VOL_NETWORK:
|
|
|
|
case VIR_STORAGE_VOL_NETDIR:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected storage volume type '%s' "
|
|
|
|
"for storage pool type '%s'"),
|
|
|
|
virStorageVolTypeToString(info.type),
|
|
|
|
virStoragePoolTypeToString(pooldef->type));
|
2013-07-18 11:00:19 +00:00
|
|
|
goto cleanup;
|
2013-11-20 09:37:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2013-07-18 11:00:19 +00:00
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
case VIR_STORAGE_POOL_ISCSI:
|
|
|
|
if (def->startupPolicy) {
|
2013-07-18 11:00:19 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2013-11-20 09:37:31 +00:00
|
|
|
_("'startupPolicy' is only valid for "
|
|
|
|
"'file' type volume"));
|
2013-07-18 11:00:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-11-20 09:37:31 +00:00
|
|
|
switch (def->srcpool->mode) {
|
2013-12-05 10:09:03 +00:00
|
|
|
case VIR_DOMAIN_DISK_SOURCE_POOL_MODE_DEFAULT:
|
|
|
|
case VIR_DOMAIN_DISK_SOURCE_POOL_MODE_LAST:
|
|
|
|
def->srcpool->mode = VIR_DOMAIN_DISK_SOURCE_POOL_MODE_HOST;
|
|
|
|
/* fallthrough */
|
|
|
|
case VIR_DOMAIN_DISK_SOURCE_POOL_MODE_HOST:
|
|
|
|
def->srcpool->actualtype = VIR_DOMAIN_DISK_TYPE_BLOCK;
|
|
|
|
if (!(def->src = virStorageVolGetPath(vol)))
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_SOURCE_POOL_MODE_DIRECT:
|
|
|
|
def->srcpool->actualtype = VIR_DOMAIN_DISK_TYPE_NETWORK;
|
|
|
|
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_ISCSI;
|
|
|
|
|
|
|
|
if (qemuTranslateDiskSourcePoolAuth(def, pooldef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (qemuAddISCSIPoolSourceHost(def, pooldef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2013-11-20 09:37:31 +00:00
|
|
|
|
|
|
|
case VIR_STORAGE_POOL_MPATH:
|
|
|
|
case VIR_STORAGE_POOL_RBD:
|
|
|
|
case VIR_STORAGE_POOL_SHEEPDOG:
|
|
|
|
case VIR_STORAGE_POOL_GLUSTER:
|
|
|
|
case VIR_STORAGE_POOL_LAST:
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("using '%s' pools for backing 'volume' disks "
|
|
|
|
"isn't yet supported"),
|
|
|
|
virStoragePoolTypeToString(pooldef->type));
|
2013-04-04 19:38:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2013-07-24 08:38:20 +00:00
|
|
|
if (ret < 0)
|
|
|
|
savedError = virSaveLastError();
|
|
|
|
if (pool)
|
|
|
|
virStoragePoolFree(pool);
|
|
|
|
if (vol)
|
|
|
|
virStorageVolFree(vol);
|
|
|
|
if (savedError) {
|
|
|
|
virSetError(savedError);
|
|
|
|
virFreeError(savedError);
|
|
|
|
}
|
|
|
|
|
2013-07-18 11:00:19 +00:00
|
|
|
VIR_FREE(poolxml);
|
|
|
|
virStoragePoolDefFree(pooldef);
|
2013-04-04 19:38:00 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2013-11-25 16:26:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def)
|
|
|
|
{
|
|
|
|
if (def->type == -1)
|
|
|
|
return VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
|
|
|
|
return def->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuTranslateSnapshotDiskSourcePool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainSnapshotDiskDefPtr def)
|
|
|
|
{
|
|
|
|
if (def->type != VIR_DOMAIN_DISK_TYPE_VOLUME)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Snapshots are not yet supported with 'pool' volumes"));
|
|
|
|
return -1;
|
|
|
|
}
|