hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAFWQH ---------------------------------------- Even if all processes that use the zspool exits, some swapcache pages may still exist and occupy zspool memory. When unbinding memcg for the zspool, the zspool should be empty. If the zspool memory is still used, try to reclaim swapcache pages. Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- .../multi_pool_zram/multi_pool_zram_drv.c | 24 +++++++ include/linux/swap.h | 10 +++ mm/swapfile.c | 65 +++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/drivers/block/multi_pool_zram/multi_pool_zram_drv.c b/drivers/block/multi_pool_zram/multi_pool_zram_drv.c index 08987c974a70..732a084539cc 100644 --- a/drivers/block/multi_pool_zram/multi_pool_zram_drv.c +++ b/drivers/block/multi_pool_zram/multi_pool_zram_drv.c @@ -134,9 +134,26 @@ static void zram_set_obj_size(struct zram *zram, zram->table[index].flags = (flags << ZRAM_FLAG_SHIFT) | size; } +struct zram_is_used_arg { + struct zram *zram; + int pool_index; +}; + +static bool zram_is_used(void *arg) +{ + struct zram_is_used_arg *zram_arg = arg; + struct zram *zram = zram_arg->zram; + int pool_index = zram_arg->pool_index; + + return (zs_get_total_pages(zram->mem_pool[pool_index]) != 0) + || (atomic64_read(&zram->zspool_stats[pool_index].same_pages) != 0); +} + static int zspool_bind_memcg(struct zram *zram, int pool_index, struct mem_cgroup *memcg) { + struct zram_is_used_arg arg = {.zram = zram, .pool_index = pool_index}; + bool swapcache_reclaimed = false; bool drained = false; int ret = -EBUSY; @@ -160,6 +177,13 @@ static int zspool_bind_memcg(struct zram *zram, int pool_index, drained = true; goto restart; } + if (!swapcache_reclaimed) { + spin_unlock(&zram->rebind_memcg_spinlock); + up_write(&zram->rebind_memcg_lock); + try_to_reclaim_swap_cache(zram->disk->part0->bd_inode, zram_is_used, &arg); + swapcache_reclaimed = true; + goto restart; + } goto out; } diff --git a/include/linux/swap.h b/include/linux/swap.h index d31b74bd7eb1..1e07f2e23104 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -733,5 +733,15 @@ static inline bool mem_cgroup_swap_full(struct folio *folio) } #endif +struct zs_pool; +#ifdef CONFIG_MEMCG_ZRAM +void try_to_reclaim_swap_cache(struct inode *inode, bool (*continue_reclaim)(void *arg), void *arg); +#else +static inline +void try_to_reclaim_swap_cache(struct inode *inode, bool (*continue_reclaim)(void *arg), void *arg) +{ +} +#endif + #endif /* __KERNEL__*/ #endif /* _LINUX_SWAP_H */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 889a22c23a94..1b9d60f6ebb3 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -3887,6 +3887,71 @@ void __folio_throttle_swaprate(struct folio *folio, gfp_t gfp) } #endif +#ifdef CONFIG_MEMCG_ZRAM +static unsigned int find_next_to_reclaim(struct swap_info_struct *si, + unsigned int prev) +{ + unsigned int i; + unsigned char count; + + for (i = prev + 1; i < si->max; i++) { + count = READ_ONCE(si->swap_map[i]); + if (count == SWAP_HAS_CACHE) + break; + if ((i % LATENCY_LIMIT) == 0) + cond_resched(); + } + + if (i == si->max) + i = 0; + + return i; +} + +/* Refer to frontswap_shrink(). */ +void try_to_reclaim_swap_cache(struct inode *inode, bool (*continue_reclaim)(void *arg), void *arg) +{ + struct swap_info_struct *si = NULL; + unsigned int i = 0; + struct folio *folio; + bool found = false; + swp_entry_t entry; + int type; + + spin_lock(&swap_lock); + plist_for_each_entry(si, &swap_active_head, list) { + if (si->swap_file->f_mapping == inode->i_mapping) { + found = true; + type = si->type; + break; + } + } + spin_unlock(&swap_lock); + if (!found) + return; + + disable_swap_slots_cache_lock(); + while (READ_ONCE(si->inuse_pages) && continue_reclaim(arg)) { + i = find_next_to_reclaim(si, i); + if (!i) + break; + + entry = swp_entry(type, i); + folio = filemap_get_folio(swap_address_space(entry), i); + if (IS_ERR(folio)) + continue; + + folio_lock(folio); + folio_wait_writeback(folio); + folio_free_swap(folio); + folio_unlock(folio); + folio_put(folio); + } + reenable_swap_slots_cache_unlock(); +} +EXPORT_SYMBOL_GPL(try_to_reclaim_swap_cache); +#endif + static int __init swapfile_init(void) { int nid; -- 2.43.0