3.2 KiB
Pre9 LZMA cache review resolution
This document records the follow-up to commit 61f4709, which cached one
decoded LZMA extent per vnode.
Findings addressed
- The cache is now one entry in
struct erofs_mount, rather than one entry in everystruct erofs_node. Retained decoded memory is bounded by one extent per mounted filesystem, with the number of mounts controlled by mount privileges. Keeping many ordinary file descriptors open cannot create more cache entries. - Cache initialization is performed in
erofs_mountfs()immediately after mount allocation.erofs_sb_free()destroys it on every mount failure path and after successfulvflush()during unmount. Node reclaim no longer owns cache cleanup. EROFS_MAP_METAis an explicit ineligibility condition. Metadata-backed tailpacking therefore remains on its existing read path.packed_inodeandmetabox_enare explicit ineligibility conditions. The mount-private backing objects cannot populate or consume the user-data cache.- The cache type and helper names are now
erofs_zextent_cacheandz_erofs_extent_cache_*, distinguishing decoded extents from Linux's managed compressed-page cache names. - The key retains the existing physical/logical extent fields, device id,
flags, and algorithm, and adds the stable inode
nid. Thedatapointer is the validity bit, so NID zero is not treated as an empty key.
Copy bound and concurrency
z_erofs_read_uio() limits each output request to MAXPHYS. The generic
z_erofs_read_data() API can receive a larger request, so cache eligibility
rejects any request whose mapped portion exceeds MAXPHYS. Both cache helper
entry points also contain KASSERT(len <= MAXPHYS) checks. The largest copy
performed while holding z_extent_cache_lock is therefore MAXPHYS; the
12 MiB Z_EROFS_PCLUSTER_MAX_DSIZE limit remains an on-disk decoded-extent
allocation bound, not a mutex-copy bound.
Allocation, compressed reads, and decompression happen outside the mutex. A cache hit copies while holding the mutex, and a miss publishes and copies under the same mutex before the previous allocation is freed. Concurrent misses may decode duplicate extents and may replace one another, but pointer access and replacement remain serialized. A refcounted immutable cache entry was deliberately not introduced in this first stage.
Resource tradeoff
The per-mount entry is intentionally a small first-stage design. It removes
the unbounded-per-open-vnode retention introduced by 61f4709, but it can
thrash when many files are read concurrently on one mount. Retention lasts
until unmount, and the retained allocation is capped by the existing EROFS
format constant Z_EROFS_PCLUSTER_MAX_DSIZE (12 MiB). A FreeBSD shrinker or
pressure callback is deferred; adding one would require a broader memory
accounting and lifecycle design than this corrective commit.
Validation scope
This correction is statically validated only. QEMU validation remains required for complete SHA-256 reads, same-file concurrent reads, close/reopen, unmount cleanup, metadata tailpacking, and memory-pressure behavior. The existing Pre9 manual test report predates this correction and must not be reported as runtime validation of this commit.