From: Wolfram Sang <wsa+renesas@sang-engineering.com>
To: linux-renesas-soc@vger.kernel.org, Matthew Wilcox <willy@infradead.org>
Cc: Bjorn Andersson <andersson@kernel.org>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
linux-remoteproc@vger.kernel.org,
sashiko-reviews@lists.linux.dev
Subject: 3 XArray questions (was: Re: [PATCH v3 1/2] hwspinlock: Convert to XArray)
Date: Tue, 14 Jul 2026 21:49:19 +0200 [thread overview]
Message-ID: <alaSvyTylYZ0csVd@shikoro> (raw)
In-Reply-To: <20260713124622.63181-2-wsa+renesas@sang-engineering.com>
Hi Matthew,
Sashiko found issues with the XArray conversion[1]. I tried to educate
myself enough to evaluate its findings. Yet, I'd be happy if you could
double-check my reasoning. Note: I left all issues with use-after-free
aside. Reason is that the hwspinlock subsystem has so many problems with
removing locks that I proposed to remove the removal[2].
[1] https://sashiko.dev/#/patchset/20260713124622.63181-1-wsa%2Brenesas%40sang-engineering.com
[2] https://lkml.iu.edu/2605.1/07475.html
Now for the issues:
> > + xas_lock(&xas);
> > + existing = xas_load(&xas);
> > + if (existing) {
> > + pr_err("hwspinlock id %d already exists!\n", id);
> > + xas_set_err(&xas, -EBUSY);
> > }
> > + xas_store(&xas, hwlock);
>
> [Severity: High]
> Could xas_store() fail with -ENOMEM under mild memory fragmentation?
>
> Because xas_lock() acquires a spinlock, XArray's internal node allocations
> are restricted to GFP_NOWAIT. XArray typically requires callers modifying the
> array under a lock to wrap the operation in a xas_nomem() retry loop,
> similar to:
>
> do {
> xas_lock(&xas);
> ...
> xas_store(&xas, hwlock);
> ...
> xas_unlock(&xas);
> } while (xas_nomem(&xas, GFP_KERNEL));
>
> Without this loop, the GFP_NOWAIT allocation failure would be fatal. Could
> this cause hardware spinlock registration to fail spuriously?
Reading the documentation of xas_nomem(), I think Sashiko is right and
such a loop is needed, or?
> > /* mark this hwspinlock as available */
> > - tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
> > + xas_set_mark(&xas, HWSPINLOCK_UNUSED);
> > + ret = xas_error(&xas);
> > + xas_unlock(&xas);
> >
> > - /* self-sanity check which should never fail */
> > - WARN_ON(tmp != hwlock);
> > -
> > -out:
> > - mutex_lock(&hwspinlock_tree_lock);
> > return ret;
> > }
> >
> > static struct hwspinlock *hwspin_lock_unregister_single(unsigned int id)
> > {
> > + XA_STATE(xas, &hwspinlocks, id);
> > struct hwspinlock *hwlock = NULL;
> > - int ret;
> > + bool unused;
> >
> > - mutex_lock(&hwspinlock_tree_lock);
> > + xas_lock(&xas);
> >
> > - /* make sure the hwspinlock is not in use (tag is set) */
> > - ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
> > - if (ret == 0) {
> > + /* make sure the hwspinlock is not in use (mark is set) */
> > + unused = xas_get_mark(&xas, HWSPINLOCK_UNUSED);
>
> [Severity: High]
> Does xas_get_mark() return the correct value here?
>
> Since the XA_STATE is freshly initialized and xas_load() hasn't been called
> to walk the tree, xas->xa_node is NULL. In this state, xas_get_mark() queries
> the global root mark of the XArray.
>
> If any lock in the XArray is unused, won't this return true, potentially
> allowing active locks to be erroneously deleted?
Despite I intend to remove this function in the future anyhow, the fix
for this issue is a simple 'xas_load(&xas);' right before
'xas_get_mark()'?
> > @@ -782,12 +753,12 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
> > }
> >
> > dev = hwlock->bank->dev;
> > - mutex_lock(&hwspinlock_tree_lock);
> > + xas_lock(&xas);
> > + xas_set(&xas, hwlock_to_id(hwlock));
> >
> > /* make sure the hwspinlock is used */
> > - ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock),
> > - HWSPINLOCK_UNUSED);
> > - if (ret == 1) {
> > + unused = xas_get_mark(&xas, HWSPINLOCK_UNUSED);
>
> [Severity: High]
> Will xas_get_mark() silently abort here?
>
> Calling xas_set() initializes the state to XAS_RESTART, which makes
> xas_invalid() evaluate to true. Because of this, both xas_get_mark() and the
> subsequent xas_set_mark() further down will silently return or abort without
> performing their intended operations.
>
> Could this prevent the lock from being marked as available again, effectively
> leaking it permanently?
Not sure if I parse this correctly, but I think xas_load() is also
needed after xas_set() and before xas_get_mark()?
Thanks and happy hacking,
Wolfram
next prev parent reply other threads:[~2026-07-14 19:49 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 12:46 [PATCH v3 0/2] hwspinlock: convert to XArray and add summary in debugfs Wolfram Sang
2026-07-13 12:46 ` [PATCH v3 1/2] hwspinlock: Convert to XArray Wolfram Sang
2026-07-14 19:49 ` Wolfram Sang [this message]
2026-07-13 12:46 ` [PATCH v3 2/2] hwspinlock: add list of mailboxes to debugfs Wolfram Sang
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=alaSvyTylYZ0csVd@shikoro \
--to=wsa+renesas@sang-engineering.com \
--cc=andersson@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=linux-remoteproc@vger.kernel.org \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=willy@infradead.org \
/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