On 09/11/17(Thu) 09:02, Helg Bredow wrote: > The current libfuse signal handling assumes that the file system will always > be unmounted by the child. One obvious case where this is not true is if the > file system is busy. To replicate: > > 1. mount a fuse file system > 2. cd anywhere on the file system > 3. pkill -INT <fuse exe> > > The result is a zombie child process and no more response to signals even if > the file system is no longer busy. > > This patch ensures that the child always exits and that an error is printed > to stdout if the file system cannot be unmounted. Tested with fuse-exfat and > ntfs_3g. Suggestions for improvement are welcome.
Nice to see that you're fixing a bug. However I'd suggest you to go much further in your improvement. Signal handlers are hard and instead of doing work inside the signal handler you should toggle a global variable/flag and do this work inside the main loop (fuse_loop()?). For example your code below calls fprintf(3) in the signal handler. This is incorrect, this functions is not signal handler safe. What about fuse_unmount()? Are you sure it can be called from a signal handler? I'd recommend you to read signal(3) and some signal handlers like the ones from dhclient(8) and ntpd(8). > Index: fuse.c > =================================================================== > RCS file: /cvs/src/lib/libfuse/fuse.c,v > retrieving revision 1.34 > diff -u -p -r1.34 fuse.c > --- fuse.c 4 Nov 2017 13:17:18 -0000 1.34 > +++ fuse.c 9 Nov 2017 08:41:11 -0000 > @@ -303,26 +303,40 @@ ifuse_get_signal(unused int num) > { > struct fuse *f; > pid_t child; > - int status; > + int status, err; > + > + if (num == SIGCHLD) { > + /* child fuse_unmount() completed, check error */ > + while (waitpid(WAIT_ANY, &status, WNOHANG) == -1) { > + if (errno != EINTR) > + fprintf(stderr, "fuse: %s\n", strerror(errno)); > + } > + > + if (WIFEXITED(status)) { > + err = WEXITSTATUS(status); > + if (err) > + fprintf(stderr, "fuse: %s\n", strerror(err)); > + } > + > + signal(SIGCHLD, SIG_DFL); > + return; > + } > > if (sigse != NULL) { > + signal(SIGCHLD, ifuse_get_signal); > child = fork(); > > if (child < 0) > - return; > + return ; > > - f = sigse->args; > if (child == 0) { > + /* try to unmount, file system may be busy */ > + f = sigse->args; > + errno = 0; > fuse_unmount(f->fc->dir, f->fc); > - sigse = NULL; > - exit(0); > + _exit(errno); > } > > - fuse_loop(f); > - while (waitpid(child, &status, 0) == -1) { > - if (errno != EINTR) > - break; > - } > } > } > >