132 lines
3.4 KiB
Diff
132 lines
3.4 KiB
Diff
https://www.redhat.com/archives/libvir-list/2020-August/msg00598.html
|
|
|
|
Add a portable generic implementation of virMassClose as fallback on
|
|
non-FreeBSD and non-glibc.
|
|
|
|
This implementation uses poll(2) to look for open files to keep
|
|
performance reasonable while not using any mallocs.
|
|
|
|
This solves a deadlock with musl libc.
|
|
|
|
Signed-off-by: Natanael Copa <ncopa alpinelinux org>
|
|
---
|
|
src/util/vircommand.c | 76 +++++++++++++++++++++++++++++++++----------
|
|
1 file changed, 58 insertions(+), 18 deletions(-)
|
|
|
|
diff -ur src/util/vircommand.c src/util/vircommand.c
|
|
--- src/util/vircommand.c
|
|
+++ src/util/vircommand.c
|
|
@@ -443,7 +443,7 @@
|
|
return 0;
|
|
}
|
|
|
|
-# ifdef __linux__
|
|
+# if defined(__linux__) && defined(__GLIBC__)
|
|
/* 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
|
|
@@ -478,17 +478,7 @@
|
|
|
|
return 0;
|
|
}
|
|
-
|
|
-# else /* !__linux__ */
|
|
-
|
|
-static int
|
|
-virCommandMassCloseGetFDsGeneric(virCommandPtr cmd G_GNUC_UNUSED,
|
|
- virBitmapPtr fds)
|
|
-{
|
|
- virBitmapSetAll(fds);
|
|
- return 0;
|
|
-}
|
|
-# endif /* !__linux__ */
|
|
+# endif /* __linux__ && __GLIBC__ */
|
|
|
|
# ifdef __FreeBSD__
|
|
|
|
@@ -542,7 +532,7 @@
|
|
return 0;
|
|
}
|
|
|
|
-# else /* ! __FreeBSD__ */
|
|
+# elif defined(__GLIBC__) /* ! __FreeBSD__ */
|
|
|
|
static int
|
|
virCommandMassClose(virCommandPtr cmd,
|
|
@@ -569,13 +559,8 @@
|
|
|
|
fds = virBitmapNew(openmax);
|
|
|
|
-# ifdef __linux__
|
|
if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0)
|
|
return -1;
|
|
-# else
|
|
- if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0)
|
|
- return -1;
|
|
-# endif
|
|
|
|
fd = virBitmapNextSetBit(fds, 2);
|
|
for (; fd >= 0; fd = virBitmapNextSetBit(fds, fd)) {
|
|
@@ -593,6 +578,61 @@
|
|
return 0;
|
|
}
|
|
|
|
+#else /* ! __FreeBSD__ && ! __GLIBC__ */
|
|
+static int
|
|
+virCommandMassClose(virCommandPtr cmd,
|
|
+ int childin,
|
|
+ int childout,
|
|
+ int childerr)
|
|
+{
|
|
+ static struct pollfd pfds[1024];
|
|
+ int fd = 0;
|
|
+ int i, total;
|
|
+ int max_fd = sysconf(_SC_OPEN_MAX);
|
|
+
|
|
+ if (max_fd < 0) {
|
|
+ virReportSystemError(errno, "%s", _("sysconf(_SC_OPEN_MAX) failed"));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ total = max_fd - fd;
|
|
+ for (i = 0; i < (total < 1024 ? total : 1024); i++)
|
|
+ pfds[i].events = 0;
|
|
+
|
|
+ while (fd < max_fd) {
|
|
+ int nfds, r = 0;
|
|
+
|
|
+ total = max_fd - fd;
|
|
+ nfds = total < 1024 ? total : 1024;
|
|
+
|
|
+ for (i = 0; i < nfds; i++)
|
|
+ pfds[i].fd = fd + i;
|
|
+
|
|
+ do {
|
|
+ r = poll(pfds, nfds, 0);
|
|
+ } while (r == -1 && errno == EINTR);
|
|
+
|
|
+ if (r < 0) {
|
|
+ virReportSystemError(errno, "%s", _("poll() failed"));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < nfds; i++)
|
|
+ if (pfds[i].revents != POLLNVAL) {
|
|
+ if (pfds[i].fd == childin || pfds[i].fd == childout || pfds[i].fd == childerr)
|
|
+ continue;
|
|
+ if (!virCommandFDIsSet(cmd, pfds[i].fd)) {
|
|
+ VIR_MASS_CLOSE(pfds[i].fd);
|
|
+ } else if (virSetInherit(pfds[i].fd, true) < 0) {
|
|
+ virReportSystemError(errno, _("failed to preserve fd %d"), pfds[i].fd);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ fd += nfds;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
# endif /* ! __FreeBSD__ */
|
|
|
|
/*
|