summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2016-06-20 20:12:23 +0200
committerNikolaus Rath <Nikolaus@rath.org>2016-06-20 12:50:05 -0700
commit6189312b0c530792657556b266546cd2edb23d4a (patch)
treee8c2cf0b8d7d5cfad41e2ea92cb5475e9e69cab7
parent9448849b568bf430950463fb70dab81a139b29bd (diff)
downloadfuse-6189312b0c530792657556b266546cd2edb23d4a.tar.gz
libfuse/fuse_daemonize: wait until daemon child process is ready (#55)
Mounting a FUSE file system remotely using SSH in combination with pseudo-terminal allocation (-t), results in "Transport endpoint is not connected" errors when trying to access the file system contents. For example: # ssh -t root@localhost "cmsfs-fuse /dev/disk/by-path/ccw-0.0.0190 /CMSFS" Connection to localhost closed. # ls /CMSFS ls: cannot access '/CMSFS': Transport endpoint is not connected The cmsfs-fuse main program (which can also be any other FUSE file system) calls into the fuse_main() libfuse library function. The fuse_main() function later calls fuse_daemonize() to fork the daemon process to handle the FUSE file system I/O. The fuse_daemonize() function calls fork() as usual. The child proceeds with setsid() and then redirecting its file descriptors to /dev/null etc. The parent process, simply exits. The child's functions and the parent's exit creates a subtle race. This is seen with an SSH connection. The SSH command above calls cmsfs-fuse on an allocated pseudo-terminal device (-t option). If the parent exits, SSH receives the command completion and closes the connection, that means, it closes the master side of the pseudo-terminal. This causes a HUP signal being sent to the process group on the pseudo-terminal. At this point in time, the child might not have completed the setsid() call and, hence, becomes terminated. Note that fuse daemon sets up its signal handlers after fuse_daemonize() has completed. Even if the child has the chance to disassociate from its parent process group to become it's own process group with setsid(), the child still has the pseudo-terminal opened as stdin, stdout, and stderr. So the pseudo-terminal still behave as controlling terminal and might cause a SIGHUP at closing the the master side. To solve the problem, the parent has to wait until the child (the fuse daemon process) has completed its processing, that means, has become its own process group with setsid() and closed any file descriptors pointing to the pseudo-terminal. Closes: #27 Reported-by: Ofer Baruch <oferba@il.ibm.com> Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
-rw-r--r--ChangeLog2
-rw-r--r--lib/helper.c14
2 files changed, 16 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index d18888d..0990310 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@ Unreleased Changes
==================
* Added SELinux support.
+* Fixed race-condition when session is terminated right after starting
+ a FUSE file system.
FUSE 2.9.6 (2016-04-23)
=======================
diff --git a/lib/helper.c b/lib/helper.c
index b644012..49d30f9 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -181,6 +181,13 @@ int fuse_daemonize(int foreground)
{
if (!foreground) {
int nullfd;
+ int waiter[2];
+ char completed;
+
+ if (pipe(waiter)) {
+ perror("fuse_daemonize: pipe");
+ return -1;
+ }
/*
* demonize current process by forking it and killing the
@@ -193,6 +200,7 @@ int fuse_daemonize(int foreground)
case 0:
break;
default:
+ read(waiter[0], &completed, sizeof(completed));
_exit(0);
}
@@ -211,6 +219,12 @@ int fuse_daemonize(int foreground)
if (nullfd > 2)
close(nullfd);
}
+
+ /* Propagate completion of daemon initializatation */
+ completed = 1;
+ write(waiter[1], &completed, sizeof(completed));
+ close(waiter[0]);
+ close(waiter[1]);
}
return 0;
}