From: Your Name Date: Wed, 12 Feb 2020 10:53:59 +0000 (+0000) Subject: src: use closefrom() for mass closing of FDs X-Git-Tag: v6.1.0-rc1~154 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=59afd9764dcffdc3339003a430b860cc68128f4d;p=thirdparty%2Flibvirt.git src: use closefrom() for mass closing of FDs On FreeBSD 12 the default ulimit settings allow for 100,000 open file descriptors. As a result spawning processes in libvirt is abominably slow. Fortunately FreeBSD has long since provided a good solution in the form of closefrom(), which closes all FDs equal to or larger than the specified parameter. Reviewed-by: Ján Tomko Signed-off-by: Daniel P. Berrangé --- diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 904a3023c5..4a87f7c281 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -494,6 +494,60 @@ virCommandMassCloseGetFDsGeneric(virCommandPtr cmd G_GNUC_UNUSED, } # endif /* !__linux__ */ +# ifdef __FreeBSD__ + +static int +virCommandMassClose(virCommandPtr cmd, + int childin, + int childout, + int childerr) +{ + int lastfd = -1; + int fd = -1; + size_t i; + + /* + * Two phases of closing. + * + * The first (inefficient) phase iterates over FDs, + * preserving certain FDs we need to pass down, and + * closing others. The number of iterations is bounded + * to the number of the biggest FD we need to preserve. + * + * The second (speedy) phase uses closefrom() to cull + * all remaining FDs in the process. + * + * Usually the first phase will be fairly quick only + * processing a handful of low FD numbers, and thus using + * closefrom() is a massive win for high ulimit() NFILES + * values. + */ + lastfd = MAX(lastfd, childin); + lastfd = MAX(lastfd, childout); + lastfd = MAX(lastfd, childerr); + + for (i = 0; i < cmd->npassfd; i++) + lastfd = MAX(lastfd, cmd->passfd[i].fd); + + for (fd = 0; fd <= lastfd; fd++) { + if (fd == childin || fd == childout || fd == childerr) + continue; + if (!virCommandFDIsSet(cmd, fd)) { + int tmpfd = fd; + VIR_MASS_CLOSE(tmpfd); + } else if (virSetInherit(fd, true) < 0) { + virReportSystemError(errno, _("failed to preserve fd %d"), fd); + return -1; + } + } + + closefrom(lastfd + 1); + + return 0; +} + +# else /* ! __FreeBSD__ */ + static int virCommandMassClose(virCommandPtr cmd, int childin, @@ -520,13 +574,13 @@ virCommandMassClose(virCommandPtr cmd, if (!(fds = virBitmapNew(openmax))) return -1; -# ifdef __linux__ +# ifdef __linux__ if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0) return -1; -# else +# else if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0) return -1; -# endif +# endif fd = virBitmapNextSetBit(fds, 2); for (; fd >= 0; fd = virBitmapNextSetBit(fds, fd)) { @@ -544,6 +598,7 @@ virCommandMassClose(virCommandPtr cmd, return 0; } +# endif /* ! __FreeBSD__ */ /* * virExec: