aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2023-06-19 13:26:44 +0200
committerJakob Unterwurzacher2023-06-19 13:27:44 +0200
commita97df8508a3f9bfc6d398c152bf15c6fcd98c74b (patch)
treed0744494ee277b344acf1d5463a9b22ff758c5cf
parent751acc4698aa299624a593745d0daf82f5a4fe10 (diff)
fusefrontend: sharedstorage: retry read-path on EIO error
With -sharedstorage, when we get a decryption error, we lock the byte range and try again. This makes concurrent R/W safe agains torn writes. https://github.com/rfjakob/gocryptfs/issues/754
-rw-r--r--internal/fusefrontend/file.go15
1 files changed, 14 insertions, 1 deletions
diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go
index 277a844..5ee7cda 100644
--- a/internal/fusefrontend/file.go
+++ b/internal/fusefrontend/file.go
@@ -254,7 +254,20 @@ func (f *File) Read(ctx context.Context, buf []byte, off int64) (resultData fuse
tlog.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d", f.qIno.Ino, off, len(buf))
out, errno := f.doRead(buf[:0], uint64(off), uint64(len(buf)))
if errno != 0 {
- return nil, errno
+ // With -sharedstorage, when we get a decryption error, we lock the
+ // byte range and try again.
+ if !(f.rootNode.args.SharedStorage && errno == syscall.EIO) {
+ return nil, errno
+ }
+ blocks := f.contentEnc.ExplodePlainRange(uint64(off), uint64(len(buf)))
+ alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks)
+ if err := f.LockSharedStorage(unix.F_RDLCK, int64(alignedOffset), int64(alignedLength)); err != nil {
+ return nil, fs.ToErrno(err)
+ }
+ out, errno = f.doRead(buf[:0], uint64(off), uint64(len(buf)))
+ if errno != 0 {
+ return nil, errno
+ }
}
tlog.Debug.Printf("ino%d: Read: errno=%d, returning %d bytes", f.qIno.Ino, errno, len(out))
return fuse.ReadResultData(out), errno