]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
src: use closefrom() for mass closing of FDs
authorYour Name <you@example.com>
Wed, 12 Feb 2020 10:53:59 +0000 (10:53 +0000)
committerDaniel P. Berrangé <berrange@redhat.com>
Wed, 12 Feb 2020 11:12:03 +0000 (11:12 +0000)
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 <jtomko@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
src/util/vircommand.c

index 904a3023c57bb999eddf0e199a595672d351654b..4a87f7c281788542f1405645e97a61b00afb45b9 100644 (file)
@@ -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: