| From: Shakeel Butt <shakeel.butt@linux.dev> |
| Subject: memcg: warn for unexpected events and stats |
| Date: Wed, 1 May 2024 10:26:16 -0700 |
| |
| To reduce memory usage by the memcg events and stats, the kernel uses |
| indirection table and only allocate stats and events which are being used |
| by the memcg code. To make this more robust, let's add warnings where |
| unexpected stats and events indexes are used. |
| |
| Link: https://lkml.kernel.org/r/20240501172617.678560-8-shakeel.butt@linux.dev |
| Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev> |
| Reviewed-by: Roman Gushchin <roman.gushchin@linux.dev> |
| Cc: Johannes Weiner <hannes@cmpxchg.org> |
| Cc: Michal Hocko <mhocko@kernel.org> |
| Cc: Muchun Song <muchun.song@linux.dev> |
| Cc: T.J. Mercier <tjmercier@google.com> |
| Cc: Yosry Ahmed <yosryahmed@google.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| mm/memcontrol.c | 39 +++++++++++++++++++++++---------------- |
| 1 file changed, 23 insertions(+), 16 deletions(-) |
| |
| --- a/mm/memcontrol.c~memcg-warn-for-unexpected-events-and-stats |
| +++ a/mm/memcontrol.c |
| @@ -670,7 +670,7 @@ unsigned long lruvec_page_state(struct l |
| return node_page_state(lruvec_pgdat(lruvec), idx); |
| |
| i = memcg_stats_index(idx); |
| - if (i < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return 0; |
| |
| pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); |
| @@ -686,14 +686,14 @@ unsigned long lruvec_page_state_local(st |
| enum node_stat_item idx) |
| { |
| struct mem_cgroup_per_node *pn; |
| - long x = 0; |
| + long x; |
| int i; |
| |
| if (mem_cgroup_disabled()) |
| return node_page_state(lruvec_pgdat(lruvec), idx); |
| |
| i = memcg_stats_index(idx); |
| - if (i < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return 0; |
| |
| pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); |
| @@ -922,7 +922,7 @@ unsigned long memcg_page_state(struct me |
| long x; |
| int i = memcg_stats_index(idx); |
| |
| - if (i < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return 0; |
| |
| x = READ_ONCE(memcg->vmstats->state[i]); |
| @@ -959,7 +959,10 @@ void __mod_memcg_state(struct mem_cgroup |
| { |
| int i = memcg_stats_index(idx); |
| |
| - if (mem_cgroup_disabled() || i < 0) |
| + if (mem_cgroup_disabled()) |
| + return; |
| + |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return; |
| |
| __this_cpu_add(memcg->vmstats_percpu->state[i], val); |
| @@ -972,7 +975,7 @@ static unsigned long memcg_page_state_lo |
| long x; |
| int i = memcg_stats_index(idx); |
| |
| - if (i < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return 0; |
| |
| x = READ_ONCE(memcg->vmstats->state_local[i]); |
| @@ -991,7 +994,7 @@ static void __mod_memcg_lruvec_state(str |
| struct mem_cgroup *memcg; |
| int i = memcg_stats_index(idx); |
| |
| - if (i < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return; |
| |
| pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); |
| @@ -1102,34 +1105,38 @@ void __mod_lruvec_kmem_state(void *p, en |
| void __count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx, |
| unsigned long count) |
| { |
| - int index = memcg_events_index(idx); |
| + int i = memcg_events_index(idx); |
| |
| - if (mem_cgroup_disabled() || index < 0) |
| + if (mem_cgroup_disabled()) |
| + return; |
| + |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, idx)) |
| return; |
| |
| memcg_stats_lock(); |
| - __this_cpu_add(memcg->vmstats_percpu->events[index], count); |
| + __this_cpu_add(memcg->vmstats_percpu->events[i], count); |
| memcg_rstat_updated(memcg, count); |
| memcg_stats_unlock(); |
| } |
| |
| static unsigned long memcg_events(struct mem_cgroup *memcg, int event) |
| { |
| - int index = memcg_events_index(event); |
| + int i = memcg_events_index(event); |
| |
| - if (index < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, event)) |
| return 0; |
| - return READ_ONCE(memcg->vmstats->events[index]); |
| + |
| + return READ_ONCE(memcg->vmstats->events[i]); |
| } |
| |
| static unsigned long memcg_events_local(struct mem_cgroup *memcg, int event) |
| { |
| - int index = memcg_events_index(event); |
| + int i = memcg_events_index(event); |
| |
| - if (index < 0) |
| + if (WARN_ONCE(i < 0, "%s: missing stat item %d\n", __func__, event)) |
| return 0; |
| |
| - return READ_ONCE(memcg->vmstats->events_local[index]); |
| + return READ_ONCE(memcg->vmstats->events_local[i]); |
| } |
| |
| static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg, |
| _ |