diff options
| author | Jakob Unterwurzacher | 2023-06-19 13:26:44 +0200 |
|---|---|---|
| committer | Jakob Unterwurzacher | 2026-07-16 22:07:54 +0200 |
| commit | fbbc8aa8c077b31fdf0e14dc73a1bb4a3705f5a3 (patch) | |
| tree | 4aa5988761173b51e0323fd854602c4cc34d8441 | |
| parent | df552e13cd388d79c3e95ba78fb13ff927a0429b (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.go | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index 1de08c0..223c765 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -253,7 +253,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 |
