[libvirt] [PATCHv2] daemon: clean up daemonization
Daniel Veillard
veillard at redhat.com
Tue Dec 27 10:51:10 UTC 2011
On Fri, Dec 23, 2011 at 02:13:53PM -0700, Eric Blake wrote:
> Valgrind detected a pipe fd leak before the parent exits on success,
> introduced in commit 4296cea; by itself, the leak is not bad, since
> we immediately called _exit(), but we might as well be clean to make
> valgrind analysis easier. Meanwhile, if the daemon grandchild detects
> an error, the parent failed to flush the error message before exiting.
> Also, we had the possibility of both parent and child returning to the
> caller, such that the user could see duplicated reports of failure
> from the two return paths. And we might as well be robust to the
> (unlikely) situation of being started with stdin closed.
>
> * daemon/libvirtd.c (daemonForkIntoBackground): Use exit if an
> error message was generated, avoid fd leaks for valgrind's sake,
> avoid returning to caller in both parent and child, and don't
> close a just-dup'd stdin.
> Based on a report by Alex Jia.
>
> * How to reproduce?
> % service libvirtd stop
> % valgrind -v --track-fds=yes /usr/sbin/libvirtd --daemon
>
> * Actual valgrind result:
>
> ==16804== FILE DESCRIPTORS: 7 open at exit.
> ==16804== Open file descriptor 7:
> ==16804== at 0x321FAD8B87: pipe (in /lib64/libc-2.12.so)
> ==16804== by 0x41F34D: daemonForkIntoBackground (libvirtd.c:186)
> ==16804== by 0x4207A0: main (libvirtd.c:1420)
>
> Signed-off-by: Alex Jia <ajia at redhat.com>
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> daemon/libvirtd.c | 50 ++++++++++++++++++++++++++++++++++----------------
> 1 files changed, 34 insertions(+), 16 deletions(-)
>
> diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
> index d7a03d7..f52e73f 100644
> --- a/daemon/libvirtd.c
> +++ b/daemon/libvirtd.c
> @@ -190,6 +190,7 @@ static int daemonForkIntoBackground(const char *argv0)
> switch (pid) {
> case 0:
> {
> + /* intermediate child */
> int stdinfd = -1;
> int stdoutfd = -1;
> int nextpid;
> @@ -206,9 +207,9 @@ static int daemonForkIntoBackground(const char *argv0)
> goto cleanup;
> if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
> goto cleanup;
> - if (VIR_CLOSE(stdinfd) < 0)
> + if (stdinfd > STDERR_FILENO && VIR_CLOSE(stdinfd) < 0)
> goto cleanup;
> - if (VIR_CLOSE(stdoutfd) < 0)
> + if (stdoutfd > STDERR_FILENO && VIR_CLOSE(stdoutfd) < 0)
> goto cleanup;
>
> if (setsid() < 0)
> @@ -216,26 +217,28 @@ static int daemonForkIntoBackground(const char *argv0)
>
> nextpid = fork();
> switch (nextpid) {
> - case 0:
> + case 0: /* grandchild */
> return statuspipe[1];
> - case -1:
> - return -1;
> - default:
> - _exit(0);
> + case -1: /* error */
> + goto cleanup;
> + default: /* intermediate child succeeded */
> + _exit(EXIT_SUCCESS);
> }
>
> cleanup:
> VIR_FORCE_CLOSE(stdoutfd);
> VIR_FORCE_CLOSE(stdinfd);
> - return -1;
> + VIR_FORCE_CLOSE(statuspipe[1]);
> + _exit(EXIT_FAILURE);
>
> }
>
> - case -1:
> - return -1;
> + case -1: /* error in parent */
> + goto error;
>
> default:
> {
> + /* parent */
> int ret;
> char status;
>
> @@ -243,23 +246,38 @@ static int daemonForkIntoBackground(const char *argv0)
>
> /* We wait to make sure the first child forked successfully */
> if (virPidWait(pid, NULL) < 0)
> - return -1;
> + goto error;
>
> - /* Now block until the second child initializes successfully */
> + /* If we get here, then the grandchild was spawned, so we
> + * must exit. Block until the second child initializes
> + * successfully */
> again:
> ret = read(statuspipe[0], &status, 1);
> if (ret == -1 && errno == EINTR)
> goto again;
>
> - if (ret == 1 && status != 0) {
> + VIR_FORCE_CLOSE(statuspipe[0]);
> +
> + if (ret != 1) {
> + fprintf(stderr,
> + _("%s: error: unable to determine if daemon is "
> + "running: %s\n"), argv0, strerror(errno));
> + exit(EXIT_FAILURE);
> + } else if (status != 0) {
> fprintf(stderr,
> - _("%s: error: %s. Check /var/log/messages or run without "
> - "--daemon for more info.\n"), argv0,
> + _("%s: error: %s. Check /var/log/messages or run "
> + "without --daemon for more info.\n"), argv0,
> virDaemonErrTypeToString(status));
> + exit(EXIT_FAILURE);
> }
> - _exit(ret == 1 && status == 0 ? 0 : 1);
> + _exit(EXIT_SUCCESS);
> }
> }
> +
> +error:
> + VIR_FORCE_CLOSE(statuspipe[0]);
> + VIR_FORCE_CLOSE(statuspipe[1]);
> + return -1;
> }
>
ACK to the Chrismas patch :-)
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list