From 0a51083e39494b65093ca9f76fc711eae1c08726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Fri, 2 Apr 2021 15:10:34 +0200 Subject: [PATCH] zed: implement close_from() in terms of /proc/self/fd, if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /dev/fd on Darwin Consider the following strace output: prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024, rlim_max=1024*1024}) = 0 Yes, that is well over a million file descriptors! This reduces the ZED start-up time from "at least a second" to "instantaneous", and, under strace, from "don't even try" to "usable" by simple virtue of doing five syscalls instead of over a million; in most cases the main loop does nothing Recent Linuxes (5.8+) have close_range(2) for this, but that's an overoptimisation (and libcs don't have wrappers for it yet) This is also run by the ZEDLET pre-exec. Compare: Finished "all-syslog.sh" eid=13 pid=6717 time=1.027100s exit=0 Finished "history_event-zfs-list-cacher.sh" eid=13 pid=6718 time=1.046923s exit=0 to Finished "all-syslog.sh" eid=12 pid=4834 time=0.001836s exit=0 Finished "history_event-zfs-list-cacher.sh" eid=12 pid=4835 time=0.001346s exit=0 lol Reviewed-by: Brian Behlendorf Signed-off-by: Ahelenia ZiemiaƄska Closes #11834 --- cmd/zed/zed_file.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/cmd/zed/zed_file.c b/cmd/zed/zed_file.c index 4437892e90..c7b0d00b6b 100644 --- a/cmd/zed/zed_file.c +++ b/cmd/zed/zed_file.c @@ -12,6 +12,7 @@ * You may not use this file except in compliance with the license. */ +#include #include #include #include @@ -160,6 +161,13 @@ zed_file_is_locked(int fd) return (lock.l_pid); } + +#if __APPLE__ +#define PROC_SELF_FD "/dev/fd" +#else /* Linux-compatible layout */ +#define PROC_SELF_FD "/proc/self/fd" +#endif + /* * Close all open file descriptors greater than or equal to [lowfd]. * Any errors encountered while closing file descriptors are ignored. @@ -167,17 +175,23 @@ zed_file_is_locked(int fd) void zed_file_close_from(int lowfd) { - const int maxfd_def = 256; - int errno_bak; + static const int maxfd_def = 256; + int errno_bak = errno; struct rlimit rl; - int maxfd; + int maxfd = 0; int fd; + DIR *fddir; + struct dirent *fdent; - errno_bak = errno; - - if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { - maxfd = maxfd_def; - } else if (rl.rlim_max == RLIM_INFINITY) { + if ((fddir = opendir(PROC_SELF_FD)) != NULL) { + while ((fdent = readdir(fddir)) != NULL) { + fd = atoi(fdent->d_name); + if (fd > maxfd && fd != dirfd(fddir)) + maxfd = fd; + } + (void) closedir(fddir); + } else if (getrlimit(RLIMIT_NOFILE, &rl) < 0 || + rl.rlim_max == RLIM_INFINITY) { maxfd = maxfd_def; } else { maxfd = rl.rlim_max;