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.
This commit is contained in:
nielash 2024-02-06 02:53:12 -05:00
parent 5638a3841f
commit 0e2f1d64e3
3 changed files with 32 additions and 4 deletions

View file

@ -81,6 +81,9 @@ func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors
} }
asyncerrors = errChan asyncerrors = errChan
unmount = func() error { unmount = func() error {
if s.UnmountedExternally {
return nil
}
var umountErr error var umountErr error
var out []byte var out []byte
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
@ -98,5 +101,12 @@ func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (asyncerrors
} }
return nil return nil
} }
nfs.OnUnmountFunc = func() {
s.UnmountedExternally = true
errChan <- nil
VFS.Shutdown()
}
return return
} }

View file

@ -7,6 +7,7 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"strings"
"github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5"
"github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs"
@ -100,6 +101,16 @@ func (o *Options) Limit() int {
return o.HandleLimit 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 // LogIntercepter intercepts noisy go-nfs logs and reroutes them to DEBUG
type LogIntercepter struct { type LogIntercepter struct {
Level nfs.LogLevel Level nfs.LogLevel
@ -114,6 +125,12 @@ func (l *LogIntercepter) Intercept(args ...interface{}) {
// Interceptf intercepts go-nfs logs and calls fs.Debugf instead // Interceptf intercepts go-nfs logs and calls fs.Debugf instead
func (l *LogIntercepter) Interceptf(format string, args ...interface{}) { 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...) fs.Debugf(nil, "[NFS DEBUG] "+format, args...)
} }

View file

@ -16,10 +16,11 @@ import (
// Server contains everything to run the Server // Server contains everything to run the Server
type Server struct { type Server struct {
opt Options opt Options
handler nfs.Handler handler nfs.Handler
ctx context.Context // for global config ctx context.Context // for global config
listener net.Listener listener net.Listener
UnmountedExternally bool
} }
// NewServer creates a new server // NewServer creates a new server