Description
The erofs filesystem never evicts cached dentries, leading to unbounded memory growth in the sentry.
The dentry comment in pkg/sentry/fsimpl/erofs/erofs.go documents this:
TODO: This can lead to unbounded memory growth in sentry due to the ever-growing dentry tree. We should have a dentry LRU cache, similar to what fsimpl/gofer does.
Have a fix ready - LRU dentry cache.
Steps to reproduce
Create an EROFS image with 1.5M files and walk it inside a gVisor sandbox. Capture a heap profile before and after the walk.
#!/bin/bash
set -eu
WORKDIR=$(mktemp -d)
trap 'rm -rf "$WORKDIR"' EXIT
echo "Creating 1.5M files..."
python3 -c "
import os
for i in range(100):
for j in range(100):
d = os.path.join('$WORKDIR/root', f't_{i:03d}', f's_{j:03d}')
os.makedirs(d, exist_ok=True)
for k in range(150):
open(os.path.join(d, f'f_{k:03d}.txt'), 'wb').write(b'data')
if (i + 1) % 10 == 0:
print(f' {(i+1)*100*150} files created')
"
mkfs.erofs "$WORKDIR/img.erofs" "$WORKDIR/root"
rm -rf "$WORKDIR/root"
BUNDLE="$WORKDIR/bundle"
mkdir -p "$BUNDLE"
CID="erofs-test-$$"
cat > "$BUNDLE/config.json" <<EOF
{
"ociVersion": "1.2.0",
"process": {
"terminal": false,
"user": { "uid": 0, "gid": 0 },
"cwd": "/",
"args": ["/usr/bin/sleep", "infinity"],
"env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
},
"root": { "path": "/" }
}
EOF
RUNSC="${RUNSC_PATH:-runsc}"
sudo "$RUNSC" --profile --network=none --overlay2=root:memory \
create --bundle "$BUNDLE" "$CID"
sudo "$RUNSC" start "$CID"
sleep 2
sudo "$RUNSC" debug -profile-heap "$WORKDIR/before.pprof" -delay 2s "$CID"
sudo "$RUNSC" exec "$CID" mkdir -p /mnt
sudo "$RUNSC" debug --mount "erofs:$WORKDIR/img.erofs:/mnt" "$CID"
sudo "$RUNSC" exec "$CID" python3 -c "
import os
count = 0
for dp, _, fns in os.walk('/mnt'):
for f in fns:
os.stat(os.path.join(dp, f))
count += 1
print(f'walked {count} files')
"
sudo "$RUNSC" debug -profile-heap "$WORKDIR/after.pprof" -delay 2s "$CID"
sudo "$RUNSC" kill "$CID" KILL; sleep 1
sudo "$RUNSC" delete -force "$CID"
echo "=== Before walk ==="
go tool pprof -text -inuse_space "$WORKDIR/before.pprof" 2>&1 | head -3
echo "=== After walk ==="
go tool pprof -text -inuse_space "$WORKDIR/after.pprof" 2>&1 | head -3
Expected: Heap stays bounded after walking 1.5M files.
Actual:
=== Before walk ===
Type: inuse_space
Time: 2026-05-15 20:09:14 UTC
Showing nodes accounting for 4128.45kB, 100% of 4128.45kB total
=== After walk ===
Type: inuse_space
Time: 2026-05-15 20:09:34 UTC
Showing nodes accounting for 2353.31MB, 99.79% of 2358.36MB total
runsc version
runsc version release-20260420.0-134-g7e7d35b8a0ae
spec: 1.2.1
docker version (if using docker)
uname
Linux XXX 6.8.0-1048-gcp #51~22.04.1-Ubuntu SMP Wed Feb 11 02:38:51 UTC 2026 aarch64 aarch64 aarch64 GNU/Linux
kubectl (if using Kubernetes)
repo state (if built from source)
release-20260511.0-26-g7e7d35b8a
runsc debug logs (if available)
Description
The erofs filesystem never evicts cached dentries, leading to unbounded memory growth in the sentry.
The dentry comment in pkg/sentry/fsimpl/erofs/erofs.go documents this:
Have a fix ready - LRU dentry cache.
Steps to reproduce
Create an EROFS image with 1.5M files and walk it inside a gVisor sandbox. Capture a heap profile before and after the walk.
Expected: Heap stays bounded after walking 1.5M files.
Actual:
=== Before walk ===
Type: inuse_space
Time: 2026-05-15 20:09:14 UTC
Showing nodes accounting for 4128.45kB, 100% of 4128.45kB total
=== After walk ===
Type: inuse_space
Time: 2026-05-15 20:09:34 UTC
Showing nodes accounting for 2353.31MB, 99.79% of 2358.36MB total
runsc version
docker version (if using docker)
uname
Linux XXX 6.8.0-1048-gcp #51~22.04.1-Ubuntu SMP Wed Feb 11 02:38:51 UTC 2026 aarch64 aarch64 aarch64 GNU/Linuxkubectl (if using Kubernetes)
repo state (if built from source)
release-20260511.0-26-g7e7d35b8a
runsc debug logs (if available)