]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: fd: add a new function to only raise RLIMIT_NOFILE
authorWilly Tarreau <w@1wt.eu>
Thu, 22 Sep 2022 14:08:47 +0000 (16:08 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 4 Oct 2022 06:38:47 +0000 (08:38 +0200)
In issue #1866 an issue was reported under docker, by which a user cannot
lower the number of FD needed. It looks like a restriction imposed in this
environment, but it results in an error while it ought not have to in the
case of shrinking.

This patch adds a new function raise_rlim_nofile() that takes the desired
new setting, compares it to the current one, and only calls setrlimit() if
one of the values in the new setting is larger than the older one. As such
it will continue to emit warnings and errors in case of failure to raise
the limit but will never shrink it.

This patch is only preliminary to another one, but will have to be
backported where relevant (likely only 2.6).

include/haproxy/fd.h
src/fd.c

index 8925efb66e0d966a4331da559eff39d487310e82..2a5bcad28ead8c78b5ecca0d649e7e468392ee82 100644 (file)
@@ -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 <start> */
 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);
 
index eb386a830d2b4f9dd37ee4417efe789357fc2223..f4f1bae81e402f1cb024565e2d45db756a89379a 100644 (file)
--- 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 <new_limit> and returns the previous one
+ * in <old_limit> 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 <next>
  * by bounding it to MAX_DELAY_MS. <next> may equal TICK_ETERNITY. The pollers
  * just needs to call this function right before polling to get their timeout