Re: [RFC PATCH] zram: avoid preemption with CPU-based compression backends

From: Barry Song

Date: Wed Aug 05 2026 - 06:39:56 EST


On Wed, Aug 5, 2026 at 6:25 PM Sergey Senozhatsky
<senozhatsky@xxxxxxxxxxxx> wrote:
>
> Hi Barry,
>
> On (26/08/05 15:50), Barry Song wrote:
> > BTW, I wonder if compression and decompression could use separate
> > mutexes. That way, a sleepable zs_malloc() in the compression path
> > would not block decompression, which is the more latency-sensitive
> > operation.
>
> quick and dirty patch. Just curious if this improves anything on your
> side.
>

Thanks very much for your quick patch, Sergey.

We are going to run three experiments:

1. Use the approach I just sent, which avoids calling zs_malloc()
with direct reclaim while holding the mutex, and extend it to
the other zs_malloc() call sites:

https://lore.kernel.org/all/20260805100740.71994-1-baohua@xxxxxxxxxx/

2. Experiment 1 plus preemption disabled.

3. Your patch, which separates the compression and decompression
mutexes.

I'd like to understand which change has the biggest impact on
performance.

Let me gather some data, and I'll get back to you.

> We also maybe can have more that num_online_cpus() stream, if we
> switch to idle streams list instead [1]
>
> [1] https://lore.kernel.org/lkml/20250130111105.2861324-3-senozhatsky@xxxxxxxxxxxx/
>
> ----
>
> diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
> index 974c4691887e..3c523ea0dc27 100644
> --- a/drivers/block/zram/zcomp.c
> +++ b/drivers/block/zram/zcomp.c
> @@ -112,21 +112,28 @@ ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at)
> return at;
> }
>
> -struct zcomp_strm *zcomp_stream_get(struct zcomp *comp)
> +struct zcomp_strm *zcomp_stream_get_write(struct zcomp *comp)
> {
> for (;;) {
> - struct zcomp_strm *zstrm = raw_cpu_ptr(comp->stream);
> -
> - /*
> - * Inspired by zswap
> - *
> - * stream is returned with ->mutex locked which prevents
> - * cpu_dead() from releasing this stream under us, however
> - * there is still a race window between raw_cpu_ptr() and
> - * mutex_lock(), during which we could have been migrated
> - * from a CPU that has already destroyed its stream. If
> - * so then unlock and re-try on the current CPU.
> - */
> + struct zcomp_strm *zstrm = raw_cpu_ptr(comp->stream_write);
> +
> + mutex_lock(&zstrm->lock);
> + if (likely(zstrm->buffer))
> + return zstrm;
> + mutex_unlock(&zstrm->lock);
> + }
> +}
> +
> +void zcomp_stream_put_write(struct zcomp_strm *zstrm)
> +{
> + mutex_unlock(&zstrm->lock);
> +}
> +
> +struct zcomp_strm *zcomp_stream_get_read(struct zcomp *comp)
> +{
> + for (;;) {
> + struct zcomp_strm *zstrm = raw_cpu_ptr(comp->stream_read);
> +
> mutex_lock(&zstrm->lock);
> if (likely(zstrm->buffer))
> return zstrm;
> @@ -134,7 +141,7 @@ struct zcomp_strm *zcomp_stream_get(struct zcomp *comp)
> }
> }
>
[...]

Best Regards
Barry