From 08e7878d8cecef67e26f36620d231733d53121d4 Mon Sep 17 00:00:00 2001 From: Nexoniarz Date: Sun, 9 Aug 2026 23:41:11 +0200 Subject: [PATCH] schfs: read a whole block per tree descent, not half of one BOUNCE was 2048 while the comment directly above it said "one page at a time", and the buffer it sizes is a single kalloc() -- so half of every bounce buffer went unused and every read did twice the work it needed to. The chunk size is not a copy-size tuning knob. Each trip through the loop takes the volume sleeplock and builds a fresh B-tree cursor to find the extent for that offset, so it really sets how many tree descents happen per byte read. An 834 KB file took 417 of them; it now takes 209. Measured in the guest, bracketed inside one command line so nothing depends on host timing: reading 834 KB goes from 1.73s to 0.90s under TCG, cold and warm alike. Warm equalling cold is itself the tell -- the cost was never the disk, it was the per-chunk work, which is why KVM was 6.4x faster on the same read while caching made no difference at all. This does not fix `ls`, and the numbers say why: 2.80s -> 2.65s cold. loaduvm already reads a page at a time, so exec was never the bottleneck there. At 241 entries in 2.65s that is ~11ms per file, spent in the per-entry lookup path rather than in reading anything. schfs-check passes; bootcheck 108 [ok]. Co-Authored-By: Claude Opus 5 --- kernel/fs/schfs/vfs.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/kernel/fs/schfs/vfs.c b/kernel/fs/schfs/vfs.c index 1139932..e7aaac9 100644 --- a/kernel/fs/schfs/vfs.c +++ b/kernel/fs/schfs/vfs.c @@ -142,7 +142,18 @@ schfs_vfs_ifree(struct inode *ip) // the tree while a copyout could fault. One page at a time keeps that buffer // off the 4096-byte kernel stack -- it is kalloc'd -- and bounds how long the // volume lock is held. -#define BOUNCE 2048 +// +// One filesystem block, which is also one kalloc page: this said 2048 while +// the comment above it said one page, so half of every bounce buffer went +// unused and every read did twice the work it needed to. +// +// The chunk size is not a copy-size tuning knob. Each trip through the loop +// takes the volume sleeplock and builds a fresh B-tree cursor to find the +// extent for that offset, so this is really "how many tree descents per byte +// read". Measured on an 834 KB file: 417 descents at 2048, 209 at 4096. +// +// It must not exceed a page, because the buffer is a single kalloc(). +#define BOUNCE SCHFS_BLKSIZE static int schfs_vfs_read(struct inode *ip, int user_dst, uint64 dst, uint64 off, uint n)