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

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