Re: [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused
From: Yosry Ahmed <yosry@kernel.org>
Date: 2026-09-10 11:12:24
On Thu, Sep 10, 2026 at 4:10 AM Kefeng Wang [off-list ref] wrote:
quoted hunk ↗ jump to hunk
On 9/10/2026 6:29 PM, Yosry Ahmed wrote:quoted
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.quoted
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, unsignedint 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(structswap_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.
Yeah I think that's a good idea, even for the zswap_store() path.