[libvirt] [PATCH v2 4/4] virCommand: use procfs to learn opened FDs
Ján Tomko
jtomko at redhat.com
Tue Jul 16 11:19:23 UTC 2019
On Tue, Jul 16, 2019 at 10:54:36AM +0200, Michal Privoznik wrote:
>When spawning a child process, between fork() and exec() we close
>all file descriptors and keep only those the caller wants us to
>pass onto the child. The problem is how we do that. Currently, we
>get the limit of opened files and then iterate through each one
>of them and either close() it or make it survive exec(). This
>approach is suboptimal (although, not that much in default
>configurations where the limit is pretty low - 1024). We have
>/proc where we can learn what FDs we hold open and thus we can
>selectively close only those.
>
>Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>---
> src/util/vircommand.c | 86 +++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 78 insertions(+), 8 deletions(-)
>
>diff --git a/src/util/vircommand.c b/src/util/vircommand.c
>index 6cd7cbe065..bfc6c15cfb 100644
>--- a/src/util/vircommand.c
>+++ b/src/util/vircommand.c
>@@ -418,27 +418,97 @@ virExecCommon(virCommandPtr cmd, gid_t *groups, int ngroups)
> static int
> virCommandMassClose(virCommandPtr cmd,
> int childin,
> int childout,
> int childerr)
> {
>+ VIR_AUTOPTR(virBitmap) fds = NULL;
> int openmax = sysconf(_SC_OPEN_MAX);
>- int fd;
>- int tmpfd;
>+ int fd = -1;
>
>- if (openmax < 0) {
>- virReportSystemError(errno, "%s",
>- _("sysconf(_SC_OPEN_MAX) failed"));
>+ /* In general, it is not save to call malloc() between fork() and exec()
s/save/safe/
>+ * because the child might have forked at the worst possible time, i.e.
>+ * when another thread was in malloc() and thus held its lock. That is to
>+ * say, POSIX does not mandate malloc() to be async-safe. Fortunately,
>+ * glibc developers are aware of this and made malloc() async-safe.
>+ * Therefore we can safely allocate memory here (and transitively call
>+ * opendir/readdir) without a deadlock. */
>+
>+ if (!(fds = virBitmapNew(openmax)))
>+ return -1;
>+
>+# ifdef __linux__
>+ if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0)
>+ return -1;
>+# else
>+ if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0)
> return -1;
>- }
>+# endif
>
>- for (fd = 3; fd < openmax; fd++) {
>+ fd = virBitmapNextSetBit(fds, -1);
>+ for (; fd >= 0; fd = virBitmapNextSetBit(fds, fd)) {
fd >= 3 to make it match the previous behavior
> if (fd == childin || fd == childout || fd == childerr)
> continue;
> if (!virCommandFDIsSet(cmd, fd)) {
>- tmpfd = fd;
>+ int tmpfd = fd;
> VIR_MASS_CLOSE(tmpfd);
Reviewed-by: Ján Tomko <jtomko at redhat.com>
Jano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20190716/944adb5c/attachment-0001.sig>
More information about the libvir-list
mailing list