[PATCH] s-s-d: use close_range if possible
This commit introduces a new `close_all_fds` function in s-s-d to close all file
descriptors prior to starting a new process. The function leverages the
`close_range` system call if it is supported (available in glibc >= 2.34 and
kernel >= 5.9). If `close_range` is not available, the function falls back to
iterating over each file descriptor individually.
These changes address the issue where s-s-d could freeze when the system has a
relatively high `max_fds` setting.
---
this change might be useful for systems with a high `max_fds` setting, i was
found this problem while trying to run s-s-d in docker container since it have
default max_fds set to 1073741816 and it will take a long time to close all fds
maybe this patch should be backported to previous version of s-s-d?
configure.ac | 1 +
utils/start-stop-daemon.c | 25 ++++++++++++++++++-------
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 3f1a86362..faed01518 100644
--- a/configure.ac
+++ b/configure.ac
@@ -213,6 +213,7 @@ AC_CHECK_FUNCS([\
AC_CHECK_FUNCS([\
setsid \
getdtablesize \
+ close_range \
getprocs64 \
getprogname \
getexecname \
diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index 8899f0c03..029733b0e 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -496,14 +496,26 @@ parse_unsigned(const char *string, int base, int *value_r)
return 0;
}
-static long
-get_open_fd_max(void)
+static void
+close_all_fds(void)
{
+ long max_fd;
+ int close_range_ret = ENOSYS;
+
#ifdef HAVE_GETDTABLESIZE
- return getdtablesize();
+ max_fd = getdtablesize();
#else
- return sysconf(_SC_OPEN_MAX);
+ max_fd = sysconf(_SC_OPEN_MAX);
#endif
+
+#ifdef HAVE_CLOSE_RANGE
+ close_range_ret = close_range(3, max_fd, 0);
+#endif
+ if (close_range_ret == ENOSYS) {
+ long fd;
+ for (fd = max_fd - 1; fd >= 3; fd--)
+ close(fd);
+ }
}
#ifndef HAVE_SETSID
@@ -2664,9 +2676,8 @@ do_start(int argc, char **argv)
dup2(devnull_fd, 0); /* stdin */
- /* Now close all extra fds. */
- for (i = get_open_fd_max() - 1; i >= 3; --i)
- close(i);
+ /* Now close all extra fds. */
+ close_all_fds();
}
execv(startas, argv);
fatale("unable to start %s", startas);
--
2.46.0
Reply to: