* [PATCH v2 0/4] mm: zswap: misc optimizations
@ 2026-09-10 9:54 Kefeng Wang
2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Kefeng Wang @ 2026-09-10 9:54 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham,
Yosry Ahmed, Kefeng Wang
This series cleans up duplication in zswap_invalidate() and adds
fast paths in zswap_store() which now skips redundant xarray lookups,
while swap_range_free() skips needless zswap_invalidate() calls.
v2:
- split patches and refactor zswap_invalidate(), suggested by
Johannes Weiner
- add patch4 to skip zswap_invalidate() in swap_range_free()
Kefeng Wang (4):
mm: zswap: pass type and offset to zswap_invalidate() directly
mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path
mm: zswap: avoid unnecessary xarray lookup in zswap_store()
mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is
unused
include/linux/zswap.h | 4 ++--
mm/swapfile.c | 6 ++++--
mm/zswap.c | 29 +++++++++++++++--------------
3 files changed, 21 insertions(+), 18 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly 2026-09-10 9:54 [PATCH v2 0/4] mm: zswap: misc optimizations Kefeng Wang @ 2026-09-10 9:54 ` Kefeng Wang 2026-09-10 10:26 ` Yosry Ahmed ` (2 more replies) 2026-09-10 9:54 ` [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path Kefeng Wang ` (2 subsequent siblings) 3 siblings, 3 replies; 14+ messages in thread From: Kefeng Wang @ 2026-09-10 9:54 UTC (permalink / raw) To: Andrew Morton Cc: linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed, Kefeng Wang zswap_invalidate() takes a swp_entry_t only to unpack it right back into type and offset. Both callers already have those values, so pass them directly and drop the swp_entry()/swp_type()/swp_offset() round-trip. Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> --- include/linux/zswap.h | 4 ++-- mm/swapfile.c | 2 +- mm/zswap.c | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/linux/zswap.h b/include/linux/zswap.h index 30c193a1207e..463bdee5c1e1 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(swp_entry_t swp); +void zswap_invalidate(int type, pgoff_t offset); 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(swp_entry_t swp) {} +static inline void zswap_invalidate(int type, pgoff_t offset) {} static inline int zswap_swapon(int type, unsigned long nr_pages) { return 0; diff --git a/mm/swapfile.c b/mm/swapfile.c index 05d3408396f9..ba71905e4d46 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1319,7 +1319,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset, unsigned int i; for (i = 0; i < nr_entries; i++) - zswap_invalidate(swp_entry(si->type, offset + i)); + zswap_invalidate(si->type, offset + i); if (si->flags & SWP_BLKDEV) swap_slot_free_notify = diff --git a/mm/zswap.c b/mm/zswap.c index a12b6452a225..420c405d0402 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -228,10 +228,15 @@ static bool zswap_has_pool; /* One swap address space for each 64M swap space */ #define ZSWAP_ADDRESS_SPACE_SHIFT 14 #define ZSWAP_ADDRESS_SPACE_PAGES (1 << ZSWAP_ADDRESS_SPACE_SHIFT) + +static inline struct xarray *zswap_tree(int type, pgoff_t offset) +{ + return &zswap_trees[type][offset >> ZSWAP_ADDRESS_SPACE_SHIFT]; +} + static inline struct xarray *swap_zswap_tree(swp_entry_t swp) { - return &zswap_trees[swp_type(swp)][swp_offset(swp) - >> ZSWAP_ADDRESS_SPACE_SHIFT]; + return zswap_tree(swp_type(swp), swp_offset(swp)); } #define zswap_pool_debug(msg, p) \ @@ -1659,10 +1664,9 @@ int zswap_load(struct folio *folio) return 0; } -void zswap_invalidate(swp_entry_t swp) +void zswap_invalidate(int type, pgoff_t offset) { - pgoff_t offset = swp_offset(swp); - struct xarray *tree = swap_zswap_tree(swp); + struct xarray *tree = zswap_tree(type, offset); struct zswap_entry *entry; if (xa_empty(tree)) -- 2.55.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly 2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang @ 2026-09-10 10:26 ` Yosry Ahmed 2026-09-10 17:57 ` Nhat Pham 2026-09-10 19:27 ` Johannes Weiner 2 siblings, 0 replies; 14+ messages in thread From: Yosry Ahmed @ 2026-09-10 10:26 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > > zswap_invalidate() takes a swp_entry_t only to unpack it right back > into type and offset. Both callers already have those values, so > pass them directly and drop the swp_entry()/swp_type()/swp_offset() > round-trip. > Suggested-by: Johannes Weiner <hannes@cmpxchg.org> ? > Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Acked-by: Yosry Ahmed <yosry@kernel.org> > --- > include/linux/zswap.h | 4 ++-- > mm/swapfile.c | 2 +- > mm/zswap.c | 14 +++++++++----- > 3 files changed, 12 insertions(+), 8 deletions(-) > > diff --git a/include/linux/zswap.h b/include/linux/zswap.h > index 30c193a1207e..463bdee5c1e1 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(swp_entry_t swp); > +void zswap_invalidate(int type, pgoff_t offset); > 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(swp_entry_t swp) {} > +static inline void zswap_invalidate(int type, pgoff_t offset) {} > static inline int zswap_swapon(int type, unsigned long nr_pages) > { > return 0; > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 05d3408396f9..ba71905e4d46 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -1319,7 +1319,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset, > unsigned int i; > > for (i = 0; i < nr_entries; i++) > - zswap_invalidate(swp_entry(si->type, offset + i)); > + zswap_invalidate(si->type, offset + i); > > if (si->flags & SWP_BLKDEV) > swap_slot_free_notify = > diff --git a/mm/zswap.c b/mm/zswap.c > index a12b6452a225..420c405d0402 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -228,10 +228,15 @@ static bool zswap_has_pool; > /* One swap address space for each 64M swap space */ > #define ZSWAP_ADDRESS_SPACE_SHIFT 14 > #define ZSWAP_ADDRESS_SPACE_PAGES (1 << ZSWAP_ADDRESS_SPACE_SHIFT) > + > +static inline struct xarray *zswap_tree(int type, pgoff_t offset) > +{ > + return &zswap_trees[type][offset >> ZSWAP_ADDRESS_SPACE_SHIFT]; > +} > + > static inline struct xarray *swap_zswap_tree(swp_entry_t swp) > { > - return &zswap_trees[swp_type(swp)][swp_offset(swp) > - >> ZSWAP_ADDRESS_SPACE_SHIFT]; > + return zswap_tree(swp_type(swp), swp_offset(swp)); > } > > #define zswap_pool_debug(msg, p) \ > @@ -1659,10 +1664,9 @@ int zswap_load(struct folio *folio) > return 0; > } > > -void zswap_invalidate(swp_entry_t swp) > +void zswap_invalidate(int type, pgoff_t offset) > { > - pgoff_t offset = swp_offset(swp); > - struct xarray *tree = swap_zswap_tree(swp); > + struct xarray *tree = zswap_tree(type, offset); > struct zswap_entry *entry; > > if (xa_empty(tree)) > -- > 2.55.0 > > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly 2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang 2026-09-10 10:26 ` Yosry Ahmed @ 2026-09-10 17:57 ` Nhat Pham 2026-09-10 19:27 ` Johannes Weiner 2 siblings, 0 replies; 14+ messages in thread From: Nhat Pham @ 2026-09-10 17:57 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Yosry Ahmed On Thu, Sep 10, 2026 at 2:54 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > > zswap_invalidate() takes a swp_entry_t only to unpack it right back > into type and offset. Both callers already have those values, so > pass them directly and drop the swp_entry()/swp_type()/swp_offset() > round-trip. > > Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Acked-by: Nhat Pham <nphamcs@gmail.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly 2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang 2026-09-10 10:26 ` Yosry Ahmed 2026-09-10 17:57 ` Nhat Pham @ 2026-09-10 19:27 ` Johannes Weiner 2 siblings, 0 replies; 14+ messages in thread From: Johannes Weiner @ 2026-09-10 19:27 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 05:54:46PM +0800, Kefeng Wang wrote: > zswap_invalidate() takes a swp_entry_t only to unpack it right back > into type and offset. Both callers already have those values, so > pass them directly and drop the swp_entry()/swp_type()/swp_offset() > round-trip. > > Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Noice. Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path 2026-09-10 9:54 [PATCH v2 0/4] mm: zswap: misc optimizations Kefeng Wang 2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang @ 2026-09-10 9:54 ` Kefeng Wang 2026-09-10 10:27 ` Yosry Ahmed 2026-09-10 19:27 ` Johannes Weiner 2026-09-10 9:54 ` [PATCH v2 3/4] mm: zswap: avoid unnecessary xarray lookup in zswap_store() Kefeng Wang 2026-09-10 9:54 ` [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused Kefeng Wang 3 siblings, 2 replies; 14+ messages in thread From: Kefeng Wang @ 2026-09-10 9:54 UTC (permalink / raw) To: Andrew Morton Cc: linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed, Kefeng Wang The check_old path in zswap_store() open-codes the same per-slot xarray lookup and entry free that zswap_invalidate() already does. Reuse zswap_invalidate() whose xa_empty() check skips empty per-area trees to avoid unnecessary xarray lookup and code duplication. Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> --- mm/zswap.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index 420c405d0402..2c06e4e0e130 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -1549,15 +1549,9 @@ bool zswap_store(struct folio *folio) if (!ret) { unsigned type = swp_type(swp); pgoff_t offset = swp_offset(swp); - struct zswap_entry *entry; - struct xarray *tree; - - for (index = 0; index < nr_pages; ++index) { - tree = swap_zswap_tree(swp_entry(type, offset + index)); - entry = xa_erase(tree, offset + index); - if (entry) - zswap_entry_free(entry); - } + + for (index = 0; index < nr_pages; ++index) + zswap_invalidate(type, offset + index); } return ret; -- 2.55.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path 2026-09-10 9:54 ` [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path Kefeng Wang @ 2026-09-10 10:27 ` Yosry Ahmed 2026-09-10 19:27 ` Johannes Weiner 1 sibling, 0 replies; 14+ messages in thread From: Yosry Ahmed @ 2026-09-10 10:27 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > > The check_old path in zswap_store() open-codes the same per-slot > xarray lookup and entry free that zswap_invalidate() already does. > Reuse zswap_invalidate() whose xa_empty() check skips empty per-area > trees to avoid unnecessary xarray lookup and code duplication. > > Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Nice. Acked-by: Yosry Ahmed <yosry@kernel.org> > --- > mm/zswap.c | 12 +++--------- > 1 file changed, 3 insertions(+), 9 deletions(-) > > diff --git a/mm/zswap.c b/mm/zswap.c > index 420c405d0402..2c06e4e0e130 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -1549,15 +1549,9 @@ bool zswap_store(struct folio *folio) > if (!ret) { > unsigned type = swp_type(swp); > pgoff_t offset = swp_offset(swp); > - struct zswap_entry *entry; > - struct xarray *tree; > - > - for (index = 0; index < nr_pages; ++index) { > - tree = swap_zswap_tree(swp_entry(type, offset + index)); > - entry = xa_erase(tree, offset + index); > - if (entry) > - zswap_entry_free(entry); > - } > + > + for (index = 0; index < nr_pages; ++index) > + zswap_invalidate(type, offset + index); > } > > return ret; > -- > 2.55.0 > > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path 2026-09-10 9:54 ` [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path Kefeng Wang 2026-09-10 10:27 ` Yosry Ahmed @ 2026-09-10 19:27 ` Johannes Weiner 1 sibling, 0 replies; 14+ messages in thread From: Johannes Weiner @ 2026-09-10 19:27 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 05:54:47PM +0800, Kefeng Wang wrote: > The check_old path in zswap_store() open-codes the same per-slot > xarray lookup and entry free that zswap_invalidate() already does. > Reuse zswap_invalidate() whose xa_empty() check skips empty per-area > trees to avoid unnecessary xarray lookup and code duplication. > > Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 3/4] mm: zswap: avoid unnecessary xarray lookup in zswap_store() 2026-09-10 9:54 [PATCH v2 0/4] mm: zswap: misc optimizations Kefeng Wang 2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang 2026-09-10 9:54 ` [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path Kefeng Wang @ 2026-09-10 9:54 ` Kefeng Wang 2026-09-10 10:28 ` Yosry Ahmed 2026-09-10 9:54 ` [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused Kefeng Wang 3 siblings, 1 reply; 14+ messages in thread From: Kefeng Wang @ 2026-09-10 9:54 UTC (permalink / raw) To: Andrew Morton Cc: linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed, Kefeng Wang zswap_store() falls through to check_old and walks the swap xarray even when zswap is disabled. Add a zswap_never_enabled() early return matching zswap_load() to avoid unnecessary xarray lookup. Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> --- mm/zswap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/zswap.c b/mm/zswap.c index 2c06e4e0e130..6197aa71e33c 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -1492,6 +1492,9 @@ bool zswap_store(struct folio *folio) VM_WARN_ON_ONCE(!folio_test_locked(folio)); VM_WARN_ON_ONCE(!folio_test_swapcache(folio)); + if (zswap_never_enabled()) + return false; + if (!zswap_enabled) goto check_old; -- 2.55.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/4] mm: zswap: avoid unnecessary xarray lookup in zswap_store() 2026-09-10 9:54 ` [PATCH v2 3/4] mm: zswap: avoid unnecessary xarray lookup in zswap_store() Kefeng Wang @ 2026-09-10 10:28 ` Yosry Ahmed 0 siblings, 0 replies; 14+ messages in thread From: Yosry Ahmed @ 2026-09-10 10:28 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > > zswap_store() falls through to check_old and walks the swap xarray > even when zswap is disabled. Add a zswap_never_enabled() early return > matching zswap_load() to avoid unnecessary xarray lookup. > > Reviewed-by: Johannes Weiner <hannes@cmpxchg.org> > Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Acked-by: Yosry Ahmed <yosry@kernel.org> > --- > mm/zswap.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/mm/zswap.c b/mm/zswap.c > index 2c06e4e0e130..6197aa71e33c 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -1492,6 +1492,9 @@ bool zswap_store(struct folio *folio) > VM_WARN_ON_ONCE(!folio_test_locked(folio)); > VM_WARN_ON_ONCE(!folio_test_swapcache(folio)); > > + if (zswap_never_enabled()) > + return false; > + > if (!zswap_enabled) > goto check_old; > > -- > 2.55.0 > > ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused 2026-09-10 9:54 [PATCH v2 0/4] mm: zswap: misc optimizations Kefeng Wang ` (2 preceding siblings ...) 2026-09-10 9:54 ` [PATCH v2 3/4] mm: zswap: avoid unnecessary xarray lookup in zswap_store() Kefeng Wang @ 2026-09-10 9:54 ` Kefeng Wang 2026-09-10 10:29 ` Yosry Ahmed 3 siblings, 1 reply; 14+ messages in thread From: Kefeng Wang @ 2026-09-10 9:54 UTC (permalink / raw) To: Andrew Morton Cc: linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed, Kefeng Wang 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 <wangkefeng.wang@huawei.com> --- 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); + } if (si->flags & SWP_BLKDEV) swap_slot_free_notify = -- 2.55.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused 2026-09-10 9:54 ` [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused Kefeng Wang @ 2026-09-10 10:29 ` Yosry Ahmed 2026-09-10 11:10 ` Kefeng Wang 0 siblings, 1 reply; 14+ messages in thread From: Yosry Ahmed @ 2026-09-10 10:29 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > > 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 <wangkefeng.wang@huawei.com> > --- > 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. If we keep it in zswap_invalidate(), we can probably also skip patch 3? > > if (si->flags & SWP_BLKDEV) > swap_slot_free_notify = > -- > 2.55.0 > > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused 2026-09-10 10:29 ` Yosry Ahmed @ 2026-09-10 11:10 ` Kefeng Wang 2026-09-10 11:12 ` Yosry Ahmed 0 siblings, 1 reply; 14+ messages in thread From: Kefeng Wang @ 2026-09-10 11:10 UTC (permalink / raw) To: Yosry Ahmed Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed On 9/10/2026 6:29 PM, Yosry Ahmed wrote: > On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: >> >> 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 <wangkefeng.wang@huawei.com> >> --- >> 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. ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused 2026-09-10 11:10 ` Kefeng Wang @ 2026-09-10 11:12 ` Yosry Ahmed 0 siblings, 0 replies; 14+ messages in thread From: Yosry Ahmed @ 2026-09-10 11:12 UTC (permalink / raw) To: Kefeng Wang Cc: Andrew Morton, linux-mm, Chengming Zhou, Johannes Weiner, Kairui Song, Nhat Pham, Yosry Ahmed On Thu, Sep 10, 2026 at 4:10 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > > > > On 9/10/2026 6:29 PM, Yosry Ahmed wrote: > > On Thu, Sep 10, 2026 at 2:55 AM Kefeng Wang <wangkefeng.wang@huawei.com> wrote: > >> > >> 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 <wangkefeng.wang@huawei.com> > >> --- > >> 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. Yeah I think that's a good idea, even for the zswap_store() path. ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-09-10 19:28 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-10 9:54 [PATCH v2 0/4] mm: zswap: misc optimizations Kefeng Wang 2026-09-10 9:54 ` [PATCH v2 1/4] mm: zswap: pass type and offset to zswap_invalidate() directly Kefeng Wang 2026-09-10 10:26 ` Yosry Ahmed 2026-09-10 17:57 ` Nhat Pham 2026-09-10 19:27 ` Johannes Weiner 2026-09-10 9:54 ` [PATCH v2 2/4] mm: zswap: reuse zswap_invalidate() in zswap_store() check_old path Kefeng Wang 2026-09-10 10:27 ` Yosry Ahmed 2026-09-10 19:27 ` Johannes Weiner 2026-09-10 9:54 ` [PATCH v2 3/4] mm: zswap: avoid unnecessary xarray lookup in zswap_store() Kefeng Wang 2026-09-10 10:28 ` Yosry Ahmed 2026-09-10 9:54 ` [PATCH v2 4/4] mm: zswap: skip zswap_invalidate() in swap_range_free() when zswap is unused Kefeng Wang 2026-09-10 10:29 ` Yosry Ahmed 2026-09-10 11:10 ` Kefeng Wang 2026-09-10 11:12 ` Yosry Ahmed
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox