From 4ed4483bbc49b8b72f9bb0d3034d4e94c1f82125 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 6 Jun 2024 09:39:00 +0100 Subject: [PATCH] vfs: fix fatal error: sync: unlock of unlocked mutex in panics Before this change a panic could be overwritten with the message fatal error: sync: unlock of unlocked mutex This was because we temporarily unlocked the mutex, but failed to lock it again if there was a panic. This is code is never the cause of an error but it masks the underlying error by overwriting the panic cause. See: https://forum.rclone.org/t/serve-webdav-is-crashing-fatal-error-sync-unlock-of-unlocked-mutex/46300 --- vfs/vfscache/item.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/vfs/vfscache/item.go b/vfs/vfscache/item.go index 6cc68d1e5..702847719 100644 --- a/vfs/vfscache/item.go +++ b/vfs/vfscache/item.go @@ -573,6 +573,15 @@ func (item *Item) open(o fs.Object) (err error) { return err } +// Calls f with mu unlocked, re-locking mu if a panic is raised +// +// mu must be locked when calling this function +func unlockMutexForCall(mu *sync.Mutex, f func()) { + mu.Unlock() + defer mu.Lock() + f() +} + // Store stores the local cache file to the remote object, returning // the new remote object. objOld is the old object if known. // @@ -589,9 +598,9 @@ func (item *Item) _store(ctx context.Context, storeFn StoreFn) (err error) { // Object has disappeared if cacheObj == nil if cacheObj != nil { o, name := item.o, item.name - item.mu.Unlock() - o, err := operations.Copy(ctx, item.c.fremote, o, name, cacheObj) - item.mu.Lock() + unlockMutexForCall(&item.mu, func() { + o, err = operations.Copy(ctx, item.c.fremote, o, name, cacheObj) + }) if err != nil { if errors.Is(err, fs.ErrorCantUploadEmptyFiles) { fs.Errorf(name, "Writeback failed: %v", err)