Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Sergey Senozhatsky" <senozhatsky@chromium.org>,
	"Andrew Morton" <akpm@linux-foundation.org>
Cc: "Brian Geffon" <bgeffon@google.com>,
	"Barry Song" <baohua@kernel.org>,
	"Bo Zhang" <zhangbo0325@gmail.com>,
	"Minchan Kim" <minchan@kernel.org>,
	"Richard Chang" <richardycc@google.com>,
	linux-mm@kvack.org
Subject: Re: [PATCH v5 12/13] zram: borrow idle decompression streams in exclusive mode
Date: Mon, 19 Oct 2026 03:53:14 +0000	[thread overview]
Message-ID: <sashiko-outbox-176604@kernel.org> (raw)
In-Reply-To: <20261018035125.3120704-13-senozhatsky@chromium.org>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] zram: raw_smp_processor_id() re-evaluated in zcomp_dstrm_excl_tryget() loop
--

commit a4463f4c7972dc5e8129cff84e8c92b3498b7a73
Author: Sergey Senozhatsky <senozhatsky@chromium.org>

zram: borrow idle decompression streams in exclusive mode

This commit allows exclusive decompression stream requests to scan online
CPUs and borrow an idle per-CPU decompression stream before falling back
to sleeping on a per-zcomp waitqueue.

> diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
> index 4fda13aac8965..c6d2fd23c6f66 100644
> --- a/drivers/block/zram/zcomp.c
> +++ b/drivers/block/zram/zcomp.c
> @@ -185,38 +185,67 @@ bool zcomp_shared_decomp(struct zcomp *comp)
>  	return !comp->ops->create_dctx;
>  }
>  
> +static bool zcomp_dstrm_excl_trylock(struct zcomp_dstrm *zstrm)
> +{
> +	/* Cheap pre-check: don't touch a busy stream's cachelines */
> +	if (mutex_is_locked(&zstrm->excl_lock))
> +		return false;
> +	/*
> +	 * Pin the stream.  The write side of ->lock is only taken by
> +	 * zcomp_cpu_dead(), which also sets ->local_copy to NULL.
> +	 */
> +	if (!down_read_trylock(&zstrm->lock))
> +		return false;
> +	if (zstrm->local_copy && mutex_trylock(&zstrm->excl_lock))
> +		return true;
> +	up_read(&zstrm->lock);
> +	return false;
> +}
> +
> +static struct zcomp_dstrm *zcomp_dstrm_excl_tryget(struct zcomp *comp)
> +{
> +	struct zcomp_dstrm *zstrm;
> +	unsigned int cpu;
> +
> +	/* Best-effort start CPU hint; migration during the scan is fine */
> +	for_each_online_cpu_wrap(cpu, raw_smp_processor_id()) {
> +		zstrm = per_cpu_ptr(comp->dstream, cpu);
> +		if (zcomp_dstrm_excl_trylock(zstrm))
> +			return zstrm;
> +	}
> +	return NULL;
> +}

[Severity: High]
Does passing raw_smp_processor_id() directly as the start argument to
for_each_online_cpu_wrap() in zcomp_dstrm_excl_tryget() break the loop
termination logic when the task migrates during the scan?

for_each_online_cpu_wrap() expands via for_each_cpu_wrap() to
for_each_set_bit_wrap() in include/linux/find.h:

#define for_each_set_bit_wrap(bit, addr, size, start) \
	for ((bit) = find_next_bit_wrap((addr), (size), (start));		\
	     (bit) < (size);							\
	     (bit) = __for_each_wrap((addr), (size), (start), (bit) + 1))

Because start is expanded inside __for_each_wrap() on every step,
raw_smp_processor_id() is re-evaluated on each iteration rather than
once at the beginning of the loop.

__for_each_wrap() relies on start remaining constant across the loop to
know whether the scan has wrapped around:

	/* If not wrapped around */
	if (n > start) {
		/* and have a bit, just return it. */
		bit = find_next_bit(bitmap, size, n);
		if (bit < size)
			return bit;

		/* Otherwise, wrap around and ... */
		n = 0;
	}

	/* Search the other part. */
	bit = find_next_bit(bitmap, start, n);
	return bit < start ? bit : size;

Since zcomp_dstrm_get() calls zcomp_dstrm_excl_tryget() in preemptible
context with migration enabled, if a task fails zcomp_dstrm_excl_trylock()
on CPU k and migrates to CPU m >= k + 1 before the step expression runs,
__for_each_wrap() sees n = k + 1 <= start (where start is now m). It then
treats the scan as having already wrapped and only searches [k + 1, m)
(returning size immediately if m == k + 1), skipping CPU m and the
remaining online CPUs.

When that happens, zcomp_dstrm_excl_tryget() returns NULL and
zcomp_dstrm_get() sleeps in wait_event() on comp->dstrm_waitq even when
idle streams are available on the skipped CPUs. In the case where CPU k
is concurrently taken offline (so zcomp_cpu_dead() sets local_copy to NULL
without waking comp->dstrm_waitq and the task is migrated off CPU k) while
all other online streams are idle, no task holds excl_lock to wake
comp->dstrm_waitq and the caller can sleep in TASK_UNINTERRUPTIBLE
indefinitely.

Should raw_smp_processor_id() be stored in a local variable before passing
it to for_each_online_cpu_wrap()?

[ ... ]

>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261018035125.3120704-1-senozhatsky@chromium.org?part=12


  reply	other threads:[~2026-10-19  3:53 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18  3:51 [PATCH v5 00/13] zram: redesign zcomp and rework backends Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 01/13] zram: prefix backends printk-s Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 02/13] zram: remove debugfs entry on init failure Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 03/13] zram: zstd: do not allocate empty C/D-dictionaries Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 04/13] zram: lz4hc: pre-initialize dictionary stream in setup_params Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 05/13] zram: lz4: use LZ4_decompress_safe_usingDict() Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 06/13] zram: lz4hc: " Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 07/13] zram: zstd: do not use kvzalloc() for zstd allocations Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 08/13] zram: reset writeback state in zram_reset_device() Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 09/13] zram: split zcomp into separate R/W streams Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 10/13] zram: introduce shared decompression streams Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 11/13] zram: allocate bounce buffer for spanning objects Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 12/13] zram: borrow idle decompression streams in exclusive mode Sergey Senozhatsky
2026-10-19  3:53   ` sashiko-bot [this message]
2026-10-19  4:01     ` Sergey Senozhatsky
2026-10-18  3:51 ` [PATCH v5 13/13] zram: use a singleton compression context for recompression Sergey Senozhatsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-176604@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=baohua@kernel.org \
    --cc=bgeffon@google.com \
    --cc=linux-mm@kvack.org \
    --cc=minchan@kernel.org \
    --cc=richardycc@google.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=senozhatsky@chromium.org \
    --cc=zhangbo0325@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox