mount: reuse the listed entry's path instead of rebuilding it (#10817)

readdir built dirPath.Child(name) for every child while entry.FullPath was
already that exact string, from NewFullPath in the meta cache store or from
FromPbEntry on the read-through path. One allocation per entry, and on a wide
tree with long paths that is most of what a listing allocates.

BenchmarkReadDirectory/kernel_readdirplus over 200k entries: 2,039,656 ->
1,839,318 allocs/op, 174.5 -> 167.8 MB/op, 152.6 -> 135.1 ms/op.
This commit is contained in:
Chris Lu
2026-08-18 20:55:17 -07:00
committed by GitHub
parent 887910b377
commit 9f15e3935c
2 changed files with 27 additions and 1 deletions
+6 -1
View File
@@ -3,6 +3,7 @@ package mount
import (
"context"
"errors"
"strings"
"sync"
"time"
@@ -219,7 +220,11 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out DirEntrySink, isPlusMode
processEachEntryFn := func(entry *filer.Entry, index int64) bool {
dirEntry.Name = entry.Name()
dirEntry.Mode = toSyscallMode(entry.Mode)
childPath := dirPath.Child(dirEntry.Name)
// Rebuild only for a sanitized name: that is the one a LOOKUP carries.
childPath := entry.FullPath
if !strings.HasSuffix(string(childPath), dirEntry.Name) {
childPath = dirPath.Child(dirEntry.Name)
}
var inode uint64
if takesLookupRef {
inode = wfs.inodeToPath.Lookup(childPath, entry.Crtime.Unix(), entry.IsDirectory(), len(entry.HardLinkId) > 0, entry.Inode, false)
@@ -336,3 +336,24 @@ func TestReadDirDirectTrimsConsumedEntries(t *testing.T) {
t.Errorf("handle held %d entries at peak, want well under the %d in the directory", peak, total)
}
}
// The table has to key on the sanitized name, not the stored bytes.
func TestReadDirPlusSanitizedName(t *testing.T) {
dir := util.FullPath("/images")
const rawName = "bad\xffname.jpg"
wfs := newPagingWFS(t, dir, []string{"good.jpg", rawName}, 0)
dirInode, _ := wfs.inodeToPath.GetInode(dir)
sink := &benchSink{plus: true, takesRef: true, sinkLimit: 16}
if got := walkOnce(t, wfs, dirInode, sink, false); got != 4 {
t.Fatalf("listed %d entries, want 4 (. .. and two children)", got)
}
sanitized := dir.Child(util.SanitizeUTF8Name(rawName))
if !wfs.inodeToPath.HasPath(sanitized) {
t.Errorf("%s not in the inode table", sanitized)
}
if wfs.inodeToPath.HasPath(dir.Child(rawName)) {
t.Errorf("%s keyed on the unsanitized name", dir.Child(rawName))
}
}