vircommand: Unify mass FD closing

We have two version of mass FD closing: one for FreeBSD (because
it has closefrom()) and the other for everything else. But now
that we have closefrom() wrapper even for Linux, we can unify
these two.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Kristina Hanicova <khanicov@redhat.com>
This commit is contained in:
Michal Privoznik 2023-08-21 15:10:39 +02:00
parent 06d0a66292
commit dd2eeaad0b

View File

@ -526,60 +526,6 @@ virCommandMassCloseGetFDsGeneric(virCommand *cmd G_GNUC_UNUSED,
} }
# endif /* !__linux__ */ # 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__ */
static int static int
virCommandMassClose(virCommand *cmd, virCommandMassClose(virCommand *cmd,
int childin, int childin,
@ -588,7 +534,9 @@ virCommandMassClose(virCommand *cmd,
{ {
g_autoptr(virBitmap) fds = NULL; g_autoptr(virBitmap) fds = NULL;
int openmax = sysconf(_SC_OPEN_MAX); int openmax = sysconf(_SC_OPEN_MAX);
int lastfd = -1;
int fd = -1; int fd = -1;
size_t i;
/* In general, it is not safe to call malloc() between fork() and exec() /* In general, it is not safe to call malloc() between fork() and exec()
* because the child might have forked at the worst possible time, i.e. * because the child might have forked at the worst possible time, i.e.
@ -605,16 +553,23 @@ virCommandMassClose(virCommand *cmd,
fds = virBitmapNew(openmax); fds = virBitmapNew(openmax);
# ifdef __linux__ # ifdef __linux__
if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0) if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0)
return -1; return -1;
# else # else
if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0) if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0)
return -1; return -1;
# endif # endif
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);
fd = virBitmapNextSetBit(fds, 2); fd = virBitmapNextSetBit(fds, 2);
for (; fd >= 0; fd = virBitmapNextSetBit(fds, fd)) { for (; fd >= 0 && fd <= lastfd; fd = virBitmapNextSetBit(fds, fd)) {
if (fd == childin || fd == childout || fd == childerr) if (fd == childin || fd == childout || fd == childerr)
continue; continue;
if (!virCommandFDIsSet(cmd, fd)) { if (!virCommandFDIsSet(cmd, fd)) {
@ -626,11 +581,21 @@ virCommandMassClose(virCommand *cmd,
} }
} }
if (virCloseFrom(lastfd + 1) < 0) {
if (errno != ENOSYS)
return -1;
if (fd > 0) {
for (; fd >= 0; fd = virBitmapNextSetBit(fds, fd)) {
int tmpfd = fd;
VIR_MASS_CLOSE(tmpfd);
}
}
}
return 0; return 0;
} }
# endif /* ! __FreeBSD__ */
/* /*
* virExec: * virExec: