From 0e2f1d64e36145b791b8017d235c158b3a70ec79 Mon Sep 17 00:00:00 2001 From: nielash Date: Tue, 6 Feb 2024 02:53:12 -0500 Subject: [PATCH] nfsmount: fix exit after external unmount #7503 Before this change, if a user unmounted externally (for example, via the Finder UI), rclone would not be aware of this and wait forever to exit -- effectively causing a deadlock that would require Ctrl+C to terminate. After this change, when the handler detects an external unmount, it calls a function which allows rclone to cleanly shutdown the VFS and exit. --- cmd/nfsmount/nfsmount.go | 10 ++++++++++ cmd/serve/nfs/handler.go | 17 +++++++++++++++++ cmd/serve/nfs/server.go | 9 +++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cmd/nfsmount/nfsmount.go b/cmd/nfsmount/nfsmount.go index 610c2f655..8b9f21b7e 100644 --- a/cmd/nfsmount/nfsmount.go +++ b/cmd/nfsmount/nfsmount.go @@ -81,6 +81,9 @@ func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors } asyncerrors = errChan unmount = func() error { + if s.UnmountedExternally { + return nil + } var umountErr error var out []byte if runtime.GOOS == "darwin" { @@ -98,5 +101,12 @@ func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors } return nil } + + nfs.OnUnmountFunc = func() { + s.UnmountedExternally = true + errChan <- nil + VFS.Shutdown() + } + return } diff --git a/cmd/serve/nfs/handler.go b/cmd/serve/nfs/handler.go index 9cfa82999..ed00639af 100644 --- a/cmd/serve/nfs/handler.go +++ b/cmd/serve/nfs/handler.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "net" + "strings" "github.com/go-git/go-billy/v5" "github.com/rclone/rclone/fs" @@ -100,6 +101,16 @@ func (o *Options) Limit() int { return o.HandleLimit } +// OnUnmountFunc registers a function to call when externally unmounted +var OnUnmountFunc func() + +func onUnmount() { + fs.Infof(nil, "unmount detected") + if OnUnmountFunc != nil { + OnUnmountFunc() + } +} + // LogIntercepter intercepts noisy go-nfs logs and reroutes them to DEBUG type LogIntercepter struct { Level nfs.LogLevel @@ -114,6 +125,12 @@ func (l *LogIntercepter) Intercept(args ...interface{}) { // Interceptf intercepts go-nfs logs and calls fs.Debugf instead func (l *LogIntercepter) Interceptf(format string, args ...interface{}) { + argsS := fmt.Sprint(args...) + // bit of a workaround... the real fix is probably https://github.com/willscott/go-nfs/pull/28 + if strings.Contains(argsS, "mount.Umnt") { + onUnmount() + } + fs.Debugf(nil, "[NFS DEBUG] "+format, args...) } diff --git a/cmd/serve/nfs/server.go b/cmd/serve/nfs/server.go index a7396cdb0..14e125264 100644 --- a/cmd/serve/nfs/server.go +++ b/cmd/serve/nfs/server.go @@ -16,10 +16,11 @@ import ( // Server contains everything to run the Server type Server struct { - opt Options - handler nfs.Handler - ctx context.Context // for global config - listener net.Listener + opt Options + handler nfs.Handler + ctx context.Context // for global config + listener net.Listener + UnmountedExternally bool } // NewServer creates a new server