All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kiryl Shutsemau <kirill@shutemov.name>
To: Ilya Gladyshev <ilya.gladyshev@linux.dev>
Cc: akpm@linux-foundation.org, andrew+netdev@lunn.ch,
	apopple@nvidia.com,  artem.kuzin@huawei.com,
	baolin.wang@linux.alibaba.com, david@kernel.org,
	 Liam.Howlett@oracle.com, edumazet@google.com,
	harry.yoo@oracle.com,  hramamurthy@google.com, ivgorbunov@me.com,
	joshwash@google.com,  linux-kernel@vger.kernel.org,
	linux-mm@kvack.org, lorenzo.stoakes@oracle.com, mhocko@suse.com,
	 muchun.song@linux.dev, pfalcato@suse.de, rppt@kernel.org,
	surenb@google.com,  torvalds@linuxfoundation.org, vbabka@suse.cz,
	willy@infradead.org, yuzhao@google.com,  ziy@nvidia.com
Subject: Re: [PATCH v6 3/3] mm: implement page refcount locking via dedicated bit
Date: Mon, 14 Sep 2026 11:39:00 +0100	[thread overview]
Message-ID: <aqe-sLv4L5SOHA6l@thinkstation> (raw)
In-Reply-To: <ebd6540ad89a4bb80e2a62d00901b5c827315b66.1789239015.git.ilya.gladyshev@linux.dev>

On Sat, Sep 12, 2026 at 10:50:10PM +0300, Ilya Gladyshev wrote:
> The current page refcount implementation uses a single counter value
> (zero) as dead. So, to prevent incrementing a dead refcount in
> folio_try_get(), it fundamentally requires a CAS loop.
> 
> This CAS loop can act as a serialization point and can become a
> significant bottleneck during high-frequency file read operations
> [1][2].
> 
> This patch reallocates the refcount value range:
> 
> (1) refcount < 0 means dead refcount (uninit / frozen)
> (2) refcount = 0 allowed only as a temporary state (see below)
> (3) refcount > 0 is a regular reference count
> 
> In other words, refcount is now split into "dead bit" and a 31-bit
> counter.
> 
> Refcount decrement now works as follows:
> 1. Counter decrement
> 2. If it is now zero, try to put it deep inside the dead zone
>    (CAS to INT_MIN). Or you can view it as "set up frozen bit and reset
>    counter".
> 3. This CAS can fail only if someone grabbed a reference in-between --
>    that's okay, this page is their problem now.
> 
> The size of the dead zone allows performing an optimistic increment
> inside page_ref_add_unless_frozen(), replacing the previous read + CAS
> loop with a single RMW operation. This reduces cache line bouncing and
> improves scalability, especially in NUMA scenarios.
> 
> [1]: https://lore.kernel.org/all/20251017141536.577466-1-kirill@shutemov.name/
> [2]: https://lore.kernel.org/all/CAHk-=wj00-nGmXEkxY=-=Z_qP6kiGUziSFvxHJ9N-cLWry5zpA@mail.gmail.com/
> 
> Reviewed-by: Artem Kuzin <artem.kuzin@huawei.com>
> Co-developed-by: Ivan Gorbunov <ivgorbunov@me.com>
> Signed-off-by: Ivan Gorbunov <ivgorbunov@me.com>
> Signed-off-by: Ilya Gladyshev <ilya.gladyshev@linux.dev>
> Acked-by: Linus Torvalds <torvalds@linuxfoundation.org>
> ---
>  include/linux/page-flags.h | 13 +++++++++++++
>  include/linux/page_ref.h   | 30 +++++++++++++++++++++++++-----
>  2 files changed, 38 insertions(+), 5 deletions(-)
> 
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 7a863572adce..b19721e0e7ca 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -196,6 +196,19 @@ enum pageflags {
>  
>  #define PAGEFLAGS_MASK		((1UL << NR_PAGEFLAGS) - 1)
>  
> +/* Most significant bit in page refcount */
> +#define PAGEREF_FROZEN_BIT BIT(31)

I am not sure about the naming here. I would expect _BIT to be 31.
Maybe we should name it _MASK?

#define PAGEREF_FROZEN_BIT	31
#define PAGEREF_FROZEN_MASK	BIT(PAGEREF_FROZEN_BIT)

> +
> +/* Page reference counter can be in 3 logical states,
> + * which are described below with their value representation
> + *        state              |         value
> + * (1)  safe with  owners    |   1...INT_MAX
> + * (2)  safe with no owners  |         0
> + * (3)  frozen               |  INT_MIN....-1
> + *
> + * State (2) can only temporarily occur inside dec_and_test.
> + */
> +

Do we what to enforce your comment about (2)? VM_WARN() in
page_ref_dec(), page_ref_sub() and _return() variants?

BTW, I wounder if all these VM_WARNs makes DEBUG_VM=y kernel too slow?
Do we need a separate config option to debug refcounts?

>  #ifndef __GENERATING_BOUNDS_H
>  
>  /*
> diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h
> index 82ff3a99297a..cc7a9d7db504 100644
> --- a/include/linux/page_ref.h
> +++ b/include/linux/page_ref.h
> @@ -64,7 +64,7 @@ static inline void __page_ref_unfreeze(struct page *page, int v)
>  
>  static inline bool __page_count_is_frozen(int count)
>  {
> -	return count == 0;
> +	return count & PAGEREF_FROZEN_BIT;
>  }
>  
>  static inline bool page_is_frozen(const struct page *page)
> @@ -79,7 +79,12 @@ static inline bool folio_is_frozen(const struct folio *folio)
>  
>  static inline int page_ref_count(const struct page *page)
>  {
> -	return atomic_read(&page->_refcount);
> +	int val = atomic_read(&page->_refcount);
> +
> +	if (unlikely(val & PAGEREF_FROZEN_BIT))
> +		return 0;
> +
> +	return val;

I was worried about the branch in the hot path and wanted to propose a
branchless hack -- val & ~(val >> 31) -- but compilers seem to be good
enough to generate CMOV. The hack produces one more instruction.

>  }
>  
>  /**
> @@ -150,7 +155,7 @@ static inline void init_page_count(struct page *page)
>  
>  static inline void set_page_count_frozen(struct page *page)
>  {
> -	set_page_count(page, 0);
> +	set_page_count(page, PAGEREF_FROZEN_BIT);

Are you sure we covered the cases that do frozen -> 1 transition with
page_ref_inc()?

Patch 2 switches __init_zone_device_page() to set_page_count_frozen().
Who unfreezes them?

Looking dax_fault_iter(), it seems to be done by folio_ref_inc() there
for FS_DAX case. Switching to PAGEREF_FROZEN_BIT would break it, no?

It seems some more ground work needed.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov


  reply	other threads:[~2026-09-14 10:39 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-12 19:50 [PATCH v6 0/3] mm: improve folio refcount scalability Ilya Gladyshev
2026-09-12 19:50 ` [PATCH v6 1/3] gve: reduce pagecnt_bias to USHRT_MAX Ilya Gladyshev
2026-09-12 19:50 ` [PATCH v6 2/3] mm: drop page refcount zero state semantics Ilya Gladyshev
2026-09-14  9:13   ` Kiryl Shutsemau
2026-09-12 19:50 ` [PATCH v6 3/3] mm: implement page refcount locking via dedicated bit Ilya Gladyshev
2026-09-14 10:39   ` Kiryl Shutsemau [this message]
2026-09-15  2:42   ` Zi Yan
2026-09-23 17:34     ` Ilya Gladyshev
2026-09-24 18:51       ` David Hildenbrand (Arm)
2026-09-24 20:06         ` Linus Torvalds
2026-09-25  2:44           ` Zi Yan
2026-09-25  7:03             ` Ilya Gladyshev
2026-09-25  7:06               ` David Hildenbrand (Arm)
2026-09-25 19:00               ` Linus Torvalds
2026-09-25 22:46                 ` Ilya Gladyshev
2026-09-25  7:15             ` David Hildenbrand (Arm)
2026-09-25 19:38   ` Matthew Wilcox
2026-09-25 23:13     ` Ilya Gladyshev
2026-09-14  0:06 ` [PATCH v6 0/3] mm: improve folio refcount scalability Andrew Morton
2026-09-14  8:10   ` Ilya Gladyshev

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=aqe-sLv4L5SOHA6l@thinkstation \
    --to=kirill@shutemov.name \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=apopple@nvidia.com \
    --cc=artem.kuzin@huawei.com \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=david@kernel.org \
    --cc=edumazet@google.com \
    --cc=harry.yoo@oracle.com \
    --cc=hramamurthy@google.com \
    --cc=ilya.gladyshev@linux.dev \
    --cc=ivgorbunov@me.com \
    --cc=joshwash@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lorenzo.stoakes@oracle.com \
    --cc=mhocko@suse.com \
    --cc=muchun.song@linux.dev \
    --cc=pfalcato@suse.de \
    --cc=rppt@kernel.org \
    --cc=surenb@google.com \
    --cc=torvalds@linuxfoundation.org \
    --cc=vbabka@suse.cz \
    --cc=willy@infradead.org \
    --cc=yuzhao@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 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.