Skip to content

Commit 73f839b

Browse files
Muchun Songakpm00
authored andcommitted
mm: memcontrol: fix swap counter leak from offline cgroup
Commit 6769183 removed the parameter of id from swap_cgroup_record() and get the memcg id from mem_cgroup_id(folio_memcg(folio)). However, the caller of it may update a different memcg's counter instead of folio_memcg(folio). E.g. in the caller of mem_cgroup_swapout(), @swap_memcg could be different with @memcg and update the counter of @swap_memcg, but swap_cgroup_record() records the wrong memcg's ID. When it is uncharged from __mem_cgroup_uncharge_swap(), the swap counter will leak since the wrong recorded ID. Fix it by bringing the parameter of id back. Link: https://lkml.kernel.org/r/[email protected] Fixes: 6769183 ("mm/swap_cgroup: decouple swap cgroup recording and clearing") Signed-off-by: Muchun Song <[email protected]> Reviewed-by: Kairui Song <[email protected]> Cc: Chris Li <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Shakeel Butt <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 8c6ff7f commit 73f839b

File tree

3 files changed

+8
-7
lines changed

3 files changed

+8
-7
lines changed

include/linux/swap_cgroup.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#if defined(CONFIG_MEMCG) && defined(CONFIG_SWAP)
88

9-
extern void swap_cgroup_record(struct folio *folio, swp_entry_t ent);
9+
extern void swap_cgroup_record(struct folio *folio, unsigned short id, swp_entry_t ent);
1010
extern unsigned short swap_cgroup_clear(swp_entry_t ent, unsigned int nr_ents);
1111
extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
1212
extern int swap_cgroup_swapon(int type, unsigned long max_pages);
@@ -15,7 +15,7 @@ extern void swap_cgroup_swapoff(int type);
1515
#else
1616

1717
static inline
18-
void swap_cgroup_record(struct folio *folio, swp_entry_t ent)
18+
void swap_cgroup_record(struct folio *folio, unsigned short id, swp_entry_t ent)
1919
{
2020
}
2121

mm/memcontrol.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4993,7 +4993,7 @@ void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry)
49934993
mem_cgroup_id_get_many(swap_memcg, nr_entries - 1);
49944994
mod_memcg_state(swap_memcg, MEMCG_SWAP, nr_entries);
49954995

4996-
swap_cgroup_record(folio, entry);
4996+
swap_cgroup_record(folio, mem_cgroup_id(swap_memcg), entry);
49974997

49984998
folio_unqueue_deferred_split(folio);
49994999
folio->memcg_data = 0;
@@ -5055,7 +5055,7 @@ int __mem_cgroup_try_charge_swap(struct folio *folio, swp_entry_t entry)
50555055
mem_cgroup_id_get_many(memcg, nr_pages - 1);
50565056
mod_memcg_state(memcg, MEMCG_SWAP, nr_pages);
50575057

5058-
swap_cgroup_record(folio, entry);
5058+
swap_cgroup_record(folio, mem_cgroup_id(memcg), entry);
50595059

50605060
return 0;
50615061
}

mm/swap_cgroup.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ static unsigned short __swap_cgroup_id_xchg(struct swap_cgroup *map,
5858
* entries must not have been charged
5959
*
6060
* @folio: the folio that the swap entry belongs to
61+
* @id: mem_cgroup ID to be recorded
6162
* @ent: the first swap entry to be recorded
6263
*/
63-
void swap_cgroup_record(struct folio *folio, swp_entry_t ent)
64+
void swap_cgroup_record(struct folio *folio, unsigned short id,
65+
swp_entry_t ent)
6466
{
6567
unsigned int nr_ents = folio_nr_pages(folio);
6668
struct swap_cgroup *map;
@@ -72,8 +74,7 @@ void swap_cgroup_record(struct folio *folio, swp_entry_t ent)
7274
map = swap_cgroup_ctrl[swp_type(ent)].map;
7375

7476
do {
75-
old = __swap_cgroup_id_xchg(map, offset,
76-
mem_cgroup_id(folio_memcg(folio)));
77+
old = __swap_cgroup_id_xchg(map, offset, id);
7778
VM_BUG_ON(old);
7879
} while (++offset != end);
7980
}

0 commit comments

Comments
 (0)