38f2fd
From dfdc5b0fc1fdf8c6d122df9578912ed90bfbabb4 Mon Sep 17 00:00:00 2001
38f2fd
Message-Id: <dfdc5b0fc1fdf8c6d122df9578912ed90bfbabb4@dist-git>
38f2fd
From: Peter Krempa <pkrempa@redhat.com>
38f2fd
Date: Thu, 12 Nov 2015 08:40:43 +0100
38f2fd
Subject: [PATCH] qemu: hotplug: Fix mlock limit handling on memory hotplug
38f2fd
38f2fd
https://bugzilla.redhat.com/show_bug.cgi?id=1280420
38f2fd
38f2fd
If mlock is required either due to use of VFIO hostdevs or due to the
38f2fd
fact that it's enabled it needs to be tweaked prior to adding new memory
38f2fd
or after removing a module. Add a helper to determine when it's
38f2fd
necessary and reuse it both on hotplug and hotunplug.
38f2fd
38f2fd
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1273491
38f2fd
(cherry picked from commit ec90b34acf7cf7d06a63908c39e21b63382a1967)
38f2fd
38f2fd
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
38f2fd
---
38f2fd
 src/qemu/qemu_domain.c  | 27 +++++++++++++++++++++++++++
38f2fd
 src/qemu/qemu_domain.h  |  1 +
38f2fd
 src/qemu/qemu_hotplug.c | 41 ++++++++++++++++++++++++++++++++++-------
38f2fd
 3 files changed, 62 insertions(+), 7 deletions(-)
38f2fd
38f2fd
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
38f2fd
index 944817d..1f206fa 100644
38f2fd
--- a/src/qemu/qemu_domain.c
38f2fd
+++ b/src/qemu/qemu_domain.c
38f2fd
@@ -3449,3 +3449,30 @@ qemuDomainGetMlockLimitBytes(virDomainDefPtr def)
38f2fd
 
38f2fd
     return memKB << 10;
38f2fd
 }
38f2fd
+
38f2fd
+
38f2fd
+/**
38f2fd
+ * @def: domain definition
38f2fd
+ *
38f2fd
+ * Returns ture if the locked memory limit needs to be set or updated due to
38f2fd
+ * configuration or passthrough devices.
38f2fd
+ * */
38f2fd
+bool
38f2fd
+qemuDomainRequiresMlock(virDomainDefPtr def)
38f2fd
+{
38f2fd
+    size_t i;
38f2fd
+
38f2fd
+    if (def->mem.locked)
38f2fd
+        return true;
38f2fd
+
38f2fd
+    for (i = 0; i < def->nhostdevs; i++) {
38f2fd
+        virDomainHostdevDefPtr dev = def->hostdevs[i];
38f2fd
+
38f2fd
+        if (dev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
38f2fd
+            dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
38f2fd
+            dev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
38f2fd
+            return true;
38f2fd
+    }
38f2fd
+
38f2fd
+    return false;
38f2fd
+}
38f2fd
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
38f2fd
index 54e7cd9..32f713b 100644
38f2fd
--- a/src/qemu/qemu_domain.h
38f2fd
+++ b/src/qemu/qemu_domain.h
38f2fd
@@ -476,5 +476,6 @@ int qemuDomainUpdateCurrentMemorySize(virQEMUDriverPtr driver,
38f2fd
                                       virDomainObjPtr vm);
38f2fd
 
38f2fd
 unsigned long long qemuDomainGetMlockLimitBytes(virDomainDefPtr def);
38f2fd
+bool qemuDomainRequiresMlock(virDomainDefPtr def);
38f2fd
 
38f2fd
 #endif /* __QEMU_DOMAIN_H__ */
38f2fd
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
38f2fd
index d96f572..70aece4 100644
38f2fd
--- a/src/qemu/qemu_hotplug.c
38f2fd
+++ b/src/qemu/qemu_hotplug.c
38f2fd
@@ -1768,6 +1768,7 @@ qemuDomainAttachMemory(virQEMUDriverPtr driver,
38f2fd
     virJSONValuePtr props = NULL;
38f2fd
     virObjectEventPtr event;
38f2fd
     bool fix_balloon = false;
38f2fd
+    bool mlock = false;
38f2fd
     int id;
38f2fd
     int ret = -1;
38f2fd
 
38f2fd
@@ -1802,16 +1803,26 @@ qemuDomainAttachMemory(virQEMUDriverPtr driver,
38f2fd
         goto cleanup;
38f2fd
     }
38f2fd
 
38f2fd
+    mlock = qemuDomainRequiresMlock(vm->def);
38f2fd
+
38f2fd
+    if (mlock &&
38f2fd
+        virProcessSetMaxMemLock(vm->pid,
38f2fd
+                                qemuDomainGetMlockLimitBytes(vm->def)) < 0) {
38f2fd
+        mlock = false;
38f2fd
+        virJSONValueFree(props);
38f2fd
+        goto removedef;
38f2fd
+    }
38f2fd
+
38f2fd
     qemuDomainObjEnterMonitor(driver, vm);
38f2fd
     if (qemuMonitorAddObject(priv->mon, backendType, objalias, props) < 0)
38f2fd
-        goto removedef;
38f2fd
+        goto exit_monitor;
38f2fd
 
38f2fd
     if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
38f2fd
         virErrorPtr err = virSaveLastError();
38f2fd
         ignore_value(qemuMonitorDelObject(priv->mon, objalias));
38f2fd
         virSetError(err);
38f2fd
         virFreeError(err);
38f2fd
-        goto removedef;
38f2fd
+        goto exit_monitor;
38f2fd
     }
38f2fd
 
38f2fd
     if (qemuDomainObjExitMonitor(driver, vm) < 0) {
38f2fd
@@ -1846,17 +1857,27 @@ qemuDomainAttachMemory(virQEMUDriverPtr driver,
38f2fd
     virDomainMemoryDefFree(mem);
38f2fd
     return ret;
38f2fd
 
38f2fd
+ exit_monitor:
38f2fd
+    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
38f2fd
+        mem = NULL;
38f2fd
+        goto audit;
38f2fd
+    }
38f2fd
+
38f2fd
  removedef:
38f2fd
-    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
38f2fd
-        mem = NULL;
38f2fd
-        goto audit;
38f2fd
-    }
38f2fd
-
38f2fd
     if ((id = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
38f2fd
         mem = virDomainMemoryRemove(vm->def, id);
38f2fd
     else
38f2fd
         mem = NULL;
38f2fd
 
38f2fd
+    /* reset the mlock limit */
38f2fd
+    if (mlock) {
38f2fd
+        virErrorPtr err = virSaveLastError();
38f2fd
+        ignore_value(virProcessSetMaxMemLock(vm->pid,
38f2fd
+                                             qemuDomainGetMlockLimitBytes(vm->def)));
38f2fd
+        virSetError(err);
38f2fd
+        virFreeError(err);
38f2fd
+    }
38f2fd
+
38f2fd
     goto audit;
38f2fd
 }
38f2fd
 
38f2fd
@@ -2952,6 +2973,12 @@ qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
38f2fd
         virDomainMemoryRemove(vm->def, idx);
38f2fd
 
38f2fd
     virDomainMemoryDefFree(mem);
38f2fd
+
38f2fd
+    /* decrease the mlock limit after memory unplug if necessary */
38f2fd
+    if (qemuDomainRequiresMlock(vm->def))
38f2fd
+        ignore_value(virProcessSetMaxMemLock(vm->pid,
38f2fd
+                                             qemuDomainGetMlockLimitBytes(vm->def)));
38f2fd
+
38f2fd
     return 0;
38f2fd
 }
38f2fd
 
38f2fd
-- 
38f2fd
2.6.3
38f2fd