[PATCH 1/3] vircommand: Use closefrom() more often
Daniel P. Berrangé
berrange at redhat.com
Wed Jun 21 15:34:34 UTC 2023
On Wed, Jun 21, 2023 at 04:09:09PM +0200, Michal Privoznik wrote:
> 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);
GLibC might have closefrom() but be in a container running on an
older kernel that lacks close_range syscall.
We could ignore return value on FreeBSD, but now on Linux we must
check the return value and fallback to the old codepath(s).
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the libvir-list
mailing list