Hi Barry,
Thanks for updating this thread, I'm thinking maybe something will
better be done at the zswap side?
The concern of using zswap_invalidate is that it calls xa_erase which
requires the xa spin lock. But if we are calling zswap_invalidate in
swap_entry_range_free, and ensure the slot is HAS_CACHE pinned, doing
a lockless read first with xa_load should be OK for checking if the
slot needs a ZSWAP invalidation. The performance cost will be minimal
and we only need to call zswap_invalidate in one place, something like
this (haven't tested, comments are welcome). Also ZSWAP mthp will
still store entried in order 0 so this should be OK for future.
diff --git a/mm/swap_slots.c b/mm/swap_slots.c
index 13ab3b771409..d7bb3caa9d4e 100644
--- a/mm/swap_slots.c
+++ b/mm/swap_slots.c
@@ -273,9 +273,6 @@ void free_swap_slot(swp_entry_t entry)
{
struct swap_slots_cache *cache;
- /* Large folio swap slot is not covered. */
- zswap_invalidate(entry);
-
cache = raw_cpu_ptr(&swp_slots);
if (likely(use_swap_slot_cache && cache->slots_ret)) {
spin_lock_irq(&cache->free_lock);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f947f4dd31a9..fbc25d38a27e 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -242,9 +242,6 @@ static int __try_to_reclaim_swap(struct
swap_info_struct *si,
folio_set_dirty(folio);
spin_lock(&si->lock);
- /* Only sinple page folio can be backed by zswap */
- if (nr_pages == 1)
- zswap_invalidate(entry);
swap_entry_range_free(si, entry, nr_pages);
spin_unlock(&si->lock);
ret = nr_pages;
@@ -1545,6 +1542,10 @@ static void swap_entry_range_free(struct
swap_info_struct *si, swp_entry_t entry
unsigned char *map_end = map + nr_pages;
struct swap_cluster_info *ci;
+ /* Slots are pinned with SWAP_HAS_CACHE, safe to invalidate */
+ for (int i = 0; i < nr_pages; ++i)
+ zswap_invalidate(swp_entry(si->type, offset + i));
+
ci = lock_cluster(si, offset);
do {
VM_BUG_ON(*map != SWAP_HAS_CACHE);
diff --git a/mm/zswap.c b/mm/zswap.c
index df66ab102d27..100ad04397fe 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -1656,15 +1656,18 @@ bool zswap_load(struct folio *folio)
return true;
}
+/* Caller need to pin the slot to prevent parallel store */
void zswap_invalidate(swp_entry_t swp)
{
pgoff_t offset = swp_offset(swp);
struct xarray *tree = swap_zswap_tree(swp);
struct zswap_entry *entry;
- entry = xa_erase(tree, offset);
- if (entry)
- zswap_entry_free(entry);
+ if (xa_load(tree, offset)) {
+ entry = xa_erase(tree, offset);
+ if (entry)
+ zswap_entry_free(entry);
+ }
}
int zswap_swapon(int type, unsigned long nr_pages)
--
2.45.2