mount: refuse a merge that shortens a manifest at the truncate

Clipping a manifest reference leaves its members whole, so peer bytes past
the handle's truncate could reappear once the file grew again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chris LuandClaude Opus 5.5 committed 2026-11-12 18:02:17 -08:00
1 parent 88323d9db0
commit c3b0a43efd
2 files changed
+12 -1

No files matched your search

@@ -316,6 +316,13 @@ func TestMergeContentEntry(t *testing.T) {
t.Fatalf("truncate then write kept %v, size %d", got, merged.Attributes.FileSize)
}
// Shortening a manifest reference leaves its members whole.
peerManifest := proto.Clone(base).(*filer_pb.Entry)
peerManifest.Chunks = append(peerManifest.Chunks, &filer_pb.FileChunk{Fid: &filer_pb.FileId{VolumeId: 1, FileKey: 5, Cookie: 1}, Offset: 0, Size: 10, IsChunkManifest: true})
if _, ok := mergeContentEntry(peerManifest, base, regrown, regrown, 1, false); ok {
t.Fatal("merged a peer manifest across the truncate")
}
// A peer truncate stands when the handle only overwrote inside it.
peerTruncated := proto.Clone(base).(*filer_pb.Entry)
peerTruncated.Chunks, peerTruncated.Attributes.FileSize = peerTruncated.Chunks[:1], 1
+5 -1
View File
@@ -379,7 +379,8 @@ const maxContentFlushMerges = 3
// (truncatedTo, or -1); otherwise the stored size stands unless the handle
// changed its size or wrote past it.
// A different file at the path, inline content changed on both sides,
// inline content next to chunks (reads stop at the inline bytes), or a local
// inline content next to chunks (reads stop at the inline bytes), a manifest
// across the truncate (its members keep their sizes), or a local
// whole-file rewrite (rewrote) over a peer's chunk change cannot be merged:
// the rewrite carries the handle's stale view.
func mergeContentEntry(stored, base, local, sent *filer_pb.Entry, truncatedTo int64, rewrote bool) (*filer_pb.Entry, bool) {
@@ -417,6 +418,9 @@ func mergeContentEntry(stored, base, local, sent *filer_pb.Entry, truncatedTo in
}
c = proto.Clone(c).(*filer_pb.FileChunk)
if truncatedTo >= 0 && c.Offset+int64(c.Size) > truncatedTo {
if c.IsChunkManifest {
return nil, false
}
c.Size = uint64(truncatedTo - c.Offset)
}
merged.Chunks = append(merged.Chunks, c)