1
0
mirror of https://github.com/rclone/rclone.git synced 2025-11-23 21:44:49 +02:00

vfs: fix SIGHUP killing serve instead of flushing directory caches

Before, rclone serve would crash when sent a SIGHUP which contradicts
the documentation - saying it should flush the directory caches.

Moved signal handling from the mount into the vfs layer, which now
handles SIGHUP on all uses of the VFS including mount and serve.

Fixes #8607
This commit is contained in:
dougal
2025-09-01 12:14:57 +01:00
committed by Nick Craig-Wood
parent 9e200531b1
commit a4962e21d1
5 changed files with 34 additions and 25 deletions

View File

@@ -403,27 +403,7 @@ func (m *MountPoint) Wait() error {
fnHandle := atexit.Register(finalise) fnHandle := atexit.Register(finalise)
defer atexit.Unregister(fnHandle) defer atexit.Unregister(fnHandle)
// Reload VFS cache on SIGHUP err := <-m.ErrChan
sigHup := make(chan os.Signal, 1)
NotifyOnSigHup(sigHup)
var err error
waiting := true
for waiting {
select {
// umount triggered outside the app
case err = <-m.ErrChan:
waiting = false
// user sent SIGHUP to clear the cache
case <-sigHup:
root, err := m.VFS.Root()
if err != nil {
fs.Errorf(m.VFS.Fs(), "Error reading root: %v", err)
} else {
root.ForgetAll()
}
}
}
finalise() finalise()

View File

@@ -76,7 +76,6 @@ func NewDriver(ctx context.Context, root string, mntOpt *mountlib.Options, vfsOp
// start mount monitoring // start mount monitoring
drv.hupChan = make(chan os.Signal, 1) drv.hupChan = make(chan os.Signal, 1)
drv.monChan = make(chan bool, 1) drv.monChan = make(chan bool, 1)
mountlib.NotifyOnSigHup(drv.hupChan)
go drv.monitor() go drv.monitor()
// unmount all volumes on exit // unmount all volumes on exit

View File

@@ -1,6 +1,6 @@
//go:build !plan9 && !js //go:build !plan9 && !js
package mountlib package vfs
import ( import (
"os" "os"

View File

@@ -1,6 +1,6 @@
//go:build plan9 || js //go:build plan9 || js
package mountlib package vfs
import ( import (
"os" "os"

View File

@@ -179,6 +179,7 @@ type VFS struct {
root *Dir root *Dir
Opt vfscommon.Options Opt vfscommon.Options
cache *vfscache.Cache cache *vfscache.Cache
cancel context.CancelFunc
cancelCache context.CancelFunc cancelCache context.CancelFunc
usageMu sync.Mutex usageMu sync.Mutex
usageTime time.Time usageTime time.Time
@@ -197,8 +198,10 @@ var (
// DefaultOpt will be used // DefaultOpt will be used
func New(f fs.Fs, opt *vfscommon.Options) *VFS { func New(f fs.Fs, opt *vfscommon.Options) *VFS {
fsDir := fs.NewDir("", time.Now()) fsDir := fs.NewDir("", time.Now())
ctx, cancel := context.WithCancel(context.Background())
vfs := &VFS{ vfs := &VFS{
f: f, f: f,
cancel: cancel,
} }
vfs.inUse.Store(1) vfs.inUse.Store(1)
@@ -259,6 +262,9 @@ func New(f fs.Fs, opt *vfscommon.Options) *VFS {
go vfs.refresh() go vfs.refresh()
} }
// Handle supported signals
go vfs.signalHandler(ctx)
// This can take some time so do it after the Pin // This can take some time so do it after the Pin
vfs.SetCacheMode(vfs.Opt.CacheMode) vfs.SetCacheMode(vfs.Opt.CacheMode)
@@ -274,6 +280,27 @@ func (vfs *VFS) refresh() {
} }
} }
// Reload VFS cache on SIGHUP
func (vfs *VFS) signalHandler(ctx context.Context) {
sigHup := make(chan os.Signal, 1)
NotifyOnSigHup(sigHup)
waiting := true
for waiting {
select {
case <-ctx.Done():
waiting = false
case <-sigHup:
root, err := vfs.Root()
if err != nil {
fs.Errorf(vfs.Fs(), "Error reading root: %v", err)
} else {
root.ForgetAll()
}
}
}
}
// Stats returns info about the VFS // Stats returns info about the VFS
func (vfs *VFS) Stats() (out rc.Params) { func (vfs *VFS) Stats() (out rc.Params) {
out = make(rc.Params) out = make(rc.Params)
@@ -372,6 +399,9 @@ func (vfs *VFS) Shutdown() {
close(vfs.pollChan) close(vfs.pollChan)
vfs.pollChan = nil vfs.pollChan = nil
} }
// Cancel any background go routines
vfs.cancel()
} }
// CleanUp deletes the contents of the on disk cache // CleanUp deletes the contents of the on disk cache