[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[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: