linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator
@ 2026-02-15 10:25 Kairui Song
  2026-02-15 10:25 ` [PATCH 2/2] mm, swap: merge common convention and simplify allocation helper Kairui Song
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Kairui Song @ 2026-02-15 10:25 UTC (permalink / raw)
  To: linux-mm
  Cc: Andrew Morton, Chris Li, Kemeng Shi, Nhat Pham, Baoquan He,
	Barry Song, Rafael J. Wysocki, Carsten Grohmann, linux-kernel,
	open list:SUSPEND TO RAM, Kairui Song

The new swap allocator didn't provide a high-performance allocation
method for hibernate, and just left it using the easy slow path. As a
result, hibernate performance is quite bad on some devices

Fix it by implementing hibernate support for the fast allocation path.

This regression seems only happen with SSD devices with poor 4k
performance. I've tested on several different NVME and SSD setups, the
performance diff is tiny on them, but testing on a Samsung SSD 830
Series (SATA II, 3.0 Gbps) showed a big difference [1]:

Test result with Samsung SSD 830 Series (SATA II, 3.0 Gbps) thanks
to Carsten Grohman [1]:
6.19:               324 seconds
After this series:  35 seconds

Test result with SAMSUNG MZ7LH480HAHQ-00005 (SATA 3.2, 6.0 Gb/s):
Before 0ff67f990bd4: Wrote 2230700 kbytes in 4.47 seconds (499.03 MB/s)
After 0ff67f990bd4: Wrote 2215472 kbytes in 4.44 seconds (498.98 MB/s)
After this series: Wrote 2038748 kbytes in 4.04 seconds (504.64 MB/s)

Test result with Memblaze P5910DT0384M00:
Before 0ff67f990bd4: Wrote 2222772 kbytes in 0.84 seconds (2646.15 MB/s)
After 0ff67f990bd4: Wrote 2224184 kbytes in 0.90 seconds (2471.31 MB/s)
After this series: Wrote 1559088 kbytes in 0.55 seconds (2834.70 MB/s)

The performance is almost the same for blazing fast SSDs, but for some
SSDs, the performance is several times better.

Patch 1 improves the hibernate performance by using the fast path, and
patch 2 cleans up the code a bit since there are now multiple fast path
users using similar conventions.

Signed-off-by: Kairui Song <kasong@tencent.com>
Tested-by: Carsten Grohmann <carstengrohmann@gmx.de>
Link: https://lore.kernel.org/linux-mm/8b4bdcfa-ce3f-4e23-839f-31367df7c18f@gmx.de/ [1]
---
Kairui Song (2):
      mm, swap: speed up hibernation allocation and writeout
      mm, swap: merge common convention and simplify allocation helper

 mm/swapfile.c | 56 ++++++++++++++++++++++++++------------------------------
 1 file changed, 26 insertions(+), 30 deletions(-)
---
base-commit: 53f061047924205138ad9bc315885255f7cc4944
change-id: 20260212-hibernate-perf-fb7783b2b252

Best regards,
-- 
Kairui Song <kasong@tencent.com>



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] mm, swap: merge common convention and simplify allocation helper
  2026-02-15 10:25 [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song
@ 2026-02-15 10:25 ` Kairui Song
  2026-02-15 10:38 ` [PATCH 1/2] mm, swap: simplify checking if a folio is swapped Kairui Song
  2026-02-15 11:18 ` [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song
  2 siblings, 0 replies; 5+ messages in thread
From: Kairui Song @ 2026-02-15 10:25 UTC (permalink / raw)
  To: linux-mm
  Cc: Andrew Morton, Chris Li, Kemeng Shi, Nhat Pham, Baoquan He,
	Barry Song, Rafael J. Wysocki, Carsten Grohmann, linux-kernel,
	open list:SUSPEND TO RAM, Kairui Song

From: Kairui Song <kasong@tencent.com>

almost all callers of the cluster scan helper require the: lock -> check
usefulness/emptiness -> unlock routine. So merge them into the same
helper to simplify the code.

This should also improve the scan slightly, as a few callers didn't
check the emptiness, which might help reduce fragmentation in rare
cases.

Signed-off-by: Kairui Song <kasong@tencent.com>
---
 mm/swapfile.c | 30 ++++++++----------------------
 1 file changed, 8 insertions(+), 22 deletions(-)

diff --git a/mm/swapfile.c b/mm/swapfile.c
index bcac10d96fb5..03cc0ff4dc8c 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -923,11 +923,14 @@ static unsigned int alloc_swap_scan_cluster(struct swap_info_struct *si,
 	bool need_reclaim, ret, usable;
 
 	lockdep_assert_held(&ci->lock);
-	VM_WARN_ON(!cluster_is_usable(ci, order));
 
-	if (end < nr_pages || ci->count + nr_pages > SWAPFILE_CLUSTER)
+	if (!cluster_is_usable(ci, order) || end < nr_pages ||
+	    ci->count + nr_pages > SWAPFILE_CLUSTER)
 		goto out;
 
+	if (cluster_is_empty(ci))
+		offset = cluster_offset(si, ci);
+
 	for (end -= nr_pages; offset <= end; offset += nr_pages) {
 		need_reclaim = false;
 		if (!cluster_scan_range(si, ci, offset, nr_pages, &need_reclaim))
@@ -1060,14 +1063,7 @@ static unsigned long cluster_alloc_swap_entry(struct swap_info_struct *si,
 			goto new_cluster;
 
 		ci = swap_cluster_lock(si, offset);
-		/* Cluster could have been used by another order */
-		if (cluster_is_usable(ci, order)) {
-			if (cluster_is_empty(ci))
-				offset = cluster_offset(si, ci);
-			found = alloc_swap_scan_cluster(si, ci, folio, offset);
-		} else {
-			swap_cluster_unlock(ci);
-		}
+		found = alloc_swap_scan_cluster(si, ci, folio, offset);
 		if (found)
 			goto done;
 	}
@@ -1332,14 +1328,7 @@ static bool swap_alloc_fast(struct folio *folio)
 		return false;
 
 	ci = swap_cluster_lock(si, offset);
-	if (cluster_is_usable(ci, order)) {
-		if (cluster_is_empty(ci))
-			offset = cluster_offset(si, ci);
-		alloc_swap_scan_cluster(si, ci, folio, offset);
-	} else {
-		swap_cluster_unlock(ci);
-	}
-
+	alloc_swap_scan_cluster(si, ci, folio, offset);
 	put_swap_device(si);
 	return folio_test_swapcache(folio);
 }
@@ -1945,10 +1934,7 @@ swp_entry_t swap_alloc_hibernation_slot(int type)
 		pcp_offset = this_cpu_read(percpu_swap_cluster.offset[0]);
 		if (pcp_si == si && pcp_offset) {
 			ci = swap_cluster_lock(si, pcp_offset);
-			if (cluster_is_usable(ci, 0))
-				offset = alloc_swap_scan_cluster(si, ci, NULL, pcp_offset);
-			else
-				swap_cluster_unlock(ci);
+			offset = alloc_swap_scan_cluster(si, ci, NULL, pcp_offset);
 		}
 		if (!offset)
 			offset = cluster_alloc_swap_entry(si, NULL);

-- 
2.52.0



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] mm, swap: simplify checking if a folio is swapped
  2026-02-15 10:25 [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song
  2026-02-15 10:25 ` [PATCH 2/2] mm, swap: merge common convention and simplify allocation helper Kairui Song
@ 2026-02-15 10:38 ` Kairui Song
  2026-02-15 10:41   ` Kairui Song
  2026-02-15 11:18 ` [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song
  2 siblings, 1 reply; 5+ messages in thread
From: Kairui Song @ 2026-02-15 10:38 UTC (permalink / raw)
  To: linux-mm
  Cc: Andrew Morton, Chris Li, Kemeng Shi, Nhat Pham, Baoquan He,
	Barry Song, Rafael J. Wysocki, Carsten Grohmann, linux-kernel,
	open list:SUSPEND TO RAM, Kairui Song

From: Kairui Song <kasong@tencent.com>

Clean up and simplify how we check if a folio is swapped. The helper
already requires the folio to be in swap cache and locked. That's enough
to pin the swap cluster from being freed, so there is no need to lock
anything else to avoid UAF.

And besides, we have cleaned up and defined the swap operation to be
mostly folio based, and now the only place a folio will have any of its
swap slots' count increased from 0 to 1 is folio_dup_swap, which also
requires the folio lock. So as we are holding the folio lock here, a
folio can't change its swap status from not swapped (all swap slots have
a count of 0) to swapped (any slot has a swap count larger than 0).

So there won't be any false negatives of this helper if we simply depend
on the folio lock to stabilize the cluster.

We are only using this helper to determine if we can and should release
the swap cache. So false positives are completely harmless, and also
already exist before. Depending on the timing, previously, it's also
possible that a racing thread releases the swap count right after
releasing the ci lock and before this helper returns. In any case, the
worst that could happen is we leave a clean swap cache. It will still be
reclaimed when under pressure just fine.

So, in conclusion, we can simplify and make the check much simpler and
lockless. Also, rename it to folio_maybe_swapped to reflect the design.

Signed-off-by: Kairui Song <kasong@tencent.com>
---
 mm/swap.h     |  5 ++--
 mm/swapfile.c | 82 ++++++++++++++++++++++++++++-----------------------
 2 files changed, 48 insertions(+), 39 deletions(-)

diff --git a/mm/swap.h b/mm/swap.h
index 9fc5fecdcfdf..3ee761ee8348 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -195,12 +195,13 @@ extern int swap_retry_table_alloc(swp_entry_t entry, gfp_t gfp);
  *
  * folio_alloc_swap(): the entry point for a folio to be swapped
  * out. It allocates swap slots and pins the slots with swap cache.
- * The slots start with a swap count of zero.
+ * The slots start with a swap count of zero. The slots are pinned
+ * by swap cache reference which doesn't contribute to swap count.
  *
  * folio_dup_swap(): increases the swap count of a folio, usually
  * during it gets unmapped and a swap entry is installed to replace
  * it (e.g., swap entry in page table). A swap slot with swap
- * count == 0 should only be increasd by this helper.
+ * count == 0 can only be increased by this helper.
  *
  * folio_put_swap(): does the opposite thing of folio_dup_swap().
  */
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 9628015fd8cf..cb18960a6089 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1743,7 +1743,11 @@ int folio_alloc_swap(struct folio *folio)
  * @subpage: if not NULL, only increase the swap count of this subpage.
  *
  * Typically called when the folio is unmapped and have its swap entry to
- * take its palce.
+ * take its place: Swap entries allocated to a folio has count == 0 and pinned
+ * by swap cache. The swap cache pin doesn't increase the swap count. This
+ * helper sets the initial count == 1 and increases the count as the folio is
+ * unmapped and swap entries referencing the slots are generated to replace
+ * the folio.
  *
  * Context: Caller must ensure the folio is locked and in the swap cache.
  * NOTE: The caller also has to ensure there is no raced call to
@@ -1944,49 +1948,44 @@ int swp_swapcount(swp_entry_t entry)
 	return count < 0 ? 0 : count;
 }
 
-static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
-					 swp_entry_t entry, int order)
+/*
+ * folio_maybe_swapped - Test if a folio covers any swap slot with count > 0.
+ *
+ * Check if a folio is swapped. Holding the folio lock ensures the folio won't
+ * go from not-swapped to swapped because the initial swap count increment can
+ * only be done by folio_dup_swap, which also locks the folio. But a concurrent
+ * decrease of swap count is possible through swap_put_entries_direct, so this
+ * may return a false positive.
+ *
+ * Context: Caller must ensure the folio is locked and in the swap cache.
+ */
+static bool folio_maybe_swapped(struct folio *folio)
 {
+	swp_entry_t entry = folio->swap;
 	struct swap_cluster_info *ci;
-	unsigned int nr_pages = 1 << order;
-	unsigned long roffset = swp_offset(entry);
-	unsigned long offset = round_down(roffset, nr_pages);
-	unsigned int ci_off;
-	int i;
+	unsigned int ci_off, ci_end;
 	bool ret = false;
 
-	ci = swap_cluster_lock(si, offset);
-	if (nr_pages == 1) {
-		ci_off = roffset % SWAPFILE_CLUSTER;
-		if (swp_tb_get_count(__swap_table_get(ci, ci_off)))
-			ret = true;
-		goto unlock_out;
-	}
-	for (i = 0; i < nr_pages; i++) {
-		ci_off = (offset + i) % SWAPFILE_CLUSTER;
-		if (swp_tb_get_count(__swap_table_get(ci, ci_off))) {
-			ret = true;
-			break;
-		}
-	}
-unlock_out:
-	swap_cluster_unlock(ci);
-	return ret;
-}
-
-static bool folio_swapped(struct folio *folio)
-{
-	swp_entry_t entry = folio->swap;
-	struct swap_info_struct *si;
-
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_swapcache(folio), folio);
 
-	si = __swap_entry_to_info(entry);
-	if (!IS_ENABLED(CONFIG_THP_SWAP) || likely(!folio_test_large(folio)))
-		return swap_entry_swapped(si, entry);
+	ci = __swap_entry_to_cluster(entry);
+	ci_off = swp_cluster_offset(entry);
+	ci_end = ci_off + folio_nr_pages(folio);
+	/*
+	 * Extra locking not needed, folio lock ensures its swap entries
+	 * won't be released, the backing data won't be gone either.
+	 */
+	rcu_read_lock();
+	do {
+		if (__swp_tb_get_count(__swap_table_get(ci, ci_off))) {
+			ret = true;
+			break;
+		}
+	} while (++ci_off < ci_end);
+	rcu_read_unlock();
 
-	return swap_page_trans_huge_swapped(si, entry, folio_order(folio));
+	return ret;
 }
 
 static bool folio_swapcache_freeable(struct folio *folio)
@@ -2032,7 +2031,7 @@ bool folio_free_swap(struct folio *folio)
 {
 	if (!folio_swapcache_freeable(folio))
 		return false;
-	if (folio_swapped(folio))
+	if (folio_maybe_swapped(folio))
 		return false;
 
 	swap_cache_del_folio(folio);
@@ -3710,6 +3709,8 @@ void si_swapinfo(struct sysinfo *val)
  *
  * Context: Caller must ensure there is no race condition on the reference
  * owner. e.g., locking the PTL of a PTE containing the entry being increased.
+ * Also the swap entry must have a count >= 1. Otherwise folio_dup_swap should
+ * be used.
  */
 int swap_dup_entry_direct(swp_entry_t entry)
 {
@@ -3721,6 +3722,13 @@ int swap_dup_entry_direct(swp_entry_t entry)
 		return -EINVAL;
 	}
 
+	/*
+	 * The caller must be increasing the swap count from a direct
+	 * reference of the swap slot (e.g. a swap entry in page table).
+	 * So the swap count must be >= 1.
+	 */
+	VM_WARN_ON_ONCE(!swap_entry_swapped(si, entry));
+
 	return swap_dup_entries_cluster(si, swp_offset(entry), 1);
 }
 
-- 
2.52.0



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] mm, swap: simplify checking if a folio is swapped
  2026-02-15 10:38 ` [PATCH 1/2] mm, swap: simplify checking if a folio is swapped Kairui Song
@ 2026-02-15 10:41   ` Kairui Song
  0 siblings, 0 replies; 5+ messages in thread
From: Kairui Song @ 2026-02-15 10:41 UTC (permalink / raw)
  To: linux-mm
  Cc: Andrew Morton, Chris Li, Kemeng Shi, Nhat Pham, Baoquan He,
	Barry Song, Rafael J. Wysocki, Carsten Grohmann, linux-kernel,
	open list:SUSPEND TO RAM

On Sun, Feb 15, 2026 at 6:38 PM Kairui Song <ryncsn@gmail.com> wrote:
>
> From: Kairui Song <kasong@tencent.com>
>
> Clean up and simplify how we check if a folio is swapped. The helper
> already requires the folio to be in swap cache and locked. That's enough
> to pin the swap cluster from being freed, so there is no need to lock
> anything else to avoid UAF.
>
> And besides, we have cleaned up and defined the swap operation to be
> mostly folio based, and now the only place a folio will have any of its
> swap slots' count increased from 0 to 1 is folio_dup_swap, which also
> requires the folio lock. So as we are holding the folio lock here, a
> folio can't change its swap status from not swapped (all swap slots have
> a count of 0) to swapped (any slot has a swap count larger than 0).
>
> So there won't be any false negatives of this helper if we simply depend
> on the folio lock to stabilize the cluster.
>
> We are only using this helper to determine if we can and should release
> the swap cache. So false positives are completely harmless, and also
> already exist before. Depending on the timing, previously, it's also
> possible that a racing thread releases the swap count right after
> releasing the ci lock and before this helper returns. In any case, the
> worst that could happen is we leave a clean swap cache. It will still be
> reclaimed when under pressure just fine.
>
> So, in conclusion, we can simplify and make the check much simpler and
> lockless. Also, rename it to folio_maybe_swapped to reflect the design.
>
> Signed-off-by: Kairui Song <kasong@tencent.com>
> ---
>  mm/swap.h     |  5 ++--
>  mm/swapfile.c | 82 ++++++++++++++++++++++++++++-----------------------
>  2 files changed, 48 insertions(+), 39 deletions(-)
>
> diff --git a/mm/swap.h b/mm/swap.h
> index 9fc5fecdcfdf..3ee761ee8348 100644
> --- a/mm/swap.h
> +++ b/mm/swap.h
> @@ -195,12 +195,13 @@ extern int swap_retry_table_alloc(swp_entry_t entry, gfp_t gfp);
>   *
>   * folio_alloc_swap(): the entry point for a folio to be swapped
>   * out. It allocates swap slots and pins the slots with swap cache.
> - * The slots start with a swap count of zero.
> + * The slots start with a swap count of zero. The slots are pinned
> + * by swap cache reference which doesn't contribute to swap count.
>   *
>   * folio_dup_swap(): increases the swap count of a folio, usually
>   * during it gets unmapped and a swap entry is installed to replace
>   * it (e.g., swap entry in page table). A swap slot with swap
> - * count == 0 should only be increasd by this helper.
> + * count == 0 can only be increased by this helper.
>   *
>   * folio_put_swap(): does the opposite thing of folio_dup_swap().
>   */
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 9628015fd8cf..cb18960a6089 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -1743,7 +1743,11 @@ int folio_alloc_swap(struct folio *folio)
>   * @subpage: if not NULL, only increase the swap count of this subpage.
>   *
>   * Typically called when the folio is unmapped and have its swap entry to
> - * take its palce.
> + * take its place: Swap entries allocated to a folio has count == 0 and pinned
> + * by swap cache. The swap cache pin doesn't increase the swap count. This
> + * helper sets the initial count == 1 and increases the count as the folio is
> + * unmapped and swap entries referencing the slots are generated to replace
> + * the folio.
>   *
>   * Context: Caller must ensure the folio is locked and in the swap cache.
>   * NOTE: The caller also has to ensure there is no raced call to
> @@ -1944,49 +1948,44 @@ int swp_swapcount(swp_entry_t entry)
>         return count < 0 ? 0 : count;
>  }
>
> -static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
> -                                        swp_entry_t entry, int order)
> +/*
> + * folio_maybe_swapped - Test if a folio covers any swap slot with count > 0.
> + *
> + * Check if a folio is swapped. Holding the folio lock ensures the folio won't
> + * go from not-swapped to swapped because the initial swap count increment can
> + * only be done by folio_dup_swap, which also locks the folio. But a concurrent
> + * decrease of swap count is possible through swap_put_entries_direct, so this
> + * may return a false positive.
> + *
> + * Context: Caller must ensure the folio is locked and in the swap cache.
> + */
> +static bool folio_maybe_swapped(struct folio *folio)
>  {
> +       swp_entry_t entry = folio->swap;
>         struct swap_cluster_info *ci;
> -       unsigned int nr_pages = 1 << order;
> -       unsigned long roffset = swp_offset(entry);
> -       unsigned long offset = round_down(roffset, nr_pages);
> -       unsigned int ci_off;
> -       int i;
> +       unsigned int ci_off, ci_end;
>         bool ret = false;
>
> -       ci = swap_cluster_lock(si, offset);
> -       if (nr_pages == 1) {
> -               ci_off = roffset % SWAPFILE_CLUSTER;
> -               if (swp_tb_get_count(__swap_table_get(ci, ci_off)))
> -                       ret = true;
> -               goto unlock_out;
> -       }
> -       for (i = 0; i < nr_pages; i++) {
> -               ci_off = (offset + i) % SWAPFILE_CLUSTER;
> -               if (swp_tb_get_count(__swap_table_get(ci, ci_off))) {
> -                       ret = true;
> -                       break;
> -               }
> -       }
> -unlock_out:
> -       swap_cluster_unlock(ci);
> -       return ret;
> -}
> -
> -static bool folio_swapped(struct folio *folio)
> -{
> -       swp_entry_t entry = folio->swap;
> -       struct swap_info_struct *si;
> -
>         VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
>         VM_WARN_ON_ONCE_FOLIO(!folio_test_swapcache(folio), folio);
>
> -       si = __swap_entry_to_info(entry);
> -       if (!IS_ENABLED(CONFIG_THP_SWAP) || likely(!folio_test_large(folio)))
> -               return swap_entry_swapped(si, entry);
> +       ci = __swap_entry_to_cluster(entry);
> +       ci_off = swp_cluster_offset(entry);
> +       ci_end = ci_off + folio_nr_pages(folio);
> +       /*
> +        * Extra locking not needed, folio lock ensures its swap entries
> +        * won't be released, the backing data won't be gone either.
> +        */
> +       rcu_read_lock();
> +       do {
> +               if (__swp_tb_get_count(__swap_table_get(ci, ci_off))) {
> +                       ret = true;
> +                       break;
> +               }
> +       } while (++ci_off < ci_end);
> +       rcu_read_unlock();
>
> -       return swap_page_trans_huge_swapped(si, entry, folio_order(folio));
> +       return ret;
>  }
>
>  static bool folio_swapcache_freeable(struct folio *folio)
> @@ -2032,7 +2031,7 @@ bool folio_free_swap(struct folio *folio)
>  {
>         if (!folio_swapcache_freeable(folio))
>                 return false;
> -       if (folio_swapped(folio))
> +       if (folio_maybe_swapped(folio))
>                 return false;
>
>         swap_cache_del_folio(folio);
> @@ -3710,6 +3709,8 @@ void si_swapinfo(struct sysinfo *val)
>   *
>   * Context: Caller must ensure there is no race condition on the reference
>   * owner. e.g., locking the PTL of a PTE containing the entry being increased.
> + * Also the swap entry must have a count >= 1. Otherwise folio_dup_swap should
> + * be used.
>   */
>  int swap_dup_entry_direct(swp_entry_t entry)
>  {
> @@ -3721,6 +3722,13 @@ int swap_dup_entry_direct(swp_entry_t entry)
>                 return -EINVAL;
>         }
>
> +       /*
> +        * The caller must be increasing the swap count from a direct
> +        * reference of the swap slot (e.g. a swap entry in page table).
> +        * So the swap count must be >= 1.
> +        */
> +       VM_WARN_ON_ONCE(!swap_entry_swapped(si, entry));
> +
>         return swap_dup_entries_cluster(si, swp_offset(entry), 1);
>  }
>
> --
> 2.52.0
>

Very sorry about this :/, something is wrong with my local branch
so this is the wrong patch.

Please ignore this series, thanks!


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator
  2026-02-15 10:25 [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song
  2026-02-15 10:25 ` [PATCH 2/2] mm, swap: merge common convention and simplify allocation helper Kairui Song
  2026-02-15 10:38 ` [PATCH 1/2] mm, swap: simplify checking if a folio is swapped Kairui Song
@ 2026-02-15 11:18 ` Kairui Song
  2 siblings, 0 replies; 5+ messages in thread
From: Kairui Song @ 2026-02-15 11:18 UTC (permalink / raw)
  To: linux-mm
  Cc: Andrew Morton, Chris Li, Kemeng Shi, Nhat Pham, Baoquan He,
	Barry Song, Rafael J. Wysocki, Carsten Grohmann, linux-kernel,
	open list:SUSPEND TO RAM

On Sun, Feb 15, 2026 at 6:25 PM Kairui Song <ryncsn@gmail.com> wrote:
>
> The new swap allocator didn't provide a high-performance allocation
> method for hibernate, and just left it using the easy slow path. As a
> result, hibernate performance is quite bad on some devices
>
> Fix it by implementing hibernate support for the fast allocation path.
>
> This regression seems only happen with SSD devices with poor 4k
> performance. I've tested on several different NVME and SSD setups, the
> performance diff is tiny on them, but testing on a Samsung SSD 830
> Series (SATA II, 3.0 Gbps) showed a big difference [1]:
>
> Test result with Samsung SSD 830 Series (SATA II, 3.0 Gbps) thanks
> to Carsten Grohman [1]:
> 6.19:               324 seconds
> After this series:  35 seconds
>
> Test result with SAMSUNG MZ7LH480HAHQ-00005 (SATA 3.2, 6.0 Gb/s):
> Before 0ff67f990bd4: Wrote 2230700 kbytes in 4.47 seconds (499.03 MB/s)
> After 0ff67f990bd4: Wrote 2215472 kbytes in 4.44 seconds (498.98 MB/s)
> After this series: Wrote 2038748 kbytes in 4.04 seconds (504.64 MB/s)
>
> Test result with Memblaze P5910DT0384M00:
> Before 0ff67f990bd4: Wrote 2222772 kbytes in 0.84 seconds (2646.15 MB/s)
> After 0ff67f990bd4: Wrote 2224184 kbytes in 0.90 seconds (2471.31 MB/s)
> After this series: Wrote 1559088 kbytes in 0.55 seconds (2834.70 MB/s)
>
> The performance is almost the same for blazing fast SSDs, but for some
> SSDs, the performance is several times better.
>
> Patch 1 improves the hibernate performance by using the fast path, and
> patch 2 cleans up the code a bit since there are now multiple fast path
> users using similar conventions.
>
> Signed-off-by: Kairui Song <kasong@tencent.com>
> Tested-by: Carsten Grohmann <carstengrohmann@gmx.de>
> Link: https://lore.kernel.org/linux-mm/8b4bdcfa-ce3f-4e23-839f-31367df7c18f@gmx.de/ [1]
> ---
> Kairui Song (2):
>       mm, swap: speed up hibernation allocation and writeout
>       mm, swap: merge common convention and simplify allocation helper
>
>  mm/swapfile.c | 56 ++++++++++++++++++++++++++------------------------------
>  1 file changed, 26 insertions(+), 30 deletions(-)
> ---
> base-commit: 53f061047924205138ad9bc315885255f7cc4944
> change-id: 20260212-hibernate-perf-fb7783b2b252
>
> Best regards,
> --
> Kairui Song <kasong@tencent.com>
>

Patch 1/2 is a wrong patch, sorry about this.

Just resent the series using B4 relay and marking it as V2 to
distinguish from this misformed one, please check that series instead,
thanks!
https://lore.kernel.org/linux-mm/20260215-hibernate-perf-v2-0-cf28c75b04b7@tencent.com/


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-02-15 11:19 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-15 10:25 [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song
2026-02-15 10:25 ` [PATCH 2/2] mm, swap: merge common convention and simplify allocation helper Kairui Song
2026-02-15 10:38 ` [PATCH 1/2] mm, swap: simplify checking if a folio is swapped Kairui Song
2026-02-15 10:41   ` Kairui Song
2026-02-15 11:18 ` [PATCH 0/2] mm/swap: hibernate: improve hibernate performance with new allocator Kairui Song

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox