mount: refuse a merge that puts inline content next to chunks

A read inside the inline bytes returns them without looking at chunks,
so one side's inline content merged with the other side's chunks hid
data after a successful flush.

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

No files matched your search

@@ -307,6 +307,18 @@ func TestMergeContentEntry(t *testing.T) {
if _, ok := mergeContentEntry(stored, base, local, local); ok {
t.Fatal("merged into a replaced file")
}
empty := flushConditionEntry()
inline := proto.Clone(empty).(*filer_pb.Entry)
inline.Content = []byte("peer")
appended := proto.Clone(empty).(*filer_pb.Entry)
appended.Chunks = flushConditionEntry(5).Chunks
if _, ok := mergeContentEntry(inline, empty, appended, appended); ok {
t.Fatal("merged chunks next to inline content")
}
if _, ok := mergeContentEntry(appended, empty, inline, inline); ok {
t.Fatal("merged inline content next to chunks")
}
}
// A miss on state no peer changed is republished once against the stored
+6 -2
View File
@@ -373,8 +373,9 @@ const maxContentFlushMerges = 3
// content it changed, taking those values from sent (local in stored's id
// space). Everything else keeps the stored value. A local truncation keeps
// its size and clips stored chunks to it; otherwise the larger size wins.
// A different file at the path, or inline content changed on both sides,
// cannot be merged.
// A different file at the path, inline content changed on both sides, or
// inline content next to chunks (reads stop at the inline bytes) cannot be
// merged.
func mergeContentEntry(stored, base, local, sent *filer_pb.Entry) (*filer_pb.Entry, bool) {
if stored == nil || base == nil || stored.IsDirectory || !bytes.Equal(stored.HardLinkId, base.HardLinkId) {
return nil, false
@@ -410,6 +411,9 @@ func mergeContentEntry(stored, base, local, sent *filer_pb.Entry) (*filer_pb.Ent
merged.Chunks = append(merged.Chunks, proto.Clone(c).(*filer_pb.FileChunk))
}
}
if len(merged.Content) > 0 && len(merged.Chunks) > 0 {
return nil, false
}
if merged.Attributes == nil {
merged.Attributes = &filer_pb.FuseAttributes{}