From 9c2130d6c2e54c45c6787fbc49a896a8544a5e47 Mon Sep 17 00:00:00 2001 From: max Date: Mon, 17 Aug 2026 01:15:41 +0000 Subject: fusefrontend: take ContentLock for truncate through node.Setattr node.Setattr opens its own file handle and called truncate directly, without ContentLock. truncate ends in doWrite, which documents that the caller holds that lock, and file.Setattr and Allocate both take it. Besides leaving a path truncate unserialized against concurrent writes, this skipped the write-operation counter that ContentLock.Lock() increments. isConsecutiveWrite() reads that counter to notice foreign modifications, so an already-open handle kept assuming its next write appends, skipped writePadHole() and grew the file past a short last block. That block no longer decrypted, and every later operation on the file failed with EIO. Fixes #1024 --- internal/fusefrontend/file_allocate_truncate.go | 2 ++ internal/fusefrontend/node.go | 2 ++ 2 files changed, 4 insertions(+) (limited to 'internal') diff --git a/internal/fusefrontend/file_allocate_truncate.go b/internal/fusefrontend/file_allocate_truncate.go index bfd11e1..f4a078c 100644 --- a/internal/fusefrontend/file_allocate_truncate.go +++ b/internal/fusefrontend/file_allocate_truncate.go @@ -97,6 +97,8 @@ func (f *File) Allocate(ctx context.Context, off uint64, sz uint64, mode uint32) } // truncate - called from node.Setattr and file.Setattr. +// +// The caller must hold f.fileTableEntry.ContentLock func (f *File) truncate(newSize uint64) (errno syscall.Errno) { var err error // Common case first: Truncate to zero diff --git a/internal/fusefrontend/node.go b/internal/fusefrontend/node.go index 28ebbd5..59f6b2f 100644 --- a/internal/fusefrontend/node.go +++ b/internal/fusefrontend/node.go @@ -246,6 +246,8 @@ func (n *Node) Setattr(ctx context.Context, f fs.FileHandle, in *fuse.SetAttrIn, } f2 := f.(*File) defer f2.Release(ctx) + f2.fileTableEntry.ContentLock.Lock() + defer f2.fileTableEntry.ContentLock.Unlock() errno = syscall.Errno(f2.truncate(sz)) if errno != 0 { return errno -- cgit v1.2.3