From 1a94f1db6b5cb2de2cf1f1f263d6ab0a94e5f518 Mon Sep 17 00:00:00 2001 From: Michael Fenn Date: Mon, 22 Apr 2013 12:10:34 -0400 Subject: [PATCH 1/2] add mlockall option to munged This patch adds a command line option (-M, --mlockall) to munged that, when activated, causes it to call mlockall(MCL_CURRENT|MCL_FUTURE) during the init process. Locking memory is beneficial during situations where the machine is under high memory and disk presure because it helps munged stay responsive. --- src/munged/conf.c | 10 +++++++++- src/munged/conf.h | 1 + src/munged/munged.8.in | 4 ++++ src/munged/munged.c | 13 +++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/munged/conf.c b/src/munged/conf.c index 1fa00e63..3726d546 100644 --- a/src/munged/conf.c +++ b/src/munged/conf.c @@ -59,7 +59,7 @@ * Command-Line Options *****************************************************************************/ -const char * const short_opts = ":hLVfFS:"; +const char * const short_opts = ":hLVfFS:M"; #include struct option long_opts[] = { @@ -69,6 +69,7 @@ struct option long_opts[] = { { "force", no_argument, NULL, 'f' }, { "foreground", no_argument, NULL, 'F' }, { "socket", required_argument, NULL, 'S' }, + { "mlockall", no_argument, NULL, 'M' }, { "advice", no_argument, NULL, 'A' }, { "key-file", required_argument, NULL, '0' }, { "num-threads", required_argument, NULL, '1' }, @@ -113,6 +114,7 @@ create_conf (void) conf->got_clock_skew = 1; conf->got_force = 0; conf->got_foreground = 0; + conf->got_mlockall = 0; conf->got_group_stat = !! MUNGE_GROUP_STAT_FLAG; conf->got_root_auth = !! MUNGE_AUTH_ROOT_ALLOW_FLAG; conf->got_socket_retry = !! MUNGE_SOCKET_RETRY_FLAG; @@ -281,6 +283,9 @@ parse_cmdline (conf_t conf, int argc, char **argv) log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy socket name string"); break; + case 'M': + conf->got_mlockall = 1; + break; case 'A': printf ("Don't Panic!\n"); exit (42); @@ -424,6 +429,9 @@ display_help (char *prog) printf (" %*s %s\n", w, "-F, --foreground", "Run process in the foreground (do not fork)"); + printf (" %*s %s\n", w, "-M, --mlockall", + "Lock all pages in memory upon startup"); + printf (" %*s %s [%s]\n", w, "-S, --socket=PATH", "Specify local socket", MUNGE_SOCKET_NAME); diff --git a/src/munged/conf.h b/src/munged/conf.h index 9e3be36c..1fb6f913 100644 --- a/src/munged/conf.h +++ b/src/munged/conf.h @@ -49,6 +49,7 @@ struct conf { unsigned got_root_auth:1; /* flag if root can decode any cred */ unsigned got_socket_retry:1; /* flag for allowing decode retries */ unsigned got_syslog:1; /* flag if logging to syslog instead */ + unsigned got_mlockall:1; /* flag if munged should lock mem */ munge_cipher_t def_cipher; /* default cipher type */ munge_zip_t def_zip; /* default compression type */ munge_mac_t def_mac; /* default message auth code type */ diff --git a/src/munged/munged.8.in b/src/munged/munged.8.in index 6d439f14..9fd511c6 100644 --- a/src/munged/munged.8.in +++ b/src/munged/munged.8.in @@ -76,6 +76,10 @@ file/directory permissions. .BI "-F, --foreground" Run the daemon in the foreground. .TP +.BI "-M, --mlockall" +Lock all pages into memory upon daemon startup. This can help keep munged +responsive when the system is under heavy memory pressure. +.TP .BI "-S, --socket " path Specify the local domain socket for communicating with clients. .TP diff --git a/src/munged/munged.c b/src/munged/munged.c index 4f53f89b..abc43521 100644 --- a/src/munged/munged.c +++ b/src/munged/munged.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* include before resource.h for bsd */ #include #include @@ -126,6 +127,18 @@ main (int argc, char *argv[]) lookup_ip_addr (conf); write_pidfile (conf->pidfile_name, conf->got_force); + if (conf->got_mlockall){ +#ifdef _POSIX_MEMLOCK + if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) { + log_msg (LOG_ERR, "%s (pid %d) could not lock pages", + META_ALIAS, (int) getpid ()); + } +#else + log_msg (LOG_ERR, "%s (pid %d) does not appear to have mlockall()", + META_ALIAS, (int) getpid ()); +#endif /* _POSIX_MEMLOCK */ + } + crypto_init (); if (random_init (conf->seed_name) < 0) { if (conf->seed_name) { From b9d269080950c7d4f319d15be7f3682c88f9dcd1 Mon Sep 17 00:00:00 2001 From: Chris Dunlap Date: Wed, 24 Apr 2013 21:13:26 -0700 Subject: [PATCH 2/2] cleanup "--mlockall" cmdline opt to munged This adjusts the issue-22 patch from Michael Fenn (1a94f1db6b5c) for adding the "--mlockall" command-line option to munged. The call to mlockall() is moved out of main() and into the newly added lock_memory(). In addition, EAGAIN is tested for, in which case mlockall() is retried up to max_tries (currently 10 times) since this error is presumably transient. But note that mlockall(MCL_CURRENT) consistently fails with EAGAIN on OpenBSD 5.2, although it appears to work on earlier and later versions. The error message for when mlockall() fails (or is not implemented, as is the case on AIX 5.2) is changed from being non-fatal to fatal. If the --mlockall option is specified, it either succeeds or the daemon terminates. The #ifdef condition _POSIX_MEMLOCK is replaced with HAVE_MLOCKALL since autoconf tests are already used throughout. Tested on: - AIX 5.2 (ENOSYS) - Debian 6 - FreeBSD 9.1 - GNU/kFreeBSD 8.1 - NetBSD 6.0 - OpenBSD 5.3, 5.2 (EAGAIN), 5.1 - SunOS 5.10 --- config/config.h.in | 3 +++ configure | 1 + configure.ac | 1 + src/munged/conf.c | 14 ++++++------ src/munged/conf.h | 2 +- src/munged/munged.8.in | 7 ++++-- src/munged/munged.c | 50 ++++++++++++++++++++++++++++++++---------- 7 files changed, 56 insertions(+), 22 deletions(-) diff --git a/config/config.h.in b/config/config.h.in index 6d14e878..c2ebcaf9 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -111,6 +111,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H +/* Define to 1 if you have the `mlockall' function. */ +#undef HAVE_MLOCKALL + /* Define to 1 if you want to use the OpenSSL cryptographic library. */ #undef HAVE_OPENSSL diff --git a/configure b/configure index f6fe09f9..34884bfe 100755 --- a/configure +++ b/configure @@ -13059,6 +13059,7 @@ fi ## for ac_func in \ localtime_r \ + mlockall \ sysconf \ do : diff --git a/configure.ac b/configure.ac index e3cf8ad0..674d7af9 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,7 @@ AC_CHECK_TYPES(socklen_t, [], [], [#include ## AC_CHECK_FUNCS( \ localtime_r \ + mlockall \ sysconf \ ) AC_REPLACE_FUNCS( \ diff --git a/src/munged/conf.c b/src/munged/conf.c index 3726d546..3e661833 100644 --- a/src/munged/conf.c +++ b/src/munged/conf.c @@ -59,7 +59,7 @@ * Command-Line Options *****************************************************************************/ -const char * const short_opts = ":hLVfFS:M"; +const char * const short_opts = ":hLVfFMS:"; #include struct option long_opts[] = { @@ -68,8 +68,8 @@ struct option long_opts[] = { { "version", no_argument, NULL, 'V' }, { "force", no_argument, NULL, 'f' }, { "foreground", no_argument, NULL, 'F' }, - { "socket", required_argument, NULL, 'S' }, { "mlockall", no_argument, NULL, 'M' }, + { "socket", required_argument, NULL, 'S' }, { "advice", no_argument, NULL, 'A' }, { "key-file", required_argument, NULL, '0' }, { "num-threads", required_argument, NULL, '1' }, @@ -114,8 +114,8 @@ create_conf (void) conf->got_clock_skew = 1; conf->got_force = 0; conf->got_foreground = 0; - conf->got_mlockall = 0; conf->got_group_stat = !! MUNGE_GROUP_STAT_FLAG; + conf->got_mlockall = 0; conf->got_root_auth = !! MUNGE_AUTH_ROOT_ALLOW_FLAG; conf->got_socket_retry = !! MUNGE_SOCKET_RETRY_FLAG; conf->got_syslog = 0; @@ -276,6 +276,9 @@ parse_cmdline (conf_t conf, int argc, char **argv) case 'F': conf->got_foreground = 1; break; + case 'M': + conf->got_mlockall = 1; + break; case 'S': if (conf->socket_name) free (conf->socket_name); @@ -283,9 +286,6 @@ parse_cmdline (conf_t conf, int argc, char **argv) log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy socket name string"); break; - case 'M': - conf->got_mlockall = 1; - break; case 'A': printf ("Don't Panic!\n"); exit (42); @@ -430,7 +430,7 @@ display_help (char *prog) "Run process in the foreground (do not fork)"); printf (" %*s %s\n", w, "-M, --mlockall", - "Lock all pages in memory upon startup"); + "Lock all pages in memory"); printf (" %*s %s [%s]\n", w, "-S, --socket=PATH", "Specify local socket", MUNGE_SOCKET_NAME); diff --git a/src/munged/conf.h b/src/munged/conf.h index 1fb6f913..0215de1a 100644 --- a/src/munged/conf.h +++ b/src/munged/conf.h @@ -46,10 +46,10 @@ struct conf { unsigned got_force:1; /* flag for FORCE option */ unsigned got_foreground:1; /* flag for FOREGROUND option */ unsigned got_group_stat:1; /* flag for gids stat'ing /etc/group */ + unsigned got_mlockall:1; /* flag for locking all memory pages */ unsigned got_root_auth:1; /* flag if root can decode any cred */ unsigned got_socket_retry:1; /* flag for allowing decode retries */ unsigned got_syslog:1; /* flag if logging to syslog instead */ - unsigned got_mlockall:1; /* flag if munged should lock mem */ munge_cipher_t def_cipher; /* default cipher type */ munge_zip_t def_zip; /* default compression type */ munge_mac_t def_mac; /* default message auth code type */ diff --git a/src/munged/munged.8.in b/src/munged/munged.8.in index 9fd511c6..766d7073 100644 --- a/src/munged/munged.8.in +++ b/src/munged/munged.8.in @@ -77,8 +77,11 @@ file/directory permissions. Run the daemon in the foreground. .TP .BI "-M, --mlockall" -Lock all pages into memory upon daemon startup. This can help keep munged -responsive when the system is under heavy memory pressure. +Lock all current and future pages in the virtual memory address space. +Access to locked pages will never be delayed by a page fault. This can +improve performance and help the daemon remain responsive when the system +is under heavy memory pressure. This typically requires root privileges +or the CAP_IPC_LOCK capability. .TP .BI "-S, --socket " path Specify the local domain socket for communicating with clients. diff --git a/src/munged/munged.c b/src/munged/munged.c index abc43521..65b07ffd 100644 --- a/src/munged/munged.c +++ b/src/munged/munged.c @@ -37,7 +37,9 @@ #include #include #include +#if HAVE_MLOCKALL #include +#endif /* HAVE_MLOCKALL */ #include /* include before resource.h for bsd */ #include #include @@ -75,6 +77,7 @@ static void hup_handler (int signum); static void exit_handler (int signum); static void segv_handler (int signum); static void write_pidfile (const char *pidfile, int got_force); +static void lock_memory (void); static void sock_create (conf_t conf); static void sock_lock (conf_t conf); static int set_file_lock (int fd); @@ -126,19 +129,9 @@ main (int argc, char *argv[]) handle_signals (); lookup_ip_addr (conf); write_pidfile (conf->pidfile_name, conf->got_force); - - if (conf->got_mlockall){ -#ifdef _POSIX_MEMLOCK - if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) { - log_msg (LOG_ERR, "%s (pid %d) could not lock pages", - META_ALIAS, (int) getpid ()); - } -#else - log_msg (LOG_ERR, "%s (pid %d) does not appear to have mlockall()", - META_ALIAS, (int) getpid ()); -#endif /* _POSIX_MEMLOCK */ + if (conf->got_mlockall) { + lock_memory (); } - crypto_init (); if (random_init (conf->seed_name) < 0) { if (conf->seed_name) { @@ -557,6 +550,39 @@ write_pidfile (const char *pidfile, int got_force) } +static void +lock_memory (void) +{ +/* Lock all current and future pages in the virtual memory address space. + * Access to locked pages will never be delayed by a page fault. + * EAGAIN is tested for up to max_tries in case this is a transient error. + * Should there be a nanosleep() between attempts? + */ +#if ! HAVE_MLOCKALL + errno = ENOSYS; + log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock pages in memory"); +#else + int rv; + int i = 0; + const int max_tries = 10; + + while (1) { + i++; + rv = mlockall (MCL_CURRENT | MCL_FUTURE); + if (rv == 0) { + break; + } + if ((errno == EAGAIN) && (i < max_tries)) { + continue; + } + log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock pages in memory"); + } + log_msg (LOG_INFO, "Locked all pages in memory"); +#endif /* ! HAVE_MLOCKALL */ + return; +} + + static void sock_create (conf_t conf) {