summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-09-17 16:35:59 +0200
committerLennart Poettering <lennart@poettering.net>2012-09-17 16:35:59 +0200
commit4096d6f5879aef73e20dd7b62a01f447629945b0 (patch)
treea4177bd95f8b1a3d9fdabfc52d3cde659439f1da
parentb58b344afd1c6dd4ef2b96451c726571f867d130 (diff)
main: bump up RLIMIT_NOFILE for systemd itself
For setups with many listening sockets the default kernel resource limit of 1024 fds is not enough. Bump this up to 64K to avoid any limitations in this regard. We are careful to pass on the kernel default to daemons however, since normally resource limits are a good to enforce, especially since select() can't handle fds > 1023.
-rw-r--r--src/core/main.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/src/core/main.c b/src/core/main.c
index 458fdca55e..44c010cfbf 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1125,6 +1125,42 @@ fail:
return r;
}
+static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
+ struct rlimit nl;
+ int r;
+
+ assert(saved_rlimit);
+
+ /* Save the original RLIMIT_NOFILE so that we can reset it
+ * later when transitioning from the initrd to the main
+ * systemd or suchlike. */
+ if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0) {
+ log_error("Reading RLIMIT_NOFILE failed: %m");
+ return -errno;
+ }
+
+ /* Make sure forked processes get the default kernel setting */
+ if (!arg_default_rlimit[RLIMIT_NOFILE]) {
+ struct rlimit *rl;
+
+ rl = newdup(struct rlimit, saved_rlimit, 1);
+ if (!rl)
+ return log_oom();
+
+ arg_default_rlimit[RLIMIT_NOFILE] = rl;
+ }
+
+ /* Bump up the resource limit for ourselves substantially */
+ nl.rlim_cur = nl.rlim_max = 64*1024;
+ r = setrlimit_closest(RLIMIT_NOFILE, &nl);
+ if (r < 0) {
+ log_error("Setting RLIMIT_NOFILE failed: %s", strerror(-r));
+ return r;
+ }
+
+ return 0;
+}
+
static struct dual_timestamp* parse_initrd_timestamp(struct dual_timestamp *t) {
const char *e;
unsigned long long a, b;
@@ -1207,6 +1243,7 @@ int main(int argc, char *argv[]) {
bool arm_reboot_watchdog = false;
bool queue_default_job = false;
char *switch_root_dir = NULL, *switch_root_init = NULL;
+ static struct rlimit saved_rlimit_nofile = { 0, 0 };
#ifdef HAVE_SYSV_COMPAT
if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
@@ -1518,6 +1555,9 @@ int main(int argc, char *argv[]) {
}
}
+ if (arg_running_as == MANAGER_SYSTEM)
+ bump_rlimit_nofile(&saved_rlimit_nofile);
+
r = manager_new(arg_running_as, &m);
if (r < 0) {
log_error("Failed to allocate manager object: %s", strerror(-r));
@@ -1696,7 +1736,7 @@ finish:
manager_free(m);
for (j = 0; j < RLIMIT_NLIMITS; j++)
- free (arg_default_rlimit[j]);
+ free(arg_default_rlimit[j]);
free(arg_default_unit);
strv_free(arg_default_controllers);
@@ -1714,6 +1754,12 @@ finish:
* rebooted while we do that */
watchdog_close(true);
+ /* Reset the RLIMIT_NOFILE to the kernel default, so
+ * that the new systemd can pass the kernel default to
+ * its child processes */
+ if (saved_rlimit_nofile.rlim_cur > 0)
+ setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
+
if (switch_root_dir) {
/* Kill all remaining processes from the
* initrd, but don't wait for them, so that we