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@xxxxxxxxxx> --- 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