From: Kairui Song Instead of let the caller ensures all slots are in the same memcg, the make it be able to handle different memcg at once. Signed-off-by: Kairui Song --- mm/swapfile.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index 2cd3e260f1bf..cd2d3b2ca6f0 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1883,10 +1883,13 @@ void __swap_cluster_free_entries(struct swap_info_struct *si, struct swap_cluster_info *ci, unsigned int ci_start, unsigned int nr_pages) { + void *shadow; unsigned long old_tb; - unsigned short id; + unsigned int type = si->type; + unsigned int id = 0, id_iter, id_check; unsigned int ci_off = ci_start, ci_end = ci_start + nr_pages; - unsigned long offset = cluster_offset(si, ci) + ci_start; + unsigned long offset = cluster_offset(si, ci); + unsigned int ci_batch = ci_off; VM_WARN_ON(ci->count < nr_pages); @@ -1896,13 +1899,29 @@ void __swap_cluster_free_entries(struct swap_info_struct *si, /* Release the last ref, or after swap cache is dropped */ VM_WARN_ON(!swp_tb_is_shadow(old_tb) || __swp_tb_get_count(old_tb) > 1); __swap_table_set(ci, ci_off, null_to_swp_tb()); + + shadow = swp_tb_to_shadow(old_tb); + id_iter = shadow_to_memcgid(shadow); + if (id != id_iter) { + if (id) { + id_check = swap_cgroup_clear(swp_entry(type, offset + ci_batch), + ci_off - ci_batch); + WARN_ON(id != id_check); + mem_cgroup_uncharge_swap(id, ci_off - ci_batch); + } + id = id_iter; + ci_batch = ci_off; + } } while (++ci_off < ci_end); - id = swap_cgroup_clear(swp_entry(si->type, offset), nr_pages); - if (id) - mem_cgroup_uncharge_swap(id, nr_pages); + if (id) { + id_check = swap_cgroup_clear(swp_entry(type, offset + ci_batch), + ci_off - ci_batch); + WARN_ON(id != id_check); + mem_cgroup_uncharge_swap(id, ci_off - ci_batch); + } - swap_range_free(si, offset, nr_pages); + swap_range_free(si, offset + ci_start, nr_pages); swap_cluster_assert_empty(ci, ci_start, nr_pages, false); if (!ci->count) -- 2.53.0