From: sashiko-bot@kernel.org
To: "Hiroshi Nishida" <nishidafmly@gmail.com>
Cc: linux-raid@vger.kernel.org, yukuai@fygo.io
Subject: Re: [PATCH 2/6] md/raid5: size stripe-cache hash locks from the CPU count
Date: Fri, 10 Jul 2026 13:41:07 +0000 [thread overview]
Message-ID: <20260710134107.A1E1F1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260710132346.7295-3-nishidafmly@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Time-of-check to time-of-use (TOCTOU) race condition in `nr_stripe_hash_locks` module parameter evaluation can lead to undefined behavior and a potential kernel panic during array creation.
Pre-existing issues:
- [High] The worker threads (`r5worker->work`) are not explicitly canceled or flushed during array teardown, which can lead to a Use-After-Free.
--
--- Patch [2]: [PATCH 2/6] md/raid5: size stripe-cache hash locks from the CPU count ---
commit bae2376a7fe52c6b3de7d64514b554d3101957fe
Author: Hiroshi Nishida <nishidafmly@gmail.com>
md/raid5: size stripe-cache hash locks from the CPU count
This commit modifies the stripe cache hash to use a per-array dynamic count
of spinlocks instead of a fixed 8, automatically sizing it based on the
online CPU count to reduce lock contention on many-core systems.
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index d8807114a6932..7f72981121fd5 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
[ ... ]
> @@ -7448,6 +7453,9 @@ static void free_conf(struct r5conf *conf)
> kfree(conf->disks);
> bioset_exit(&conf->bio_split);
> kfree(conf->stripe_hashtbl);
> + kfree(conf->hash_locks);
> + kfree(conf->inactive_list);
> + kfree(conf->temp_inactive_list);
> kfree(conf->pending_data);
[Severity: High]
This is a pre-existing issue, but looking at the teardown sequence, could
the worker threads access freed memory here?
During array teardown, md_stop() eventually causes a wait for
active_stripes to reach 0. In a worker thread executing raid5_do_work(),
active_stripes drops to 0 when handle_active_stripes() finishes releasing
the final stripes.
At this point, raid5_quiesce() wakes up and teardown proceeds to call
free_thread_groups() which frees the worker structures without calling
flush_workqueue() or cancel_work_sync().
The still-executing worker thread could then drop its lock and continue
to execute flush_deferred_bios() and r5l_flush_stripe_to_raid() using the
freed structures.
Should the worker threads be explicitly canceled or flushed before the
structures are freed?
[ ... ]
> @@ -7565,6 +7573,38 @@ static struct r5conf *setup_conf(struct mddev *mddev)
> if (conf == NULL)
> goto abort;
>
> + /*
> + * Size the stripe cache hash-lock striping per array. The
> + * nr_stripe_hash_locks module parameter selects the count: 0 (the
> + * default) auto-sizes it from the online CPU count so busier machines
> + * stripe the locks wider, while a non-zero value overrides that. The
> + * result is rounded up to a power of two (the hash uses it as a
> + * bitmask) and capped at NR_STRIPE_HASH_LOCKS_MAX; the auto path also
> + * keeps at least the historical NR_STRIPE_HASH_LOCKS_DEFAULT so small
> + * systems are unchanged. Allocating per array means an untuned system
> + * uses no more memory than before.
> + */
> + if (nr_stripe_hash_locks == 0)
> + conf->nr_hash_locks = clamp_t(unsigned int,
> + roundup_pow_of_two(num_online_cpus()),
> + NR_STRIPE_HASH_LOCKS_DEFAULT,
> + NR_STRIPE_HASH_LOCKS_MAX);
> + else
> + conf->nr_hash_locks = roundup_pow_of_two(
> + min_t(unsigned int, nr_stripe_hash_locks,
> + NR_STRIPE_HASH_LOCKS_MAX));
[Severity: High]
Could this be vulnerable to a time-of-check to time-of-use race if the
sysfs parameter is modified concurrently?
If the module parameter is changed from a non-zero value to 0 right after
the check:
Thread 1 in setup_conf():
if (nr_stripe_hash_locks == 0)
// check fails, proceeds to else block
Thread 2 writing to sysfs:
nr_stripe_hash_locks = 0;
Thread 1 inside the else block:
conf->nr_hash_locks = roundup_pow_of_two(min_t(..., 0, ...));
In this scenario, roundup_pow_of_two() would evaluate to 0. When kcalloc()
is subsequently called, it would return the zero size pointer placeholder
value (16).
The safety check testing for a null pointer would fail to catch this since
16 is non-null, and the kernel could panic when spin_lock_init()
dereferences it.
Would it be safer to read the parameter into a local variable first?
unsigned int locks = READ_ONCE(nr_stripe_hash_locks);
if (locks == 0)
conf->nr_hash_locks = clamp_t(...);
else
conf->nr_hash_locks = roundup_pow_of_two(...);
> + conf->hash_locks_mask = conf->nr_hash_locks - 1;
> + conf->hash_locks = kcalloc(conf->nr_hash_locks,
> + sizeof(*conf->hash_locks), GFP_KERNEL);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710132346.7295-1-nishidafmly@gmail.com?part=2
next prev parent reply other threads:[~2026-07-10 13:41 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 13:23 [PATCH 0/6] md/raid5: size stripe-cache and worker tuning from the hardware Hiroshi Nishida
2026-07-10 13:23 ` [PATCH 1/6] md/raid5: size the worker group array by nr_node_ids Hiroshi Nishida
2026-07-10 13:39 ` sashiko-bot
2026-07-10 13:23 ` [PATCH 2/6] md/raid5: size stripe-cache hash locks from the CPU count Hiroshi Nishida
2026-07-10 13:41 ` sashiko-bot [this message]
2026-07-10 13:23 ` [PATCH 3/6] md/raid5: scale the stripe_cache_size limit with system memory Hiroshi Nishida
2026-07-10 13:34 ` sashiko-bot
2026-07-10 13:23 ` [PATCH 4/6] md/raid5: make the stripe batch size a module parameter Hiroshi Nishida
2026-07-10 13:36 ` sashiko-bot
2026-07-10 13:23 ` [PATCH 5/6] md/raid5: scale the default stripe cache size with system memory Hiroshi Nishida
2026-07-10 13:37 ` sashiko-bot
2026-07-10 13:23 ` [PATCH 6/6] md/raid5: derive the default group_thread_cnt from the hardware Hiroshi Nishida
2026-07-10 13:42 ` sashiko-bot
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=20260710134107.A1E1F1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-raid@vger.kernel.org \
--cc=nishidafmly@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=yukuai@fygo.io \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.