BACKPORT: 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>

Bug: 356670466
Change-Id: Ie785b2977cc77278c3d72f150a64aa345a0f1a56
Signed-off-by: chunpeng li <chunpng.lee@gmail.com>
(cherry picked from commit 85ce2c517a)
This commit is contained in:
chunpeng li 2024-08-05 11:15:51 +08:00 committed by Will Deacon
parent 3cc9e23956
commit 204e871505
3 changed files with 45 additions and 4 deletions

View File

@ -723,6 +723,8 @@ static inline void mem_cgroup_uncharge_list(struct list_head *page_list)
__mem_cgroup_uncharge_list(page_list); __mem_cgroup_uncharge_list(page_list);
} }
void mem_cgroup_replace_folio(struct folio *old, struct folio *new);
void mem_cgroup_migrate(struct folio *old, struct folio *new); void mem_cgroup_migrate(struct folio *old, struct folio *new);
/** /**
@ -1279,6 +1281,11 @@ static inline void mem_cgroup_uncharge_list(struct list_head *page_list)
{ {
} }
static inline void mem_cgroup_replace_folio(struct folio *old,
struct folio *new)
{
}
static inline void mem_cgroup_migrate(struct folio *old, struct folio *new) static inline void mem_cgroup_migrate(struct folio *old, struct folio *new)
{ {
} }

View File

@ -837,7 +837,7 @@ void replace_page_cache_folio(struct folio *old, struct folio *new)
new->mapping = mapping; new->mapping = mapping;
new->index = offset; new->index = offset;
mem_cgroup_migrate(old, new); mem_cgroup_replace_folio(old, new);
xas_lock_irq(&xas); xas_lock_irq(&xas);
xas_store(&xas, new); xas_store(&xas, new);

View File

@ -7364,16 +7364,17 @@ void __mem_cgroup_uncharge_list(struct list_head *page_list)
} }
/** /**
* mem_cgroup_migrate - Charge a folio's replacement. * mem_cgroup_replace_folio - Charge a folio's replacement.
* @old: Currently circulating folio. * @old: Currently circulating folio.
* @new: Replacement folio. * @new: Replacement folio.
* *
* Charge @new as a replacement folio for @old. @old will * Charge @new as a replacement folio for @old. @old will
* be uncharged upon free. * be uncharged upon free. This is only used by the page cache
* (in replace_page_cache_folio()).
* *
* Both folios must be locked, @new->mapping must be set up. * Both folios must be locked, @new->mapping must be set up.
*/ */
void mem_cgroup_migrate(struct folio *old, struct folio *new) void mem_cgroup_replace_folio(struct folio *old, struct folio *new)
{ {
struct mem_cgroup *memcg; struct mem_cgroup *memcg;
long nr_pages = folio_nr_pages(new); long nr_pages = folio_nr_pages(new);
@ -7412,6 +7413,39 @@ void mem_cgroup_migrate(struct folio *old, struct folio *new)
local_irq_restore(flags); local_irq_restore(flags);
} }
/**
* mem_cgroup_migrate - Transfer the memcg data from the old to the new folio.
* @old: Currently circulating folio.
* @new: Replacement folio.
*
* Transfer the memcg data from the old folio to the new folio for migration.
* The old folio's data info will be cleared. Note that the memory counters
* will remain unchanged throughout the process.
*
* Both folios must be locked, @new->mapping must be set up.
*/
void mem_cgroup_migrate(struct folio *old, struct folio *new)
{
struct mem_cgroup *memcg;
VM_BUG_ON_FOLIO(!folio_test_locked(old), old);
VM_BUG_ON_FOLIO(!folio_test_locked(new), new);
VM_BUG_ON_FOLIO(folio_test_anon(old) != folio_test_anon(new), new);
VM_BUG_ON_FOLIO(folio_nr_pages(old) != folio_nr_pages(new), new);
if (mem_cgroup_disabled())
return;
memcg = folio_memcg(old);
VM_WARN_ON_ONCE_FOLIO(!memcg, old);
if (!memcg)
return;
/* Transfer the charge and the css ref */
commit_charge(new, memcg);
old->memcg_data = 0;
}
DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key); DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);
EXPORT_SYMBOL(memcg_sockets_enabled_key); EXPORT_SYMBOL(memcg_sockets_enabled_key);