diff --git a/include/haproxy/fd.h b/include/haproxy/fd.h index 8925efb66..2a5bcad28 100644 --- a/include/haproxy/fd.h +++ b/include/haproxy/fd.h @@ -78,6 +78,9 @@ ssize_t fd_write_frag_line(int fd, size_t maxlen, const struct ist pfx[], size_t /* close all FDs starting from */ void my_closefrom(int start); +struct rlimit; +int raise_rlim_nofile(struct rlimit *old_limit, struct rlimit *new_limit); + int compute_poll_timeout(int next); void fd_leaving_poll(int wait_time, int status); diff --git a/src/fd.c b/src/fd.c index eb386a830..f4f1bae81 100644 --- a/src/fd.c +++ b/src/fd.c @@ -885,6 +885,33 @@ void my_closefrom(int start) } #endif // defined(USE_POLL) +/* Sets the RLIMIT_NOFILE setting to and returns the previous one + * in if the pointer is not NULL, even if set_rlimit() fails. The + * two pointers may point to the same variable as the copy happens after + * setting the new value. The value is only changed if at least one of the new + * limits is strictly higher than the current one, otherwise returns 0 without + * changing anything. The getrlimit() or setrlimit() syscall return value is + * returned and errno is preserved. + */ +int raise_rlim_nofile(struct rlimit *old_limit, struct rlimit *new_limit) +{ + struct rlimit limit = { }; + int ret = 0; + + ret = getrlimit(RLIMIT_NOFILE, &limit); + + if (ret == 0 && + (limit.rlim_max < new_limit->rlim_max || + limit.rlim_cur < new_limit->rlim_cur)) { + ret = setrlimit(RLIMIT_NOFILE, new_limit); + } + + if (old_limit) + *old_limit = limit; + + return ret; +} + /* Computes the bounded poll() timeout based on the next expiration timer * by bounding it to MAX_DELAY_MS. may equal TICK_ETERNITY. The pollers * just needs to call this function right before polling to get their timeout