From 5e038a5e1e4efb602b14af652cab1d2df5c77d21 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 17 Feb 2021 18:11:27 +0000 Subject: [PATCH] lib/file: retry preallocate on EINTR Before this change, sometimes preallocate failed with EINTR which rclone ignored. Retrying the syscall is the correct thing to do and seems to make preallocate 100% reliable. --- lib/file/preallocate_unix.go | 45 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/file/preallocate_unix.go b/lib/file/preallocate_unix.go index d610b46b1..6f666410f 100644 --- a/lib/file/preallocate_unix.go +++ b/lib/file/preallocate_unix.go @@ -6,6 +6,7 @@ import ( "os" "sync" "sync/atomic" + "syscall" "github.com/rclone/rclone/fs" "golang.org/x/sys/unix" @@ -25,30 +26,38 @@ var ( const PreallocateImplemented = true // PreAllocate the file for performance reasons -func PreAllocate(size int64, out *os.File) error { +func PreAllocate(size int64, out *os.File) (err error) { if size <= 0 { return nil } + preAllocateMu.Lock() defer preAllocateMu.Unlock() - index := atomic.LoadInt32(&fallocFlagsIndex) -again: - if index >= int32(len(fallocFlags)) { - return nil // Fallocate is disabled - } - flags := fallocFlags[index] - err := unix.Fallocate(int(out.Fd()), flags, 0, size) - if err == unix.ENOTSUP { - // Try the next flags combination - index++ - atomic.StoreInt32(&fallocFlagsIndex, index) - fs.Debugf(nil, "preAllocate: got error on fallocate, trying combination %d/%d: %v", index, len(fallocFlags), err) - goto again - } - // Wrap important errors - if err == unix.ENOSPC { - return ErrDiskFull + for { + + index := atomic.LoadInt32(&fallocFlagsIndex) + again: + if index >= int32(len(fallocFlags)) { + return nil // Fallocate is disabled + } + flags := fallocFlags[index] + err = unix.Fallocate(int(out.Fd()), flags, 0, size) + if err == unix.ENOTSUP { + // Try the next flags combination + index++ + atomic.StoreInt32(&fallocFlagsIndex, index) + fs.Debugf(nil, "preAllocate: got error on fallocate, trying combination %d/%d: %v", index, len(fallocFlags), err) + goto again + + } + // Wrap important errors + if err == unix.ENOSPC { + return ErrDiskFull + } + if err != syscall.EINTR { + break + } } return err }