summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Landden <shawn@git.icu>2021-09-25 20:34:24 +0400
committerGitHub <noreply@github.com>2021-09-25 20:34:24 +0400
commita91aef9cf64b259536d0dbfbe4cc58f45a6b594e (patch)
tree1b1d32b8e46dbed7f5430be696b3358429573dc1
parentb83d607b65d879c1bca5933dcc6ca1689b073646 (diff)
parent9699301fc3f16ef34570fa53e0863a2b91cdd3a6 (diff)
downloaddistcc-git-a91aef9cf64b259536d0dbfbe4cc58f45a6b594e.tar.gz
Merge pull request #439 from whitslack/oom-score-adj
distccd: add --oom-score-adj option (Linux only)
-rw-r--r--configure.ac12
-rw-r--r--man/distccd.17
-rw-r--r--src/dopt.c11
-rw-r--r--src/dopt.h4
-rw-r--r--src/prefork.c11
-rw-r--r--src/setuid.c9
6 files changed, 54 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 948946b..4d709e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,6 +15,18 @@ AC_INIT(distcc, 3.4, distcc@lists.samba.org)
AC_CONFIG_HEADERS(src/config.h)
AC_CONFIG_MACRO_DIRS([m4])
+AC_CANONICAL_HOST
+AC_MSG_CHECKING([if the host system type is Linux])
+case "${host_os}" in
+linux*)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_LINUX, 1, [Define to 1 if the host system type is Linux.])
+ ;;
+*)
+ AC_MSG_RESULT(no)
+ ;;
+esac
+
# FreeBSD installs its version of libpopt into /usr/local/, but does
# not put that on the default library and header path.
# Solaris doesn't even ship libpopt. We used to add that path if
diff --git a/man/distccd.1 b/man/distccd.1
index 4ff4e44..9cf8d1c 100644
--- a/man/distccd.1
+++ b/man/distccd.1
@@ -123,6 +123,13 @@ the machine. NICENESS is an increment to the current priority of the
process. The range of priorities depends on the operating system but
is typically 0 to 20. By default the niceness is increased by 5.
.TP
+.B --oom-score-adj ADJ
+Alters the kernel's out-of-memory killer score adjustment on worker
+processes. ADJ is an integer ranging from -1000 to 1000, with greater
+values indicating a greater preference for killing these processes in an
+out-of-memory scenario. By default the score adjustment is inherited
+from the process that started the distccd daemon. (Linux only.)
+.TP
.B -p, --port PORT
Set the TCP port to listen on, rather than the default of 3632.
(Daemon mode only.)
diff --git a/src/dopt.c b/src/dopt.c
index d680ad5..1e92071 100644
--- a/src/dopt.c
+++ b/src/dopt.c
@@ -33,6 +33,7 @@
#include <fcntl.h>
#include <errno.h>
#include <popt.h>
+#include <limits.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -49,6 +50,10 @@
int opt_niceness = 5; /* default */
+#ifdef HAVE_LINUX
+int opt_oom_score_adj = INT_MIN; /* default is not to change */
+#endif
+
/**
* Number of children running jobs on this machine. If zero (recommended),
* then dynamically set from the number of CPUs.
@@ -154,6 +159,9 @@ const struct poptOption options[] = {
{ "no-detach", 0, POPT_ARG_NONE, &opt_no_detach, 0, 0, 0 },
{ "no-fifo", 0, POPT_ARG_NONE, &opt_no_fifo, 0, 0, 0 },
{ "no-fork", 0, POPT_ARG_NONE, &opt_no_fork, 0, 0, 0 },
+#ifdef HAVE_LINUX
+ { "oom-score-adj",0, POPT_ARG_INT, &opt_oom_score_adj, 0, 0, 0 },
+#endif
{ "pid-file", 'P', POPT_ARG_STRING, &arg_pid_file, 0, 0, 0 },
{ "port", 'p', POPT_ARG_INT, &arg_port, 0, 0, 0 },
#ifdef HAVE_GSSAPI
@@ -191,6 +199,9 @@ static void distccd_show_usage(void)
#endif
" -P, --pid-file FILE save daemon process id to file\n"
" -N, --nice LEVEL lower priority, 20=most nice\n"
+#ifdef HAVE_LINUX
+" --oom-score-adj ADJ set OOM score adjustment, -1000 to 1000\n"
+#endif
" --user USER if run by root, change to this persona\n"
" --jobs, -j LIMIT maximum tasks at any time\n"
" --job-lifetime SECONDS maximum lifetime of a compile request\n"
diff --git a/src/dopt.h b/src/dopt.h
index 70db3ca..139167b 100644
--- a/src/dopt.h
+++ b/src/dopt.h
@@ -46,6 +46,10 @@ extern int opt_lifetime;
extern char *opt_listen_addr;
extern int opt_niceness;
+#ifdef HAVE_LINUX
+extern int opt_oom_score_adj;
+#endif
+
#ifdef HAVE_AVAHI
extern int opt_zeroconf;
#endif
diff --git a/src/prefork.c b/src/prefork.c
index d7e1d84..d4d70d5 100644
--- a/src/prefork.c
+++ b/src/prefork.c
@@ -38,6 +38,7 @@
#include <signal.h>
#include <fcntl.h>
#include <time.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -149,6 +150,16 @@ static int dcc_preforked_child(int listen_fd)
const time_t child_lifetime = 60 /* seconds */;
start = now = time(NULL);
+#ifdef HAVE_LINUX
+ if (opt_oom_score_adj != INT_MIN) {
+ FILE *f = fopen("/proc/self/oom_score_adj", "w");
+ if (!f || fprintf(f, "%d\n", opt_oom_score_adj) < 0)
+ rs_log_warning("failed to set oom_score_adj: %s", strerror(errno));
+ if (f)
+ fclose(f);
+ }
+#endif
+
for (ireq = 0; ireq < child_requests || now - start < child_lifetime; ireq++) {
int acc_fd;
struct dcc_sockaddr_storage cli_addr;
diff --git a/src/setuid.c b/src/setuid.c
index d664b84..44bc850 100644
--- a/src/setuid.c
+++ b/src/setuid.c
@@ -139,6 +139,15 @@ int dcc_discard_root(void)
return EXIT_SETUID_FAILED;
}
+#ifdef HAVE_LINUX
+ /* On Linux changing the effective user or group ID clears the process's
+ * "dumpable" flag, which makes all files in the /proc/self/ directory
+ * owned by root and therefore unmodifiable by the process itself.
+ * Set the flag again here so we can, e.g., change oom_score_adj. */
+ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0)
+ rs_log_warning("failed to restore dumpable process flag: %s", strerror(errno));
+#endif
+
#ifdef __linux__
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0)
rs_trace("successfully set no_new_privs");