Skip to content

Commit 6c49e5f

Browse files
d-tatianindaztucker
authored andcommitted
Add support for locking memory on Linux
Linux wakes up kcompactd threads in order to make more contiguous memory available on the system, it does this by migrating live movable pages (actively modifying live processes' page tables and constantly flooding them with page invalidation IPIs, which can be up to millions per second), which causes the process to become unresponsive for up to seconds or even minutes in some severe cases. In case of sshd, we want to always be able to connect to the system, even if it's under heavy kcompactd load. Introduce an option to protect sshd and its children sessions from being compacted by kcompactd (this works in cojunction with compact_unevictable_allowed = 0). Note that we depend on MCL_ONFAULT being available, which was introduced in linux 4.4. MCL_ONFAULT allows the system to lock pages lazily, thus drastically reducing memory usage of a locked process (without MCL_ONFAULT, every existing mapping in the process is instantly write-faulted).
1 parent fdc4853 commit 6c49e5f

File tree

4 files changed

+52
-0
lines changed

4 files changed

+52
-0
lines changed

configure.ac

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,27 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
928928
AC_DEFINE([_PATH_BTMP], ["/var/log/btmp"], [log for bad login attempts])
929929
AC_DEFINE([USE_BTMP])
930930
AC_DEFINE([LINUX_OOM_ADJUST], [1], [Adjust Linux out-of-memory killer])
931+
AC_ARG_WITH([linux-memlock-onfault],
932+
[ --with-linux-memlock-onfault Enables memory locking on Linux],
933+
[
934+
if test "x$withval" != "xno" ; then
935+
AC_MSG_CHECKING([for MCL_ONFAULT])
936+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
937+
[[ #include <sys/mman.h> ]],
938+
[[ mlockall(MCL_FUTURE | MCL_ONFAULT); ]],
939+
)],
940+
[
941+
AC_MSG_RESULT([supported])
942+
AC_DEFINE([LINUX_MEMLOCK_ONFAULT], [1],
943+
[Lock all memory to protect sshd against Linux kcompactd] )],
944+
[
945+
AC_MSG_RESULT([not supported])
946+
AC_MSG_ERROR([MCL_ONFAULT is not available on your system])
947+
])
948+
fi
949+
],
950+
)
951+
931952
AC_DEFINE([SYSTEMD_NOTIFY], [1], [Have sshd notify systemd on start/reload])
932953
inet6_default_4in6=yes
933954
case `uname -r` in

openbsd-compat/port-linux.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,19 @@ oom_adjust_restore(void)
319319
}
320320
#endif /* LINUX_OOM_ADJUST */
321321

322+
#ifdef LINUX_MEMLOCK_ONFAULT
323+
#include <sys/mman.h>
324+
325+
void
326+
memlock_onfault_setup(void)
327+
{
328+
if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) < 0)
329+
verbose("unable to lock memory: %s", strerror(errno));
330+
else
331+
debug("memory locked");
332+
}
333+
#endif /* LINUX_MEMLOCK_ONFAULT */
334+
322335
#ifdef SYSTEMD_NOTIFY
323336

324337
static void ssh_systemd_notify(const char *, ...)

openbsd-compat/port-linux.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ void oom_adjust_restore(void);
3030
void oom_adjust_setup(void);
3131
#endif
3232

33+
#ifdef LINUX_MEMLOCK_ONFAULT
34+
void memlock_onfault_setup(void);
35+
#endif
36+
3337
#ifdef SYSTEMD_NOTIFY
3438
void ssh_systemd_notify_ready(void);
3539
void ssh_systemd_notify_reload(void);

platform-listen.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ platform_pre_listen(void)
3434
/* Adjust out-of-memory killer so listening process is not killed */
3535
oom_adjust_setup();
3636
#endif
37+
#ifdef LINUX_MEMLOCK_ONFAULT
38+
/*
39+
* Protect ourselves against kcompactd so that we are able to process
40+
* new connections while it is active and migrating pages.
41+
*/
42+
memlock_onfault_setup();
43+
#endif
3744
}
3845

3946
void
@@ -84,4 +91,11 @@ platform_post_fork_child(void)
8491

8592
void platform_pre_session_start(void)
8693
{
94+
#ifdef LINUX_MEMLOCK_ONFAULT
95+
/*
96+
* Memlock flags are dropped on fork, lock the memory again so that the
97+
* child connection is also protected against kcompactd.
98+
*/
99+
memlock_onfault_setup();
100+
#endif
87101
}

0 commit comments

Comments
 (0)