Userfaultfd is by default allowed only for privileged processes. Since
libvirt runs QEMU unprivileged, we need to enable unprivileged access to
userfaultfd before starting post-copy migration.
Rather than providing a static sysctl configuration file, we set the
sysctl knob in runtime once post-copy migration is requested. This way
unprivileged_userfaultfd is only enabled once actually used.
https://bugzilla.redhat.com/show_bug.cgi?id=1945420
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
Notes:
Version 2:
- setting unprivileged_userfaultfd only when it is not already enabled
- virReportSystemError replaced with VIR_WARN
src/qemu/qemu_migration_params.c | 42 ++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c
index dbc3219826..9ba4811242 100644
--- a/src/qemu/qemu_migration_params.c
+++ b/src/qemu/qemu_migration_params.c
@@ -804,6 +804,41 @@ qemuMigrationCapsToJSON(virBitmap *caps,
}
+/**
+ * qemuMigrationParamsEnableUserfaultfd
+ *
+ * Try to enable unprivileged userfaultfd unless it's missing or already
+ * enabled. Only a warning is logged when we cannot enable it, QEMU will
+ * report an error when enabling post-copy migration capability.
+ */
+static void
+qemuMigrationParamsEnableUserfaultfd(void)
+{
+ const char *sysctl = "/proc/sys/vm/unprivileged_userfaultfd";
+ g_autofree char *buf = NULL;
+
+ if (!virFileExists(sysctl))
+ return;
+
+ if (virFileReadAll(sysctl, 10, &buf) < 0) {
+ VIR_WARN("Cannot read unprivileged userfaultfd state");
+ return;
+ }
+
+ if (STREQ(buf, "1\n")) {
+ VIR_DEBUG("Unprivileged userfaultfd already enabled");
+ return;
+ }
+
+ VIR_DEBUG("Enabling unprivileged userfaultfd for post-copy migration");
+
+ if (virFileWriteStr(sysctl, "1", 0) < 0) {
+ VIR_WARN("Failed to enable unprivileged userfaultfd: %s",
+ g_strerror(errno));
+ }
+}
+
+
/**
* qemuMigrationParamsApply
* @driver: qemu driver
@@ -839,6 +874,13 @@ qemuMigrationParamsApply(virQEMUDriver *driver,
goto cleanup;
}
} else {
+ /* userfaultfd may only be enabled for privileged processes by default,
+ * we need to make sure QEMU can use it before enabling post-copy
+ * migration */
+ if (virBitmapIsBitSet(priv->migrationCaps, QEMU_MIGRATION_CAP_POSTCOPY)
&&
+ virBitmapIsBitSet(migParams->caps, QEMU_MIGRATION_CAP_POSTCOPY))
+ qemuMigrationParamsEnableUserfaultfd();
+
if (!(caps = qemuMigrationCapsToJSON(priv->migrationCaps,
migParams->caps)))
goto cleanup;
--
2.34.1