From 3de9bd9d0411ab9ba78f6072c12a5a89fbeea2e7 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 18 May 2020 15:43:29 +0100 Subject: [PATCH] vfs: fix hang in read wait code - Fixes #4039 Before this fix, rclone would sometimes hang in vfs.readAt(). This was due to a race condition causing rclone to miss the timeout signal. This was fixed by a small amount of extra locking. This very likely also fixes a number of "failed to wait for in-sequence read" errors. --- vfs/read.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/vfs/read.go b/vfs/read.go index a89b1099b..c51f46008 100644 --- a/vfs/read.go +++ b/vfs/read.go @@ -5,7 +5,6 @@ import ( "io" "os" "sync" - "sync/atomic" "time" "github.com/pkg/errors" @@ -238,18 +237,22 @@ func (fh *ReadFileHandle) readAt(p []byte, off int64) (n int, err error) { maxWait := fh.file.VFS().Opt.ReadWait timeout := time.NewTimer(maxWait) done := make(chan struct{}) - abort := int32(0) + abort := false go func() { select { case <-timeout.C: - // set abort flag an give all the waiting goroutines a kick on timeout - atomic.StoreInt32(&abort, 1) + // take the lock to make sure that fh.cond.Wait() is called before + // fh.cond.Broadcast. NB fh.cond.L == fh.mu + fh.mu.Lock() + // set abort flag and give all the waiting goroutines a kick on timeout + abort = true fs.Debugf(fh.remote, "aborting in-sequence read wait, off=%d", off) fh.cond.Broadcast() + fh.mu.Unlock() case <-done: } }() - for fh.offset != off && atomic.LoadInt32(&abort) == 0 { + for fh.offset != off && !abort { fs.Debugf(fh.remote, "waiting for in-sequence read to %d for %v", off, maxWait) fh.cond.Wait() }