[PATCH v5 00/13] zram: redesign zcomp and rework backends

From: Sergey Senozhatsky

Date: Sat Oct 17 2026 - 23:51:58 EST


The series has a number of memory usage optimisations and fixes
that result in savings from double digits KB to triple digits
KB per-context/per-CPU, depending on backend and its configuration.
More details are in the corresponding commit messages.

The zcomp redesign and backend rework happen in the final three
patches. zcomp part, basically, attempts to address the priority
inversion problem, that is seen on some setups. In zcomp, we have
always kept Read and Write contexts together in per-CPU streams.
With preemptible zram this becomes a bit of a problem, as a higher
priority Reader can preempt a Writer, which may hold a stream
lock, but since the compression stream is locked by the preempted
Writer, the Reader gets blocked on the very same stream lock.
However, we don't have any reasons to have Read and Write contexts
share and compete for the stream, because Read (decompression) and
Write (compression) paths are completely independent, they never
touch each other's buffers. Thus, we can split compression streams
into per-CPU Read streams and per-CPU Write streams (Barry Song),
so that Readers and Writers don't block each other anymore.
Decoupling Reads and Writes results in noticeable performance
improvements on synthetic tests. The Reader vs Reader priority
inversion is still possible. To attack this problem we introduce
shared decompression stream (Brian Geffon) which can be used when
decompression is stateless. There, however, stateful backends (zstd,
deflate) that cannot have shared decompression contexts. For those
backends, we introduce a remote CPU borrowing of idle exclusive
decompression contexts, if an exclusive Reader get preempted on
current CPU. We also now allocate a per-request (Read) bounce
buffer for linearisation of spanning zsmalloc objects, so stateless
decompression contexts do not block each other.

Reader vs Reader priority inversion tests:

exclusive zstd (fg reader, average of 3 runs):
Metric Base Patched
----------------------------------------------------------
Read IOPS 391k 1,064k (+2.7x)
Read clat avg 49.07 us 9.68 us (-5.1x)
Read clat stdev 7,179.16 us 30.64 us (-234x)
Read clat max 3,208,867 us 5,880.87 us (-546x)

shared lz4 (fg reader, average of 3 runs):
Metric Base Patched
----------------------------------------------------------
Read IOPS 972k 1,466k (+50.9%)
Read clat avg 11.56 us 3.29 us (-3.5x)
Read clat stdev 2,738.84 us 16.57 us (-165x)
Read clat max 2,204,467 us 6,442.50 us (-342x)

Writer vs Reader priority inversion tests:

lz4 (fg reader, average of 3 runs):
Metric Base Patched
----------------------------------------------------------
Read IOPS 642k 1,472k (+2.3x)
Read clat avg 23.97 us 3.28 us (-7.3x)
Read clat stdev 4,303.64 us 14.85 us (-290x)
Read clat max 2,393,767 us 5,710.53 us (-419x)

The final patch builds atop of decoupled Read and Write streams and
reworks the way secondary streams are handled. Secondary compression
streams are only used from recompression, which is serialized by
device lock, IOW it's single-threaded. However, we still allocated
secondary streams per-CPU (we needed to permit concurrent Reads
of recompressed objects). Because we now have dedicated R/W
streams, we can allocate a singleton compression context (for
recompression) yet still have per-CPU decompression contexts.
This saves a notable amount of memory with some backends and
configurations (e.g. zstd, deflate, lz4hc).

v4 - > v5:
-- borrow idle decompression streams in exclusive mode from remote CPUs
when exclusive reader is preempted.

Sergey Senozhatsky (13):
zram: prefix backends printk-s
zram: remove debugfs entry on init failure
zram: zstd: do not allocate empty C/D-dictionaries
zram: lz4hc: pre-initialize dictionary stream in setup_params
zram: lz4: use LZ4_decompress_safe_usingDict()
zram: lz4hc: use LZ4_decompress_safe_usingDict()
zram: zstd: do not use kvzalloc() for zstd allocations
zram: reset writeback state in zram_reset_device()
zram: split zcomp into separate R/W streams
zram: introduce shared decompression streams
zram: allocate bounce buffer for spanning objects
zram: borrow idle decompression streams in exclusive mode
zram: use a singleton compression context for recompression

drivers/block/zram/backend_842.c | 6 +-
drivers/block/zram/backend_deflate.c | 98 +++++----
drivers/block/zram/backend_lz4.c | 85 ++------
drivers/block/zram/backend_lz4hc.c | 105 ++++------
drivers/block/zram/backend_lzo.c | 6 +-
drivers/block/zram/backend_lzorle.c | 6 +-
drivers/block/zram/backend_zstd.c | 133 +++++++-----
drivers/block/zram/zcomp.c | 298 +++++++++++++++++++++++----
drivers/block/zram/zcomp.h | 53 ++++-
drivers/block/zram/zram_drv.c | 55 +++--
10 files changed, 542 insertions(+), 303 deletions(-)

--
2.56.0.176.g3575e65682-goog