From: Baoquan He <baoquan.he@linux.dev>
To: linux-mm@kvack.org
Cc: akpm@linux-foundation.org, hannes@cmpxchg.org, yosry@kernel.org,
nphamcs@gmail.com, chengming.zhou@linux.dev, chrisl@kernel.org,
kasong@tencent.com, shikemeng@huaweicloud.com, baohua@kernel.org,
youngjun.park@lge.com, linux-kernel@vger.kernel.org,
Baoquan He <baoquan.he@linux.dev>
Subject: [RFC PATCH 5/7] mm/swapfile: handle Pointer entries in count/dup/put paths
Date: Tue, 7 Jul 2026 15:32:02 +0800 [thread overview]
Message-ID: <20260707073215.72183-6-baoquan.he@linux.dev> (raw)
In-Reply-To: <20260707073215.72183-1-baoquan.he@linux.dev>
Update swap count, duplicate, and put operations to handle Pointer-type
swap table entries where the count is stored in zswap_entry->swp_tb_val
rather than inline in the entry bits.
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
---
mm/swapfile.c | 95 ++++++++++++++++++++++++++++++++++++++++-----------
mm/zswap.c | 5 +++
2 files changed, 81 insertions(+), 19 deletions(-)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index a602e5820513..15572383cafa 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1536,25 +1536,51 @@ static void __swap_cluster_put_entry(struct swap_cluster_info *ci,
lockdep_assert_held(&ci->lock);
swp_tb = __swap_table_get(ci, ci_off);
+
+ /* Pointer entries store count in the zswap_entry struct */
+ if (swp_tb_is_pointer(swp_tb)) {
+ zswap_swp_tb_put_count(swp_tb, ci, ci_off);
+ return;
+ }
+
count = __swp_tb_get_count(swp_tb);
VM_WARN_ON_ONCE(count <= 0);
VM_WARN_ON_ONCE(count > SWP_TB_COUNT_MAX);
-
- if (count == SWP_TB_COUNT_MAX) {
- count = ci->extend_table[ci_off];
- /* Overflow starts with SWP_TB_COUNT_MAX */
- VM_WARN_ON_ONCE(count < SWP_TB_COUNT_MAX);
- count--;
- if (count == (SWP_TB_COUNT_MAX - 1)) {
- ci->extend_table[ci_off] = 0;
- __swap_table_set(ci, ci_off, __swp_tb_mk_count(swp_tb, count));
+ if (count == SWP_TB_COUNT_MAX) {
+ if (!ci->extend_table) {
+ /*
+ * MAX without extend_table: MAX is the real
+ * count. Decrement and write back inline.
+ */
+ count--;
+ __swap_table_set(ci, ci_off,
+ __swp_tb_mk_count(swp_tb, count));
+ } else {
+ /*
+ * MAX with extend_table: real count lives in
+ * ci->extend_table[ci_off]. Pull, decrement
+ * it, and either move it back inline (if now
+ * fits) or write it back to the extend table.
+ */
+ count = ci->extend_table[ci_off];
+ /* Overflow starts with SWP_TB_COUNT_MAX */
+ VM_WARN_ON_ONCE(count < SWP_TB_COUNT_MAX);
+ count--;
+ if (count == (SWP_TB_COUNT_MAX - 1)) {
+ ci->extend_table[ci_off] = 0;
+ __swap_table_set(ci, ci_off,
+ __swp_tb_mk_count(swp_tb, count));
+ } else {
+ ci->extend_table[ci_off] = count;
+ }
+ }
} else {
- ci->extend_table[ci_off] = count;
+ /* count < MAX: simple inline decrement */
+ count--;
+ __swap_table_set(ci, ci_off,
+ __swp_tb_mk_count(swp_tb, count));
}
- } else {
- __swap_table_set(ci, ci_off, __swp_tb_mk_count(swp_tb, --count));
- }
/*
* `SWP_TB_COUNT_MAX - 1` triggers extend table allocation. If the
@@ -1596,7 +1622,18 @@ static void swap_put_entries_cluster(struct swap_info_struct *si,
ci_end = ci_off + nr;
do {
swp_tb = __swap_table_get(ci, ci_off);
- if (swp_tb_get_count(swp_tb) == 1) {
+ /*
+ * Pointer entries store count in the zswap_entry;
+ * handle them before swp_tb_get_count (which returns
+ * -EINVAL for non-countable types).
+ */
+ if (swp_tb_is_pointer(swp_tb)) {
+ if (zswap_swp_tb_get_count(swp_tb) == 1) {
+ if (ci_batch == -1)
+ ci_batch = ci_off;
+ continue;
+ }
+ } else if (swp_tb_get_count(swp_tb) == 1) {
/* count == 1 and non-cached slots will be batch freed. */
if (!swp_tb_is_folio(swp_tb)) {
if (ci_batch == -1)
@@ -1647,6 +1684,11 @@ static int __swap_cluster_dup_entry(struct swap_cluster_info *ci,
/* Bad or special slots can't be handled */
if (WARN_ON_ONCE(swp_tb_is_bad(swp_tb)))
return -EINVAL;
+
+ /* Pointer entries store count in the zswap_entry struct */
+ if (swp_tb_is_pointer(swp_tb))
+ return zswap_swp_tb_dup_count(swp_tb, ci, ci_off);
+
count = __swp_tb_get_count(swp_tb);
/* Must be either cached or have a count already */
if (WARN_ON_ONCE(!count && !swp_tb_is_folio(swp_tb)))
@@ -1923,13 +1965,19 @@ 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 Pointer entry
+ * means zswap has a compressed copy; the xarray still
+ * holds the entry and zswap_invalidate will free it.
*/
- VM_WARN_ON(!swp_tb_is_shadow(old_tb) || __swp_tb_get_count(old_tb) > 1);
+ if (swp_tb_is_pointer(old_tb))
+ VM_WARN_ON(zswap_swp_tb_get_count(old_tb) > 1);
+ else
+ VM_WARN_ON(!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());
- if (!SWAP_TABLE_HAS_ZEROFLAG)
+ if (!SWAP_TABLE_HAS_ZEROFLAG && !swp_tb_is_pointer(old_tb))
__swap_table_clear_zero(ci, ci_off);
/*
@@ -1961,8 +2009,11 @@ int __swap_count(swp_entry_t entry)
{
struct swap_cluster_info *ci = __swap_entry_to_cluster(entry);
unsigned int ci_off = swp_cluster_offset(entry);
+ unsigned long swp_tb = __swap_table_get(ci, ci_off);
- return swp_tb_get_count(__swap_table_get(ci, ci_off));
+ if (swp_tb_is_pointer(swp_tb))
+ return zswap_swp_tb_get_count(swp_tb);
+ return swp_tb_get_count(swp_tb);
}
/**
@@ -1980,6 +2031,8 @@ bool swap_entry_swapped(struct swap_info_struct *si, swp_entry_t entry)
swp_tb = swap_table_get(ci, offset % SWAPFILE_CLUSTER);
swap_cluster_unlock(ci);
+ if (swp_tb_is_pointer(swp_tb))
+ return zswap_swp_tb_get_count(swp_tb) > 0;
return swp_tb_get_count(swp_tb) > 0;
}
@@ -2556,8 +2609,12 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
if (!folio) {
swp_tb = swap_table_get(__swap_entry_to_cluster(entry),
swp_cluster_offset(entry));
- if (swp_tb_get_count(swp_tb) <= 0)
+ if (swp_tb_is_pointer(swp_tb)) {
+ if (zswap_swp_tb_get_count(swp_tb) <= 0)
+ continue;
+ } else if (swp_tb_get_count(swp_tb) <= 0) {
continue;
+ }
return -ENOMEM;
}
diff --git a/mm/zswap.c b/mm/zswap.c
index 1bb484d1ac87..58259673ce2b 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -1774,6 +1774,11 @@ void zswap_swp_tb_put_count(unsigned long swp_tb,
VM_WARN_ON_ONCE(count == 0);
if (count == SWP_TB_COUNT_MAX) {
+ if (!ci->extend_table) {
+ count--;
+ entry->swp_tb_val = __swp_tb_mk_count(entry->swp_tb_val, count);
+ return;
+ }
count = ci->extend_table[ci_off];
/* Overflow starts with SWP_TB_COUNT_MAX */
VM_WARN_ON_ONCE(count < SWP_TB_COUNT_MAX);
--
2.54.0
next prev parent reply other threads:[~2026-07-07 7:33 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 7:31 [RFC PATCH 0/7] mm: store zswap entries in swap table (Pointer entry) Baoquan He
2026-07-07 7:31 ` [RFC PATCH 1/7] mm/swap_table: add Pointer type support for zswap entry storage Baoquan He
2026-07-07 7:31 ` [RFC PATCH 2/7] mm/zswap: add swp_tb_val to zswap_entry and Pointer accessor helpers Baoquan He
2026-07-07 7:32 ` [RFC PATCH 3/7] mm/swap_state: do zswap conversion in __swap_cache_do_del_folio Baoquan He
2026-07-07 7:32 ` [RFC PATCH 4/7] mm/zswap, mm/swap_state: handle Pointer entries in add_folio path Baoquan He
2026-07-07 7:32 ` Baoquan He [this message]
2026-07-07 7:32 ` [RFC PATCH 6/7] mm/zswap, mm/swap_state: migrate zswap to use swap_table for entry indexing Baoquan He
2026-07-07 7:32 ` [RFC PATCH 7/7] mm/zswap, mm/swap_state: replace xarray indexing with swap table lookups Baoquan He
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=20260707073215.72183-6-baoquan.he@linux.dev \
--to=baoquan.he@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=baohua@kernel.org \
--cc=chengming.zhou@linux.dev \
--cc=chrisl@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=kasong@tencent.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=nphamcs@gmail.com \
--cc=shikemeng@huaweicloud.com \
--cc=yosry@kernel.org \
--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