In some cases management application needs to allocate memory for
qemu upfront and then just let qemu use that. Since we don't want
to expose path for memory-backend-file anywhere in the domain
XML, we can have a configuration knob that when enabled generated
predictable paths. In this case:
$memoryBackingDir/libvirt/qemu/$shortName/$alias
where $shortName is result of virDomainObjGetShortName().
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/libvirtd_qemu.aug | 1 +
src/qemu/qemu.conf | 5 ++
src/qemu/qemu_command.c | 9 +--
src/qemu/qemu_conf.c | 76 +++++++++++++++++++-
src/qemu/qemu_conf.h | 10 ++-
src/qemu/qemu_driver.c | 19 +++++
src/qemu/qemu_hotplug.c | 2 +-
src/qemu/qemu_process.c | 141 ++++++++++++++++++++++++++-----------
src/qemu/qemu_process.h | 8 +--
src/qemu/test_libvirtd_qemu.aug.in | 1 +
10 files changed, 220 insertions(+), 52 deletions(-)
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
index c19bf3a43..77d466b14 100644
--- a/src/qemu/libvirtd_qemu.aug
+++ b/src/qemu/libvirtd_qemu.aug
@@ -114,6 +114,7 @@ module Libvirtd_qemu =
let gluster_debug_level_entry = int_entry "gluster_debug_level"
let memory_entry = str_entry "memory_backing_dir"
+ | bool_entry "memory_predictable_file_names"
let vxhs_entry = bool_entry "vxhs_tls"
| str_entry "vxhs_tls_x509_cert_dir"
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 2e8370a5a..dc3098148 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -769,3 +769,8 @@
# This directory is used for memoryBacking source if configured as file.
# NOTE: big files will be stored here
#memory_backing_dir = "/var/lib/libvirt/qemu/ram"
+
+# Use predictable file names. If this is enabled, Libvirt constructs
+# full paths for memory-backing-file objects. This is experimental
+# feature and generated paths can change across releases. Don't use it.
+#memory_predictable_file_names = 1
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 82d2fb2a3..d6d2654cd 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3439,7 +3439,7 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps,
} else {
/* We can have both pagesize and mem source. If that's the case,
* prefer hugepages as those are more specific. */
- if (qemuGetMemoryBackingPath(cfg, &memPath) < 0)
+ if (qemuGetMemoryBackingPath(def, cfg, mem->info.alias, &memPath) <
0)
goto cleanup;
}
@@ -3542,12 +3542,13 @@ qemuBuildMemoryCellBackendStr(virDomainDefPtr def,
unsigned long long memsize = virDomainNumaGetNodeMemorySize(def->numa,
cell);
+ if (virAsprintf(&alias, "ram-node%zu", cell) < 0)
+ goto cleanup;
+
*backendStr = NULL;
mem.size = memsize;
mem.targetNode = cell;
-
- if (virAsprintf(&alias, "ram-node%zu", cell) < 0)
- goto cleanup;
+ mem.info.alias = alias;
if ((rc = qemuBuildMemoryBackendStr(&props, &backendType, cfg,
priv->qemuCaps,
def, &mem, priv->autoNodeset, false)) <
0)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 23dcc25e1..34f411137 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -912,6 +912,10 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
if (virConfGetValueString(conf, "memory_backing_dir",
&cfg->memoryBackingDir) < 0)
goto cleanup;
+ if (virConfGetValueBool(conf, "memory_predictable_file_names",
+ &cfg->memoryPredictableFileNames) < 0)
+ goto cleanup;
+
ret = 0;
cleanup:
@@ -1750,9 +1754,53 @@ qemuGetDomainHupageMemPath(const virDomainDef *def,
}
+int
+qemuGetMemoryBackingBasePath(virQEMUDriverConfigPtr cfg,
+ char **path)
+{
+ if (!cfg->memoryPredictableFileNames) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("predictable file names are disabled"));
+ return -1;
+ }
+
+ return virAsprintf(path, "%s/libvirt/qemu", cfg->memoryBackingDir);
+}
+
+
+int
+qemuGetMemoryBackingDomainPath(const virDomainDef *def,
+ virQEMUDriverConfigPtr cfg,
+ char **path)
+{
+ char *shortName = NULL;
+ char *base = NULL;
+ int ret = -1;
+
+ if (!cfg->memoryPredictableFileNames) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("predictable file names are disabled"));
+ return -1;
+ }
+
+ if (!(shortName = virDomainDefGetShortName(def)) ||
+ qemuGetMemoryBackingBasePath(cfg, &base) < 0 ||
+ virAsprintf(path, "%s/%s", base, shortName) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(base);
+ VIR_FREE(shortName);
+ return ret;
+}
+
+
/**
* qemuGetMemoryBackingPath:
+ * @def: domain definition
* @cfg: the driver config
+ * @alias: memory object alias
* @memPath: constructed path
*
* Constructs path to memory backing dir and stores it at @memPath.
@@ -1761,8 +1809,32 @@ qemuGetDomainHupageMemPath(const virDomainDef *def,
* -1 otherwise (with error reported).
*/
int
-qemuGetMemoryBackingPath(virQEMUDriverConfigPtr cfg,
+qemuGetMemoryBackingPath(const virDomainDef *def,
+ virQEMUDriverConfigPtr cfg,
+ const char *alias,
char **memPath)
{
- return VIR_STRDUP(*memPath, cfg->memoryBackingDir);
+ char *domainPath = NULL;
+ int ret = -1;
+
+ if (cfg->memoryPredictableFileNames) {
+ if (!alias) {
+ /* This should never happen (TM) */
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("memory device alias is not assigned"));
+ goto cleanup;
+ }
+
+ if (qemuGetMemoryBackingDomainPath(def, cfg, &domainPath) < 0 ||
+ virAsprintf(memPath, "%s/%s", domainPath, alias) < 0)
+ goto cleanup;
+ } else {
+ if (VIR_STRDUP(*memPath, cfg->memoryBackingDir) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(domainPath);
+ return ret;
}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 9d6866816..5b72788c9 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -203,6 +203,7 @@ struct _virQEMUDriverConfig {
unsigned int glusterDebugLevel;
char *memoryBackingDir;
+ bool memoryPredictableFileNames;
bool vxhsTLS;
char *vxhsTLSx509certdir;
@@ -364,6 +365,13 @@ int qemuGetDomainHupageMemPath(const virDomainDef *def,
unsigned long long pagesize,
char **memPath);
-int qemuGetMemoryBackingPath(virQEMUDriverConfigPtr cfg,
+int qemuGetMemoryBackingBasePath(virQEMUDriverConfigPtr cfg,
+ char **path);
+int qemuGetMemoryBackingDomainPath(const virDomainDef *def,
+ virQEMUDriverConfigPtr cfg,
+ char **path);
+int qemuGetMemoryBackingPath(const virDomainDef *def,
+ virQEMUDriverConfigPtr cfg,
+ const char *alias,
char **memPath);
#endif /* __QEMUD_CONF_H */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dacfca9a9..7bdefd7e8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -630,6 +630,7 @@ qemuStateInitialize(bool privileged,
uid_t run_uid = -1;
gid_t run_gid = -1;
char *hugepagePath = NULL;
+ char *memoryBackingPath = NULL;
size_t i;
if (VIR_ALLOC(qemu_driver) < 0)
@@ -888,6 +889,23 @@ qemuStateInitialize(bool privileged,
VIR_FREE(hugepagePath);
}
+ if (cfg->memoryPredictableFileNames) {
+ if (qemuGetMemoryBackingBasePath(cfg, &memoryBackingPath) < 0)
+ goto error;
+
+ if (virFileMakePath(memoryBackingPath) < 0) {
+ virReportSystemError(errno,
+ _("unable to create memory backing path %s"),
+ memoryBackingPath);
+ goto error;
+ }
+ if (privileged &&
+ virFileUpdatePerm(memoryBackingPath,
+ 0, S_IXGRP | S_IXOTH) < 0)
+ goto error;
+ VIR_FREE(memoryBackingPath);
+ }
+
if (!(qemu_driver->closeCallbacks = virCloseCallbacksNew()))
goto error;
@@ -945,6 +963,7 @@ qemuStateInitialize(bool privileged,
virObjectUnref(conn);
VIR_FREE(driverConf);
VIR_FREE(hugepagePath);
+ VIR_FREE(memoryBackingPath);
qemuStateCleanup();
return -1;
}
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 91f7f9ed6..5701c033b 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2077,7 +2077,7 @@ qemuDomainAttachMemory(virQEMUDriverPtr driver,
priv->qemuCaps, vm->def, mem, NULL, true) <
0)
goto cleanup;
- if (qemuProcessBuildDestroyHugepagesPath(driver, vm, mem, true) < 0)
+ if (qemuProcessBuildDestroyMemoryPaths(driver, vm, mem, true) < 0)
goto cleanup;
if (qemuDomainNamespaceSetupMemory(driver, vm, mem) < 0)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index fdc868912..5dea02718 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3324,60 +3324,121 @@ qemuProcessNeedHugepagesPath(virDomainDefPtr def,
}
+static bool
+qemuProcessNeedMemoryBackingPath(virDomainDefPtr def,
+ virQEMUDriverConfigPtr cfg,
+ virDomainMemoryDefPtr mem)
+{
+ size_t i;
+ size_t numaNodes;
+
+ if (!cfg->memoryPredictableFileNames)
+ return false;
+
+ if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE ||
+ def->mem.access != VIR_DOMAIN_MEMORY_ACCESS_DEFAULT)
+ return true;
+
+ numaNodes = virDomainNumaGetNodeCount(def->numa);
+ for (i = 0; i < numaNodes; i++) {
+ if (virDomainNumaGetNodeMemoryAccessMode(def->numa, i)
+ != VIR_DOMAIN_MEMORY_ACCESS_DEFAULT)
+ return true;
+ }
+
+ if (mem &&
+ mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM &&
+ (mem->access != VIR_DOMAIN_MEMORY_ACCESS_DEFAULT ||
+ (mem->targetNode >= 0 &&
+ virDomainNumaGetNodeMemoryAccessMode(def->numa, mem->targetNode)
+ != VIR_DOMAIN_MEMORY_ACCESS_DEFAULT)))
+ return true;
+
+ return false;
+}
+
+
+static int
+qemuProcessBuildDestroyMemoryPathsImpl(virQEMUDriverPtr driver,
+ virDomainDefPtr def,
+ const char *path,
+ bool build)
+{
+ if (build) {
+ if (virFileExists(path))
+ return 0;
+
+ if (virFileMakePathWithMode(path, 0700) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create %s"),
+ path);
+ return -1;
+ }
+
+ if (qemuSecurityDomainSetPathLabel(driver->securityManager,
+ def, path) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to label %s"), path);
+ return -1;
+ }
+ } else {
+ if (rmdir(path) < 0 &&
+ errno != ENOENT)
+ VIR_WARN("Unable to remove hugepage path: %s (errno=%d)",
+ path, errno);
+ }
+
+ return 0;
+}
+
+
int
-qemuProcessBuildDestroyHugepagesPath(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
- virDomainMemoryDefPtr mem,
- bool build)
+qemuProcessBuildDestroyMemoryPaths(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainMemoryDefPtr mem,
+ bool build)
{
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
- char *hugepagePath = NULL;
+ char *path = NULL;
size_t i;
- bool shouldBuild = false;
+ bool shouldBuildHP = false;
+ bool shouldBuildMB = false;
int ret = -1;
- if (build)
- shouldBuild = qemuProcessNeedHugepagesPath(vm->def, mem);
+ if (build) {
+ shouldBuildHP = qemuProcessNeedHugepagesPath(vm->def, mem);
+ shouldBuildMB = qemuProcessNeedMemoryBackingPath(vm->def, cfg, mem);
+ }
- if (!build || shouldBuild) {
+ if (!build || shouldBuildHP) {
for (i = 0; i < cfg->nhugetlbfs; i++) {
- VIR_FREE(hugepagePath);
- hugepagePath = qemuGetDomainHugepagePath(vm->def,
&cfg->hugetlbfs[i]);
+ path = qemuGetDomainHugepagePath(vm->def, &cfg->hugetlbfs[i]);
- if (!hugepagePath)
+ if (!path)
goto cleanup;
- if (build) {
- if (virFileExists(hugepagePath)) {
- ret = 0;
- goto cleanup;
- }
-
- if (virFileMakePathWithMode(hugepagePath, 0700) < 0) {
- virReportSystemError(errno,
- _("Unable to create %s"),
- hugepagePath);
- goto cleanup;
- }
+ if (qemuProcessBuildDestroyMemoryPathsImpl(driver, vm->def,
+ path, build) < 0)
+ goto cleanup;
- if (qemuSecurityDomainSetPathLabel(driver->securityManager,
- vm->def, hugepagePath) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Unable to set huge path in
security driver"));
- goto cleanup;
- }
- } else {
- if (rmdir(hugepagePath) < 0 &&
- errno != ENOENT)
- VIR_WARN("Unable to remove hugepage path: %s (errno=%d)",
- hugepagePath, errno);
- }
+ VIR_FREE(path);
}
}
+ if (!build || shouldBuildMB) {
+ if (qemuGetMemoryBackingDomainPath(vm->def, cfg, &path) < 0)
+ goto cleanup;
+
+ if (qemuProcessBuildDestroyMemoryPathsImpl(driver, vm->def,
+ path, build) < 0)
+ goto cleanup;
+
+ VIR_FREE(path);
+ }
+
ret = 0;
cleanup:
- VIR_FREE(hugepagePath);
+ VIR_FREE(path);
virObjectUnref(cfg);
return ret;
}
@@ -5550,7 +5611,7 @@ qemuProcessPrepareHost(virQEMUDriverPtr driver,
NULL) < 0)
goto cleanup;
- if (qemuProcessBuildDestroyHugepagesPath(driver, vm, NULL, true) < 0)
+ if (qemuProcessBuildDestroyMemoryPaths(driver, vm, NULL, true) < 0)
goto cleanup;
/* Ensure no historical cgroup for this VM is lying around bogus
@@ -6254,7 +6315,7 @@ void qemuProcessStop(virQEMUDriverPtr driver,
goto endjob;
}
- qemuProcessBuildDestroyHugepagesPath(driver, vm, NULL, false);
+ qemuProcessBuildDestroyMemoryPaths(driver, vm, NULL, false);
vm->def->id = -1;
@@ -7112,7 +7173,7 @@ qemuProcessReconnect(void *opaque)
goto cleanup;
}
- if (qemuProcessBuildDestroyHugepagesPath(driver, obj, NULL, true) < 0)
+ if (qemuProcessBuildDestroyMemoryPaths(driver, obj, NULL, true) < 0)
goto error;
if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps,
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index 814b86d8a..cd9a72031 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -38,10 +38,10 @@ int qemuProcessStopCPUs(virQEMUDriverPtr driver,
virDomainPausedReason reason,
qemuDomainAsyncJob asyncJob);
-int qemuProcessBuildDestroyHugepagesPath(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
- virDomainMemoryDefPtr mem,
- bool build);
+int qemuProcessBuildDestroyMemoryPaths(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainMemoryDefPtr mem,
+ bool build);
void qemuProcessAutostartAll(virQEMUDriverPtr driver);
void qemuProcessReconnectAll(virConnectPtr conn, virQEMUDriverPtr driver);
diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in
index 688e5b9fd..2f0a1277d 100644
--- a/src/qemu/test_libvirtd_qemu.aug.in
+++ b/src/qemu/test_libvirtd_qemu.aug.in
@@ -100,3 +100,4 @@ module Test_libvirtd_qemu =
{ "1" = "mount" }
}
{ "memory_backing_dir" = "/var/lib/libvirt/qemu/ram" }
+{ "memory_predictable_file_names" = "1" }
--
2.13.6