diff options
author | Jakob Unterwurzacher | 2021-01-02 18:11:18 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2021-01-02 18:19:41 +0100 |
commit | de108d3fc06dd9de404c497dfa9faa26956f43e3 (patch) | |
tree | 3f1044f2bdd7587cd34e321ba49c5f70d1cf03a0 | |
parent | c20c7992a06434dd4a9624a57aee608acfc33c12 (diff) |
-idle: don't lazy-unmount
When a process has its working dir inside the mount,
the only way we notice is that we get EBUSY when trying
to unmount.
We used to lazy-unmount in this case, but this means
pulling the rug from under the process.
For example, bash will start throwing
cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
messages.
Fixes https://github.com/rfjakob/gocryptfs/issues/533
-rw-r--r-- | Documentation/MANPAGE.md | 3 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | mount.go | 28 |
3 files changed, 25 insertions, 7 deletions
diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md index a984aa6..5febe90 100644 --- a/Documentation/MANPAGE.md +++ b/Documentation/MANPAGE.md @@ -241,6 +241,9 @@ Only for forward mode: automatically unmount the filesystem if it has been idle for the specified duration. Durations can be specified like "500s" or "2h45m". 0 (the default) means stay mounted indefinitely. +When a process has open files or its working directory in the mount, +this will keep it not idle indefinitely. + #### -kernel_cache Enable the kernel_cache option of the FUSE filesystem, see fuse(8) for details. @@ -192,6 +192,7 @@ Changelog vNEXT, in progress * MANPAGE: Split options into sections acc. to where they apply ([#517](https://github.com/rfjakob/gocryptfs/issues/517)) +* `-idle`: count cwd inside the mount as busy ([#533](https://github.com/rfjakob/gocryptfs/issues/533)) v2.0-beta2, 2020-11-14 * Improve [performance](Documentation/performance.txt#L69) @@ -175,11 +175,15 @@ func doMount(args *argContainer) { const checksDuringTimeoutPeriod = 4 func idleMonitor(idleTimeout time.Duration, fs *fusefrontend.RootNode, srv *fuse.Server, mountpoint string) { - sleepTimeBetweenChecks := contentenc.MinUint64( + // sleepNs is the sleep time between checks, in nanoseconds. + sleepNs := contentenc.MinUint64( uint64(idleTimeout/checksDuringTimeoutPeriod), uint64(2*time.Minute)) - timeoutCycles := int(math.Ceil(float64(idleTimeout) / float64(sleepTimeBetweenChecks))) + timeoutCycles := int(math.Ceil(float64(idleTimeout) / float64(sleepNs))) idleCount := 0 + idleTime := func() time.Duration { + return time.Duration(sleepNs * uint64(idleCount)) + } for { // Atomically check whether the flag is 0 and reset it to 1 if so. isIdle := !atomic.CompareAndSwapUint32(&fs.IsIdle, 0, 1) @@ -191,13 +195,21 @@ func idleMonitor(idleTimeout time.Duration, fs *fusefrontend.RootNode, srv *fuse idleCount++ } tlog.Debug.Printf( - "Checking for idle (isIdle = %t, open = %d): %s", - isIdle, openFileCount, time.Now().String()) + "idleMonitor: idle for %v (idleCount = %d, isIdle = %t, open = %d)", + idleTime(), idleCount, isIdle, openFileCount) if idleCount > 0 && idleCount%timeoutCycles == 0 { - tlog.Info.Printf("Filesystem idle; unmounting: %s", mountpoint) - unmount(srv, mountpoint) + tlog.Info.Printf("idleMonitor: filesystem idle; unmounting: %s", mountpoint) + err := srv.Unmount() + if err != nil { + // We get "Device or resource busy" when a process has its + // working directory on the mount. Log the event at Info level + // so the user finds out why their filesystem does not get + // unmounted. + tlog.Info.Printf("idleMonitor: unmount failed: %v. Resetting idle time.", err) + idleCount = 0 + } } - time.Sleep(time.Duration(sleepTimeBetweenChecks)) + time.Sleep(time.Duration(sleepNs)) } } @@ -483,6 +495,8 @@ func handleSigint(srv *fuse.Server, mountpoint string) { }() } +// unmount() calls srv.Unmount(), and if that fails, calls "fusermount -u -z" +// (lazy unmount). func unmount(srv *fuse.Server, mountpoint string) { err := srv.Unmount() if err != nil { |