Blame SOURCES/0026-Optimize-closing-open-file-descriptors.patch

5e5f7c
From 9bbb628620d4e586941344e1bdbbc166a885c0a9 Mon Sep 17 00:00:00 2001
5e5f7c
From: Rob Crittenden <rcritten@redhat.com>
5e5f7c
Date: Thu, 5 Sep 2019 12:45:52 -0400
5e5f7c
Subject: [PATCH] Optimize closing open file descriptors
5e5f7c
5e5f7c
When forking, the code would close all unused file descriptors up
5e5f7c
to maximum number of files. In the default case this is 1024. In
5e5f7c
the container case this is 1048576. Huge delays in startup were
5e5f7c
seen due to this.
5e5f7c
5e5f7c
Even in a default 1024 ulimit case this drastically reduces the
5e5f7c
number of file descriptors to mark FD_CLOEXEC but in the container
5e5f7c
default case this saves another order of magnitude of work.
5e5f7c
5e5f7c
This patch takes inspiration from systemd[1] and walks /proc/self/fd
5e5f7c
if it is available to determine the list of open descriptors. It
5e5f7c
falls back to the "close all fds we don't care about up to limit"
5e5f7c
method.
5e5f7c
5e5f7c
https://bugzilla.redhat.com/show_bug.cgi?id=1656519
5e5f7c
5e5f7c
[1] https://github.com/systemd/systemd/blob/5238e9575906297608ff802a27e2ff9effa3b338/src/basic/fd-util.c#L217
5e5f7c
---
5e5f7c
 src/subproc.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-------
5e5f7c
 1 file changed, 62 insertions(+), 9 deletions(-)
5e5f7c
5e5f7c
diff --git a/src/subproc.c b/src/subproc.c
5e5f7c
index e49e3762..8df836ae 100644
5e5f7c
--- a/src/subproc.c
5e5f7c
+++ b/src/subproc.c
5e5f7c
@@ -19,6 +19,7 @@
5e5f7c
 
5e5f7c
 #include <sys/types.h>
5e5f7c
 #include <sys/wait.h>
5e5f7c
+#include <dirent.h>
5e5f7c
 #include <errno.h>
5e5f7c
 #include <fcntl.h>
5e5f7c
 #include <paths.h>
5e5f7c
@@ -436,6 +437,25 @@ cm_subproc_parse_args(void *parent, const char *cmdline, const char **error)
5e5f7c
 	return argv;
5e5f7c
 }
5e5f7c
 
5e5f7c
+/* Based heavily on systemd version */
5e5f7c
+static
5e5f7c
+int safe_atoi(const char *s, int *ret_i) {
5e5f7c
+	char *x = NULL;
5e5f7c
+	long l;
5e5f7c
+
5e5f7c
+	errno = 0;
5e5f7c
+	l = strtol(s, &x, 0);
5e5f7c
+	if (errno > 0)
5e5f7c
+		return -1;
5e5f7c
+	if (!x || x == s || *x != 0)
5e5f7c
+		return -1;
5e5f7c
+	if ((long) (int) l != l)
5e5f7c
+		return -1;
5e5f7c
+
5e5f7c
+	*ret_i = (int) l;
5e5f7c
+	return 0;
5e5f7c
+}
5e5f7c
+
5e5f7c
 /* Redirect stdio to /dev/null, and mark everything else as close-on-exec,
5e5f7c
  * except for perhaps one to three of them that are passed in by number. */
5e5f7c
 void
5e5f7c
@@ -443,6 +463,9 @@ cm_subproc_mark_most_cloexec(int fd, int fd2, int fd3)
5e5f7c
 {
5e5f7c
 	int i;
5e5f7c
 	long l;
5e5f7c
+	DIR *dir = NULL;
5e5f7c
+	struct dirent *de;
5e5f7c
+
5e5f7c
 	if ((fd != STDIN_FILENO) &&
5e5f7c
 	    (fd2 != STDIN_FILENO) &&
5e5f7c
 	    (fd3 != STDIN_FILENO)) {
5e5f7c
@@ -482,17 +505,47 @@ cm_subproc_mark_most_cloexec(int fd, int fd2, int fd3)
5e5f7c
 			close(STDERR_FILENO);
5e5f7c
 		}
5e5f7c
 	}
5e5f7c
-	for (i = getdtablesize() - 1; i >= 3; i--) {
5e5f7c
-		if ((i == fd) ||
5e5f7c
-		    (i == fd2) ||
5e5f7c
-		    (i == fd3)) {
5e5f7c
-			continue;
5e5f7c
+	dir = opendir("/proc/self/fd");
5e5f7c
+	if (!dir) {
5e5f7c
+		/* /proc isn't available, fall back to old way */
5e5f7c
+		for (i = getdtablesize() - 1; i >= 3; i--) {
5e5f7c
+			if ((i == fd) ||
5e5f7c
+			    (i == fd2) ||
5e5f7c
+			    (i == fd3)) {
5e5f7c
+				continue;
5e5f7c
+			}
5e5f7c
+			l = fcntl(i, F_GETFD);
5e5f7c
+			if (l != -1) {
5e5f7c
+				if (fcntl(i, F_SETFD, l | FD_CLOEXEC) != 0) {
5e5f7c
+					cm_log(0, "Potentially leaking FD %d.\n", i);
5e5f7c
+				}
5e5f7c
+			}
5e5f7c
 		}
5e5f7c
-		l = fcntl(i, F_GETFD);
5e5f7c
-		if (l != -1) {
5e5f7c
-			if (fcntl(i, F_SETFD, l | FD_CLOEXEC) != 0) {
5e5f7c
-				cm_log(0, "Potentially leaking FD %d.\n", i);
5e5f7c
+	} else {
5e5f7c
+		while ((de = readdir(dir)) != NULL) {
5e5f7c
+			int i = -1;
5e5f7c
+
5e5f7c
+			if (safe_atoi(de->d_name, &i) < 0) {
5e5f7c
+				continue;
5e5f7c
+			}
5e5f7c
+
5e5f7c
+			if ((i == fd) ||
5e5f7c
+			    (i == fd2) ||
5e5f7c
+			    (i == fd3)) {
5e5f7c
+				continue;
5e5f7c
+			}
5e5f7c
+
5e5f7c
+			if (i == dirfd(dir)) {
5e5f7c
+				continue;
5e5f7c
+			}
5e5f7c
+
5e5f7c
+			l = fcntl(i, F_GETFD);
5e5f7c
+			if (l != -1) {
5e5f7c
+				if (fcntl(i, F_SETFD, l | FD_CLOEXEC) != 0) {
5e5f7c
+					cm_log(0, "Potentially leaking FD %d.\n", i);
5e5f7c
+				}
5e5f7c
 			}
5e5f7c
 		}
5e5f7c
+		closedir(dir);
5e5f7c
 	}
5e5f7c
 }
5e5f7c
-- 
5e5f7c
2.21.0
5e5f7c