[ovs-dev] [PATCH 3/3] util: munlockall() and retry when locked memory allocation fails

Ben Pfaff blp at ovn.org
Fri Mar 26 18:30:24 UTC 2021


From: James Page <james.page at ubuntu.com>

Normally when OVS runs on a server the effective system limit for
locked memory is unlimited as the ovs-vswitchd runs as the root
user in the root namespace of the server.

When OVS is run in a non-priviledged container a system limit will
apply and its possible that this limit will be reached during
normal operation.

If this occurs unlock all memory and re-attempt (re)allocation of
memory rather than fail and abort.

If this subsequent attempt also fails abort the process as before.

Signed-off-by: James Page <james.page at ubuntu.com>
[blp at ovn.org adapted to cover more cases]
Signed-off-by: Ben Pfaff <blp at ovn.org>
---
 lib/stream-ssl.c |  4 ++--
 lib/util.c       | 40 +++++++++++++++++++++++++++++++---------
 lib/util.h       |  3 ++-
 3 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index 078fcbc3aa4a..cd906e9e7b1d 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -1096,10 +1096,10 @@ tmp_dh_callback(SSL *ssl OVS_UNUSED, int is_export OVS_UNUSED, int keylength)
 
     for (dh = dh_table; dh < &dh_table[ARRAY_SIZE(dh_table)]; dh++) {
         if (dh->keylength == keylength) {
-            if (!dh->dh) {
+            while (!dh->dh) {
                 dh->dh = dh->constructor();
                 if (!dh->dh) {
-                    out_of_memory();
+                    munlockall_or_out_of_memory();
                 }
             }
             return dh->dh;
diff --git a/lib/util.c b/lib/util.c
index 1195c7982118..e9c5c40094bc 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -41,6 +41,9 @@
 #ifdef _WIN32
 #include <shlwapi.h>
 #endif
+#ifdef HAVE_MLOCKALL
+#include <sys/mman.h>
+#endif
 
 VLOG_DEFINE_THIS_MODULE(util);
 
@@ -103,6 +106,12 @@ set_memory_locked(void)
     is_memory_locked = true;
 }
 
+void
+set_memory_unlocked(void)
+{
+    is_memory_locked = false;
+}
+
 bool
 memory_locked(void)
 {
@@ -110,8 +119,17 @@ memory_locked(void)
 }
 
 void
-out_of_memory(void)
-{
+munlockall_or_out_of_memory(void)
+{
+#ifdef HAVE_MLOCKALL
+    if (errno == EAGAIN && memory_locked()) {
+        /* Locked memory allocation failed
+         * unlock and try again */
+        munlockall();
+        set_memory_unlocked();
+        return;
+    }
+#endif // HAVE_MLOCKALL
     ovs_abort(0, "virtual memory exhausted");
 }
 
@@ -120,7 +138,8 @@ xcalloc__(size_t count, size_t size)
 {
     void *p = count && size ? calloc(count, size) : malloc(1);
     if (p == NULL) {
-        out_of_memory();
+        munlockall_or_out_of_memory();
+        return xcalloc__(count, size);
     }
     return p;
 }
@@ -136,7 +155,8 @@ xmalloc__(size_t size)
 {
     void *p = malloc(size ? size : 1);
     if (p == NULL) {
-        out_of_memory();
+        munlockall_or_out_of_memory();
+        return xmalloc__(size);
     }
     return p;
 }
@@ -144,11 +164,12 @@ xmalloc__(size_t size)
 void *
 xrealloc__(void *p, size_t size)
 {
-    p = realloc(p, size ? size : 1);
-    if (p == NULL) {
-        out_of_memory();
+    void *rp = realloc(p, size ? size : 1);
+    if (rp == NULL) {
+        munlockall_or_out_of_memory();
+        return xrealloc__(p, size);
     }
-    return p;
+    return rp;
 }
 
 void *
@@ -253,7 +274,8 @@ xmalloc_size_align(size_t size, size_t alignment)
     COVERAGE_INC(util_xalloc);
     error = posix_memalign(&p, alignment, size ? size : 1);
     if (error != 0) {
-        out_of_memory();
+        munlockall_or_out_of_memory();
+        return xmalloc_size_align(size, alignment);
     }
     return p;
 #else
diff --git a/lib/util.h b/lib/util.h
index 9c2b14fae304..a1958fcf93b4 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -144,8 +144,9 @@ void ctl_timeout_setup(unsigned int secs);
 void ovs_print_version(uint8_t min_ofp, uint8_t max_ofp);
 
 void set_memory_locked(void);
+void set_memory_unlocked(void);
 bool memory_locked(void);
-OVS_NO_RETURN void out_of_memory(void);
+void munlockall_or_out_of_memory(void);
 
 /* Allocation wrappers that abort if memory is exhausted. */
 void *xmalloc(size_t) MALLOC_LIKE;
-- 
2.29.2



More information about the dev mailing list