Re: [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused
From: Kefeng Wang <hidden>
Date: 2026-09-10 11:10:16
Subsystem:
memory management, memory management - swap, the rest, zswap compressed swap caching · Maintainers:
Andrew Morton, Chris Li, Kairui Song, Linus Torvalds, Johannes Weiner, Yosry Ahmed, Nhat Pham
On 9/10/2026 6:29 PM, Yosry Ahmed wrote:
On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang [off-list ref] wrote:quoted
swap_range_free() calls zswap_invalidate() for every slot being freed, even when zswap has never been enabled. Guard the loop with zswap_never_enabled() to skip it. Signed-off-by: Kefeng Wang <redacted> --- mm/swapfile.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)diff --git a/mm/swapfile.c b/mm/swapfile.c index ba71905e4d46..505592051924 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c@@ -1318,8 +1318,10 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset, void (*swap_slot_free_notify)(struct block_device *, unsigned long); unsigned int i; - for (i = 0; i < nr_entries; i++) - zswap_invalidate(si->type, offset + i); + if (!zswap_never_enabled()) { + for (i = 0; i < nr_entries; i++) + zswap_invalidate(si->type, offset + i); + }What if we add the check in zswap_invalidate()? I understand we'd avoid the loop here, which is nice, but I wonder if it's actually a measurable difference.
Skipping useless instructions is always a good thing.
If we keep it in zswap_invalidate(), we can probably also skip patch 3?
Maybe add nr_entries to zswap_invalidate() and check zswap_never_enabled() in it.
diff --git a/include/linux/zswap.h b/include/linux/zswap.h
index 463bdee5c1e1..313c2f1b6c2e 100644
--- a/include/linux/zswap.h
+++ b/include/linux/zswap.h@@ -27,7 +27,7 @@ struct zswap_lruvec_state { unsigned long zswap_total_pages(void); bool zswap_store(struct folio *folio); int zswap_load(struct folio *folio); -void zswap_invalidate(int type, pgoff_t offset); +void zswap_invalidate(int type, pgoff_t offset, unsigned int nr_entries); int zswap_swapon(int type, unsigned long nr_pages); void zswap_swapoff(int type); void zswap_memcg_offline_cleanup(struct mem_cgroup *memcg);
@@ -49,7 +49,7 @@ static inline int zswap_load(struct folio *folio) return -ENOENT; } -static inline void zswap_invalidate(int type, pgoff_t offset) {} +static inline void zswap_invalidate(int type, pgoff_t offset, unsigned
int nr_entries) {}
static inline int zswap_swapon(int type, unsigned long nr_pages)
{
return 0;diff --git a/mm/swapfile.c b/mm/swapfile.c
index 505592051924..891379c95a01 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c@@ -1316,12 +1316,8 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset,
{
unsigned long end = offset + nr_entries - 1;
void (*swap_slot_free_notify)(struct block_device *, unsigned
long);
- unsigned int i;
- if (!zswap_never_enabled()) {
- for (i = 0; i < nr_entries; i++)
- zswap_invalidate(si->type, offset + i);
- }
+ zswap_invalidate(si->type, offset, nr_entries);
if (si->flags & SWP_BLKDEV)
swap_slot_free_notify =diff --git a/mm/zswap.c b/mm/zswap.c
index 6197aa71e33c..0e72cc9a5415 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c@@ -1549,13 +1549,8 @@ bool zswap_store(struct folio *folio) * offsets corresponding to each page of the folio. Otherwise, * writeback could overwrite the new data in the swapfile. */ - if (!ret) { - unsigned type = swp_type(swp); - pgoff_t offset = swp_offset(swp); - - for (index = 0; index < nr_pages; ++index) - zswap_invalidate(type, offset + index); - } + if (!ret) + zswap_invalidate(swp_type(swp), swp_offset(swp), nr_pages); return ret; }
@@ -1661,17 +1656,25 @@ int zswap_load(struct folio *folio) return 0; } -void zswap_invalidate(int type, pgoff_t offset) +void zswap_invalidate(int type, pgoff_t offset, int nr_entries) { - struct xarray *tree = zswap_tree(type, offset); struct zswap_entry *entry; + struct xarray *tree; + int i; - if (xa_empty(tree)) + if (!zswap_never_enabled()) return; - entry = xa_erase(tree, offset); - if (entry) - zswap_entry_free(entry); + for (i = 0; i < nr_entries; ++i) { + tree = zswap_tree(type, offset + i); + + if (xa_empty(tree)) + return; + + entry = xa_erase(tree, offset + i); + if (entry) + zswap_entry_free(entry); + } }
If no objections, I will refresh all the patches.