[PATCH 1/3] vircommand: Use closefrom() more often

Michal Privoznik mprivozn at redhat.com
Wed Jun 21 14:09:09 UTC 2023


As of commit v5.9-rc1~160^2~3 the Linux kernel has close_range()
syscall, which closes not just one FD but whole range. Then, in
its commit glibc-2.34~115 glibc introduced closefrom() which is
just a wrapper over close_range(), but it allows us to use
FreeBSD-only implementation on Linux too, as both OS-es now have
the same function.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 meson.build           |   1 +
 src/util/vircommand.c | 124 ++++++++++++++++++++++--------------------
 2 files changed, 66 insertions(+), 59 deletions(-)

diff --git a/meson.build b/meson.build
index aa391e7178..a4b52b6156 100644
--- a/meson.build
+++ b/meson.build
@@ -573,6 +573,7 @@ libvirt_export_dynamic = cc.first_supported_link_argument([
 # check availability of various common functions (non-fatal if missing)
 
 functions = [
+  'closefrom',
   'elf_aux_info',
   'explicit_bzero',
   'fallocate',
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 49abb53c28..b8b8d48f92 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -479,7 +479,68 @@ virExecCommon(virCommand *cmd, gid_t *groups, int ngroups)
     return 0;
 }
 
-# ifdef __linux__
+# ifdef WITH_CLOSEFROM
+#  define USE_CLOSEFROM
+# else
+#  define USE_GENERIC
+# endif
+
+
+# ifdef USE_CLOSEFROM
+static int
+virCommandMassClose(virCommand *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 %1$d"), fd);
+            return -1;
+        }
+    }
+
+    closefrom(lastfd + 1);
+
+    return 0;
+}
+# endif /* ! WITH_CLOSEFROM */
+
+
+# ifdef USE_GENERIC
+#  ifdef __linux__
 /* On Linux, we can utilize procfs and read the table of opened
  * FDs and selectively close only those FDs we don't want to pass
  * onto child process (well, the one we will exec soon since this
@@ -515,7 +576,7 @@ virCommandMassCloseGetFDsLinux(virCommand *cmd G_GNUC_UNUSED,
     return 0;
 }
 
-# else /* !__linux__ */
+#  else /* !__linux__ */
 
 static int
 virCommandMassCloseGetFDsGeneric(virCommand *cmd G_GNUC_UNUSED,
@@ -524,61 +585,7 @@ virCommandMassCloseGetFDsGeneric(virCommand *cmd G_GNUC_UNUSED,
     virBitmapSetAll(fds);
     return 0;
 }
-# endif /* !__linux__ */
-
-# ifdef __FreeBSD__
-
-static int
-virCommandMassClose(virCommand *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 %1$d"), fd);
-            return -1;
-        }
-    }
-
-    closefrom(lastfd + 1);
-
-    return 0;
-}
-
-# else /* ! __FreeBSD__ */
+#  endif /* !__linux__ */
 
 static int
 virCommandMassClose(virCommand *cmd,
@@ -628,8 +635,7 @@ virCommandMassClose(virCommand *cmd,
 
     return 0;
 }
-
-# endif /* ! __FreeBSD__ */
+# endif /* ! USE_GENERIC */
 
 
 /*
-- 
2.39.3



More information about the libvir-list mailing list