Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memcontrol: only transfer the memcg data for migration

For most migration use cases, only transfer the memcg data from the old
folio to the new folio, and clear the old folio's memcg data. No charging
and uncharging will be done.

This shaves off some work on the migration path, and avoids the temporary
double charging of a folio during its migration.

The only exception is replace_page_cache_folio(), which will use the old
mem_cgroup_migrate() (now renamed to mem_cgroup_replace_folio). In that
context, the isolation of the old page isn't quite as thorough as with
migration, so we cannot use our new implementation directly.

This patch is the result of the following discussion on the new hugetlb
memcg accounting behavior:

https://lore.kernel.org/lkml/20231003171329.GB314430@monkey/

Link: https://lkml.kernel.org/r/20231006184629.155543-3-nphamcs@gmail.com
Signed-off-by: Nhat Pham <nphamcs@gmail.com>
Suggested-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Frank van der Linden <fvdl@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Rik van Riel <riel@surriel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Tejun heo <tj@kernel.org>
Cc: Yosry Ahmed <yosryahmed@google.com>
Cc: Zefan Li <lizefan.x@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Nhat Pham and committed by
Andrew Morton
85ce2c51 4b569387

+45 -4
+7
include/linux/memcontrol.h
··· 707 707 708 708 void mem_cgroup_cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages); 709 709 710 + void mem_cgroup_replace_folio(struct folio *old, struct folio *new); 711 + 710 712 void mem_cgroup_migrate(struct folio *old, struct folio *new); 711 713 712 714 /** ··· 1278 1276 1279 1277 static inline void mem_cgroup_cancel_charge(struct mem_cgroup *memcg, 1280 1278 unsigned int nr_pages) 1279 + { 1280 + } 1281 + 1282 + static inline void mem_cgroup_replace_folio(struct folio *old, 1283 + struct folio *new) 1281 1284 { 1282 1285 } 1283 1286
+1 -1
mm/filemap.c
··· 816 816 new->mapping = mapping; 817 817 new->index = offset; 818 818 819 - mem_cgroup_migrate(old, new); 819 + mem_cgroup_replace_folio(old, new); 820 820 821 821 xas_lock_irq(&xas); 822 822 xas_store(&xas, new);
+37 -3
mm/memcontrol.c
··· 7292 7292 } 7293 7293 7294 7294 /** 7295 - * mem_cgroup_migrate - Charge a folio's replacement. 7295 + * mem_cgroup_replace_folio - Charge a folio's replacement. 7296 7296 * @old: Currently circulating folio. 7297 7297 * @new: Replacement folio. 7298 7298 * 7299 7299 * Charge @new as a replacement folio for @old. @old will 7300 - * be uncharged upon free. 7300 + * be uncharged upon free. This is only used by the page cache 7301 + * (in replace_page_cache_folio()). 7301 7302 * 7302 7303 * Both folios must be locked, @new->mapping must be set up. 7303 7304 */ 7304 - void mem_cgroup_migrate(struct folio *old, struct folio *new) 7305 + void mem_cgroup_replace_folio(struct folio *old, struct folio *new) 7305 7306 { 7306 7307 struct mem_cgroup *memcg; 7307 7308 long nr_pages = folio_nr_pages(new); ··· 7339 7338 mem_cgroup_charge_statistics(memcg, nr_pages); 7340 7339 memcg_check_events(memcg, folio_nid(new)); 7341 7340 local_irq_restore(flags); 7341 + } 7342 + 7343 + /** 7344 + * mem_cgroup_migrate - Transfer the memcg data from the old to the new folio. 7345 + * @old: Currently circulating folio. 7346 + * @new: Replacement folio. 7347 + * 7348 + * Transfer the memcg data from the old folio to the new folio for migration. 7349 + * The old folio's data info will be cleared. Note that the memory counters 7350 + * will remain unchanged throughout the process. 7351 + * 7352 + * Both folios must be locked, @new->mapping must be set up. 7353 + */ 7354 + void mem_cgroup_migrate(struct folio *old, struct folio *new) 7355 + { 7356 + struct mem_cgroup *memcg; 7357 + 7358 + VM_BUG_ON_FOLIO(!folio_test_locked(old), old); 7359 + VM_BUG_ON_FOLIO(!folio_test_locked(new), new); 7360 + VM_BUG_ON_FOLIO(folio_test_anon(old) != folio_test_anon(new), new); 7361 + VM_BUG_ON_FOLIO(folio_nr_pages(old) != folio_nr_pages(new), new); 7362 + 7363 + if (mem_cgroup_disabled()) 7364 + return; 7365 + 7366 + memcg = folio_memcg(old); 7367 + VM_WARN_ON_ONCE_FOLIO(!memcg, old); 7368 + if (!memcg) 7369 + return; 7370 + 7371 + /* Transfer the charge and the css ref */ 7372 + commit_charge(new, memcg); 7373 + old->memcg_data = 0; 7342 7374 } 7343 7375 7344 7376 DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);