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 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.