[RFC PATCH v2 05/10] mm, swap: add xswap_try_shrink and shrink trigger on cluster free
Baoquan He <[email protected]>
| Newsgroups | gmane.linux.kernel,gmane.linux.kernel.mm |
|---|---|
| Message-ID | <[email protected]> |
Add xswap_try_shrink() — the shrink logic that scans backwards from the tail to find contiguous free clusters, then unmaps full pages when >= XSWAP_GROW_CLUSTERS free clusters accumulate. Wire the trigger in __free_cluster(): after a cluster is released to the free list, call xswap_try_shrink() to attempt tail shrinking. Also update the XSWAP_GROW_CLUSTERS comment to reflect both grow and shrink semantics. Signed-off-by: Baoquan He <[email protected]> --- mm/swapfile.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index 5d8e10be0159..0d1d0c5e24c6 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -51,11 +51,13 @@ #ifdef CONFIG_XSWAP /* - * xswap: dynamically grow the cluster_info array via a VM_SPARSE area. + * xswap: dynamically grow and shrink the cluster_info array via a + * VM_SPARSE area. * - * XSWAP_GROW_CLUSTERS is the number of clusters to map in one grow - * operation. It is set to the number of cluster_info structs that - * fit in a single page (at least 16), so that the vmalloc page table + * XSWAP_GROW_CLUSTERS is the number of clusters to map/unmap in one + * grow/shrink operation. It is set to the number of cluster_info + * structs that fit in a single page (at least 16), so that the vmalloc + * page table * overhead is proportional to the number of clusters mapped. */ #define XSWAP_GROW_CLUSTERS \ @@ -66,6 +68,7 @@ static int xswap_map_clusters(struct swap_info_struct *si, static void xswap_unmap_clusters(struct swap_info_struct *si, unsigned long start_idx, unsigned long nr); static int xswap_check_mapped(pte_t *pte, unsigned long addr, void *data); +static void xswap_try_shrink(struct swap_info_struct *si); #endif static void swap_range_alloc(struct swap_info_struct *si, @@ -629,6 +632,9 @@ static void __free_cluster(struct swap_info_struct *si, struct swap_cluster_info swap_cluster_free_table(ci); move_cluster(si, ci, &si->free_clusters, CLUSTER_FLAG_FREE); ci->order = 0; +#ifdef CONFIG_XSWAP + xswap_try_shrink(si); +#endif } /* @@ -3835,6 +3841,40 @@ static int xswap_check_mapped(pte_t *pte, unsigned long addr, void *data) { return 1; } + +/* + * Try to shrink the cluster_info tail: unmap contiguous free clusters + * at the end of the mapped range. + */ +static void xswap_try_shrink(struct swap_info_struct *si) +{ + struct swap_cluster_info *ci; + unsigned long last, idx; + + if (!(si->flags & SWP_XSWAP)) + return; + if (READ_ONCE(si->nr_clusters_mapped) <= 1) /* keep cluster 0 */ + return; + + /* Find the last non-free cluster from the tail */ + last = READ_ONCE(si->nr_clusters_mapped); + while (last > 1) { + idx = last - 1; + ci = &si->cluster_info[idx]; + if (ci->count || ci->flags != CLUSTER_FLAG_FREE) + break; + last = idx; + } + + if (last == si->nr_clusters_mapped) + return; /* nothing to shrink */ + + /* Only unmap if we can free at least one full page of clusters */ + if (si->nr_clusters_mapped - last < XSWAP_GROW_CLUSTERS) + return; + + xswap_unmap_clusters(si, last, si->nr_clusters_mapped - last); +} #endif /* CONFIG_XSWAP */ static int setup_swap_clusters_info(struct swap_info_struct *si, -- 2.54.0