Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Kairui Song <ryncsn@gmail.com>
To: Youngjun Park <youngjun.park@lge.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	 Chris Li <chrisl@kernel.org>, Kairui Song <kasong@tencent.com>,
	 Kemeng Shi <shikemeng@huaweicloud.com>,
	Nhat Pham <nphamcs@gmail.com>, Baoquan He <baoquan.he@linux.dev>,
	 Barry Song <baohua@kernel.org>,
	Jianyue Wu <wujianyue000@gmail.com>,
	her0gyugyu@gmail.com,  linux-mm@kvack.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/4] mm, swap: give hibernation swap slots their own swap table entry type
Date: Sat, 8 Aug 2026 21:25:47 +0800	[thread overview]
Message-ID: <ancjiz6-qyC0ki4O@KASONG-MC4> (raw)
In-Reply-To: <20260806190636.446205-3-youngjun.park@lge.com>

On Fri, Aug 07, 2026 at 04:06:34AM +0800, Youngjun Park wrote:
> swap_alloc_hibernation_slot() stores a fake shadow in the slot it hands
> out.  An anon slot swapped out with no workingset shadow looks exactly the
> same, so nothing in mm can tell the two apart.
> 
> Give hibernation slots their own type.  Bit 4 and every bit above it are
> set, the same shape as SWP_TB_BAD.  Bits 0 to 3 are taken by the shadow,
> PFN, pointer and bad marks, so bit 4 is the first free one.  Neither type
> holds data, so the value alone says what it is.
> 
> The entry has no swap count.  Hibernation only allocates and frees a slot,
> so a count would never change.  swap_free_hibernation_slot() frees the slot
> directly, there is no count to put first.
> 
> The next patch needs these slots to stop looking like shadows.
> 
> Suggested-by: Kairui Song <kasong@tencent.com>
> Link: https://lore.kernel.org/linux-mm/abp7aDgYLrxF3Me8@KASONG-MC4/
> Signed-off-by: Youngjun Park <youngjun.park@lge.com>
> ---
>  mm/swap_table.h | 12 ++++++++++++
>  mm/swapfile.c   | 13 +++++++------
>  2 files changed, 19 insertions(+), 6 deletions(-)
> 
> diff --git a/mm/swap_table.h b/mm/swap_table.h
> index e6613e62f8d0..c1c516bcc17e 100644
> --- a/mm/swap_table.h
> +++ b/mm/swap_table.h
> @@ -30,6 +30,7 @@ struct swap_memcg_table {
>   * PFN:      |SWAP_COUNT|Z|------ PFN -------|10| - Cached slot
>   * Pointer:  |----------- Pointer ----------|100| - (Unused)
>   * Bad:      |------------- 1 -------------|1000| - Bad slot
> + * Hibern:   |------------ 1 -------------|10000| - Hibernation slot

Nice!

Just one idea, would it be nicer if we have:
* Hibern:   |   0   |------- 1 -------------|10000| - Hibernation slot

Or:
* Hibern:   |0..001|------- 1 -------------|10000| - Hibernation slot

That way if we accidentally used __swp_tb_get_count, it return a actual
meaningful value instead of MAX. Either 0 - the slot is not used as
a countable ordinary slot, or 1 - the slot has one user: hibernation.

Maybe 0 is better at least for the intermediate commit, see below.

>  
> +static inline bool swp_tb_is_hibernation(unsigned long swp_tb)
> +{
> +	return swp_tb == SWP_TB_HIB;
> +}
> +
>  static inline bool swp_tb_is_countable(unsigned long swp_tb)
>  {
>  	return (swp_tb_is_shadow(swp_tb) || swp_tb_is_folio(swp_tb) ||
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index f5dfc7e59191..a337387f7431 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -928,7 +928,7 @@ static bool __swap_cluster_alloc_entries(struct swap_info_struct *si,
>  	 * upon folio unmap.
>  	 *
>  	 * Else, it's a exclusive order 0 allocation for hibernation.
> -	 * The slot starts with count == 1 and never increases.
> +	 * The slot carries no swap count and is freed by offset.
>  	 */
>  	if (likely(folio)) {
>  		order = folio_order(folio);
> @@ -940,8 +940,8 @@ static bool __swap_cluster_alloc_entries(struct swap_info_struct *si,
>  		order = 0;
>  		nr_pages = 1;
>  		swap_cluster_assert_empty(ci, ci_off, 1, false);
> -		/* Fake shadow placeholder with no flag, hibernation does not use the zeromap */
> -		__swap_table_set(ci, ci_off, __swp_tb_mk_count(shadow_to_swp_tb(NULL, 0), 1));
> +		/* Exclusively owned by hibernation, must never enter the swap cache */
> +		__swap_table_set(ci, ci_off, SWP_TB_HIB);
>  	} else {
>  		/* Allocation without folio is only possible with hibernation */
>  		WARN_ON_ONCE(1);
> @@ -1929,9 +1929,11 @@ void __swap_cluster_free_entries(struct swap_info_struct *si,
>  		old_tb = __swap_table_get(ci, ci_off);
>  		/*
>  		 * Freeing is done after release of the last swap count
> -		 * ref, or after swap cache is dropped
> +		 * ref, or after swap cache is dropped. A hibernation slot
> +		 * has no count and is freed directly by its owner.
>  		 */
> -		VM_WARN_ON(!swp_tb_is_shadow(old_tb) || __swp_tb_get_count(old_tb) > 1);
> +		VM_WARN_ON(!swp_tb_is_hibernation(old_tb) &&
> +			   (!swp_tb_is_shadow(old_tb) || __swp_tb_get_count(old_tb) > 1));
>  
>  		/* Resetting the slot to NULL also clears the inline flags. */
>  		__swap_table_set(ci, ci_off, null_to_swp_tb());
> @@ -2201,7 +2203,6 @@ void swap_free_hibernation_slot(swp_entry_t entry)
>  	pgoff_t offset = swp_offset(entry);
>  
>  	ci = swap_cluster_lock(si, offset);
> -	__swap_cluster_put_entry(ci, offset % SWAPFILE_CLUSTER);
>  	/*
>  	 * A slot with a folio in the swap cache is freed when the folio
>  	 * leaves the cache, the same rule swap_put_entries_cluster() follows.

This idea is right, but is the patch in the right order? If readahead
tried to add a folio to a hibernate slot by accident, seems nothing
blocks that in the current patch, and that PFN slot will have a (MAX)
count value, and considered countable? If the that folio is somehow
reclaimed, we got a corrupted shadow (hib type is gone)?

If we have the count part of a hibernation slot be 0,
__swap_cache_add_check will fail natively, seems there will be no
such risk. A few existing helpers can also help catch potential
wrong freeing of hibernation slot. (underflow check).

The layout can be changed again afterwards.

How do you think?


  reply	other threads:[~2026-08-08 13:25 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-06 19:06 [PATCH 0/4] mm, swap: keep hibernation swap slots out of the swap cache Youngjun Park
2026-08-06 19:06 ` [PATCH 1/4] mm, swap: don't free a hibernation slot that is in " Youngjun Park
2026-08-08 12:09   ` Kairui Song
2026-08-08 13:26     ` Kairui Song
2026-08-06 19:06 ` [PATCH 2/4] mm, swap: give hibernation swap slots their own swap table entry type Youngjun Park
2026-08-08 13:25   ` Kairui Song [this message]
2026-08-06 19:06 ` [PATCH 3/4] mm, swap: only allow swapped-out slots into the swap cache Youngjun Park
2026-08-06 19:06 ` [PATCH 4/4] mm, swap: drop the swap cache guard and reclaim in swap_free_hibernation_slot() Youngjun Park

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=ancjiz6-qyC0ki4O@KASONG-MC4 \
    --to=ryncsn@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=baohua@kernel.org \
    --cc=baoquan.he@linux.dev \
    --cc=chrisl@kernel.org \
    --cc=her0gyugyu@gmail.com \
    --cc=kasong@tencent.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=nphamcs@gmail.com \
    --cc=shikemeng@huaweicloud.com \
    --cc=wujianyue000@gmail.com \
    --cc=youngjun.park@lge.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