63 lines
3.2 KiB
Markdown
63 lines
3.2 KiB
Markdown
# 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
|
|
every `struct 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 successful `vflush()` during unmount. Node reclaim no longer owns
|
|
cache cleanup.
|
|
- `EROFS_MAP_META` is an explicit ineligibility condition. Metadata-backed
|
|
tailpacking therefore remains on its existing read path.
|
|
- `packed_inode` and `metabox_en` are 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_cache` and
|
|
`z_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`. The `data` pointer 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.
|