Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Kairui Song" <kasong@tencent.com>, linux-mm@kvack.org
Cc: "David Hildenbrand" <david@kernel.org>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Liam R. Howlett" <liam@infradead.org>,
	"Vlastimil Babka" <vbabka@kernel.org>,
	"Mike Rapoport" <rppt@kernel.org>,
	"Suren Baghdasaryan" <surenb@google.com>,
	"Michal Hocko" <mhocko@suse.com>,
	"Matthew Wilcox" <willy@infradead.org>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Johannes Weiner" <hannes@cmpxchg.org>,
	"Michal Hocko" <mhocko@kernel.org>,
	"Qi Zheng" <qi.zheng@linux.dev>,
	"Shakeel Butt" <shakeel.butt@linux.dev>,
	"Barry Song" <baohua@kernel.org>,
	"Axel Rasmussen" <axelrasmussen@google.com>,
	"Yuanchu Xie" <yuanchu@google.com>, "Wei Xu" <weixugc@google.com>,
	"Baoquan He" <baoquan.he@linux.dev>,
	"Baolin Wang" <baolin.wang@linux.alibaba.com>,
	"Zi Yan" <ziy@nvidia.com>, "Nico Pache" <nico.pache@linux.dev>,
	"Ryan Roberts" <ryan.roberts@arm.com>,
	"Dev Jain" <dev.jain@arm.com>,
	"Lance Yang" <lance.yang@linux.dev>,
	"Usama Arif" <usama.arif@linux.dev>,
	"Kiryl Shutsemau" <kas@kernel.org>
Subject: Re: [PATCH RFC 2/8] xarray: add xas_prev_canonical()
Date: Sat, 14 Nov 2026 21:27:17 +0000	[thread overview]
Message-ID: <sashiko-outbox-215042@kernel.org> (raw)
In-Reply-To: <20261114-swap-thp-split-v1-2-dfa8d4fa448d@tencent.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] xarray: xas_prev_canonical() corrupts xa_index on
  XA_RETRY_ENTRY
- [Medium] xarray: xas_prev_canonical() steps off non-leaf canonical
  slot on split
--

commit b768624f5f5a261ca8a1796cf3f8c4a5e5deca0d
Author: Kairui Song <kasong@tencent.com>

xarray: add xas_prev_canonical()

This commit adds xas_prev_canonical() to step backwards over multi-index
XArray entries onto the canonical slot and first index covered by the
entry, along with test cases in the XArray test suite.

> diff --git a/include/linux/xarray.h b/include/linux/xarray.h
> index be850174e802e..b76d24e7a46b3 100644
> --- a/include/linux/xarray.h
> +++ b/include/linux/xarray.h
[ ... ]
> @@ -1883,6 +1892,46 @@ static inline void *xas_prev(struct xa_state *xas)
>  	return xa_entry(xas->xa, node, xas->xa_offset);
>  }
>  
> +/**
> + * xas_prev_canonical() - Move iterator to the previous entry, onto the slot
> + * which stores it.
> + * @xas: XArray operation state.
> + *
> + * Same as xas_prev(), but it steps back over a multi-index entry as a
> + * whole: the state is left on the slot which stores the entry and on its
> + * first index, so xas_get_order() reports its order.  A cursor already
> + * inside an entry reports that entry instead of stepping off it.
> + *
> + * Context: Any context.  Hold the xa_lock or the RCU lock across the
> + * whole walk; xas_pause() is forward-only.
> + * Return: The entry at the new position, or %NULL (empty slot, error
> + * state, or the end of the walk).  The result may be an internal entry,
> + * which needs xas_retry().
> + */
> +static inline void *xas_prev_canonical(struct xa_state *xas)
> +{
> +	void *entry = NULL;
> +
> +	/* step back unless @xas is already inside an entry */
> +	if (!xas_is_node(xas) ||
> +	    xas->xa_offset >= XA_CHUNK_SIZE ||
> +	    xas->xa_offset == ((xas->xa_index >> xas->xa_node->shift) &
> +			       XA_CHUNK_MASK))
> +		entry = xas_prev(xas);

[Severity: Medium]
Does shifting xas->xa_index right by xas->xa_node->shift step off an entry
when the cursor is at a non-initial index inside the canonical slot of an
internal node?

When an entry has order >= XA_CHUNK_SHIFT (xas->xa_node->shift > 0), the
canonical slot itself covers (1UL << xas->xa_node->shift) indices.
Discarding the lower shift bits makes xas->xa_offset equal
((xas->xa_index >> xas->xa_node->shift) & XA_CHUNK_MASK) for every index
within that canonical slot, so xas_prev_canonical() calls xas_prev(xas)
even when xas->xa_index is past the first index of the entry:

CPU0                              CPU1
xas_load(&xas)
  /* order-6 entry at [128, 191],
     xas_index = 150, shift = 6,
     xa_offset = 2 */
                                  xas_split()
                                    /* splits slot 2 into child node */
xas_prev_canonical(&xas)
  /* (150 >> 6) & 63 == 2 */
  xas_prev(&xas)
    __xas_prev(&xas)
      xas->xa_index--; /* 149 */
      /* descends into child node
         at 149 instead of retrying
         at 150 */                <-- skips entry at 150

Preserving the lower shift bits the way xas_sibling() does (comparing
xas->xa_index & ((XA_CHUNK_SIZE << node->shift) - 1) against
(unsigned long)xas->xa_offset << node->shift) would avoid calling
xas_prev() when the cursor is already inside the canonical slot.

> +	if (!xas_is_node(xas))
> +		return entry;
> +	if (xa_is_sibling(entry))
> +		xas->xa_offset = xa_to_sibling(entry);
> +
> +	entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset);
> +	/* a concurrent store or split can leave a sibling or a node here */
> +	if (xa_is_sibling(entry) ||
> +	    (xas->xa_node->shift && xa_is_node(entry)))
> +		return XA_RETRY_ENTRY;
> +	xas_move_index(xas, xas->xa_offset);
> +	return entry;
> +}

[Severity: Medium]
Can xas_prev_canonical() move xas->xa_index backwards before returning
XA_RETRY_ENTRY, or lose an XA_RETRY_ENTRY returned by xas_prev()?

During a lockless RCU walk, xas_retry() calls xas_reset(), which sets
xas->xa_node = XAS_RESTART and relies on xas->xa_index remaining at the
index that needs to be retried so the next __xas_prev() call reloads that
same index.  Here, if xas_prev() returns a sibling entry and the canonical
slot at xas->xa_offset has been overwritten with XA_RETRY_ENTRY by a
concurrent xas_free_nodes() or xas_shrink(), XA_RETRY_ENTRY is neither a
sibling nor a node, so execution calls xas_move_index(xas, xas->xa_offset)
before returning XA_RETRY_ENTRY:

CPU0                              CPU1
xas_prev_canonical(&xas)
  entry = xas_prev(&xas)
    /* lands on sibling slot,
       returns xa_mk_sibling(off) */
  xas->xa_offset = off;
                                  xas_free_nodes()
                                    /* overwrites slot[off] with
                                       XA_RETRY_ENTRY */
  entry = xa_entry(..., off);
    /* entry is XA_RETRY_ENTRY */
  xas_move_index(&xas, off);      <-- lowers xas->xa_index
  return XA_RETRY_ENTRY;
xas_retry(&xas, entry)
  xas_reset(&xas);
xas_prev_canonical(&xas)
  __xas_prev(&xas)
    xas_load(&xas)                <-- reloads at lowered xa_index,
                                      skipping intermediate entries

In addition, if xas_prev() itself returns XA_RETRY_ENTRY (for example via
__xas_prev() -> xas_load() -> xas_descend() when a sibling in an internal
node was concurrently split into a child node), xas_prev_canonical()
unconditionally overwrites entry with xa_entry() and loses the retry if
that canonical slot was concurrently replaced with a normal entry.

Checking xa_is_retry(entry) after xas_prev() and before xas_move_index()
would preserve both the retry entry and xas->xa_index.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114-swap-thp-split-v1-0-dfa8d4fa448d@tencent.com?part=2


  reply	other threads:[~2026-11-14 21:27 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-13 21:26 [PATCH RFC 0/8] mm/huge_memory: clean up and speed up large folio splitting Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 1/8] mm: add folio_prev() Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 2/8] xarray: add xas_prev_canonical() Kairui Song via B4 Relay
2026-11-14 21:27   ` sashiko-bot [this message]
2026-11-13 21:26 ` [PATCH RFC 3/8] mm/huge_memory: avoid an unnecessary folio size reading Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 4/8] mm/huge_memory: walk the after-split file folios in reverse order Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 5/8] mm/huge_memory: publish split folios by walking backwards Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 6/8] mm/huge_memory: rearrange split routine handling for better optimization Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 7/8] mm/huge_memory: walk the after-split anon folios in reverse order Kairui Song via B4 Relay
2026-11-13 21:26 ` [PATCH RFC 8/8] mm/huge_memory: walk the folios reversely for the release loop Kairui Song via B4 Relay
2026-11-14 21:27   ` sashiko-bot
2026-11-13 21:40 ` [PATCH RFC 0/8] mm/huge_memory: clean up and speed up large folio splitting David Hildenbrand (Arm)
2026-11-13 21:46   ` Kairui Song

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-215042@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=baohua@kernel.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=baoquan.he@linux.dev \
    --cc=david@kernel.org \
    --cc=dev.jain@arm.com \
    --cc=hannes@cmpxchg.org \
    --cc=kas@kernel.org \
    --cc=kasong@tencent.com \
    --cc=lance.yang@linux.dev \
    --cc=liam@infradead.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@kernel.org \
    --cc=mhocko@suse.com \
    --cc=nico.pache@linux.dev \
    --cc=qi.zheng@linux.dev \
    --cc=rppt@kernel.org \
    --cc=ryan.roberts@arm.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=surenb@google.com \
    --cc=usama.arif@linux.dev \
    --cc=vbabka@kernel.org \
    --cc=weixugc@google.com \
    --cc=willy@infradead.org \
    --cc=yuanchu@google.com \
    --cc=ziy@nvidia.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