1 From 6f56aa01a357bbcf9401d79a378ae380f5f939d4 Mon Sep 17 00:00:00 2001
2 From: Kir Kolyshkin <kolyshkin@gmail.com>
3 Date: Tue, 29 May 2018 17:52:56 -0700
4 Subject: [PATCH 2/3] Optimize rpmSetCloseOnExec
6 In case maximum number of open files limit is set too high, both
7 luaext/Pexec() and lib/doScriptExec() spend way too much time
8 trying to set FD_CLOEXEC flag for all those file descriptors,
9 resulting in severe increase of time it takes to execute say
12 This becomes increasingly noticeable when running with e.g. under
13 Docker, the reason being:
15 > $ docker run fedora ulimit -n
18 One obvious fix is to use procfs to get the actual list of opened fds
19 and iterate over it. My quick-n-dirty benchmark shows the /proc approach
20 is about 10x faster than iterating through a list of just 1024 fds,
21 so it's an improvement even for default ulimit values.
23 Note that the old method is still used in case /proc is not available.
27 1. fix the function by making sure we modify (rather than set)
28 the existing flags. As the only known flag is FD_CLOEXEC,
29 this change is currently purely aesthetical, but in case
30 other flags will appear it will become a real bug fix.
32 2. get rid of magic number 3; use STDERR_FILENO
34 Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
38 (cherry picked from commit 5e6f05cd8dad6c1ee6bd1e6e43f176976c9c3416)
40 rpmio/rpmio.c | 43 ++++++++++++++++++++++++++++++++++---------
41 1 file changed, 34 insertions(+), 9 deletions(-)
43 diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c
44 index 747bf3c..8148aa2 100644
47 @@ -1477,18 +1477,43 @@ void fdFiniDigest(FD_t fd, int hashalgo,
51 +static void set_cloexec(int fd)
53 + int flags = fcntl(fd, F_GETFD);
55 + if (flags == -1 || (flags & FD_CLOEXEC))
58 + fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
61 void rpmSetCloseOnExec(void)
63 - int flag, fdno, open_max;
64 + const int min_fd = STDERR_FILENO; /* don't touch stdin/out/err */
67 + DIR *dir = opendir("/proc/self/fd");
68 + if (dir == NULL) { /* /proc not available */
69 + /* iterate over all possible fds, might be slow */
70 + int open_max = sysconf(_SC_OPEN_MAX);
74 - open_max = sysconf(_SC_OPEN_MAX);
75 - if (open_max == -1) {
77 + for (fd = min_fd + 1; fd < open_max; fd++)
82 - for (fdno = 3; fdno < open_max; fdno++) {
83 - flag = fcntl(fdno, F_GETFD);
84 - if (flag == -1 || (flag & FD_CLOEXEC))
86 - fcntl(fdno, F_SETFD, FD_CLOEXEC);
88 + /* iterate over fds obtained from /proc */
89 + struct dirent *entry;
90 + while ((entry = readdir(dir)) != NULL) {
91 + fd = atoi(entry->d_name);