Add dmem.events.local for local-only low/max event counts per DMEM region. Refactor the shared events show logic used by dmem.events.
Signed-off-by: Hongfu Li <[email protected]> --- Documentation/admin-guide/cgroup-v2.rst | 5 ++-- kernel/cgroup/dmem.c | 32 +++++++++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index afc924539a41..5e4dbe4a75c6 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -2881,7 +2881,7 @@ DMEM Interface Files drm/0000:03:00.0/vram0 12550144 drm/0000:03:00.0/stolen 8650752 - dmem.events + dmem.events, dmem.events.local A read-only file that reports the number of times each cgroup has hit its configured memory limits. The format lists each region on a single line, followed by the event counters:: @@ -2894,7 +2894,8 @@ DMEM Interface Files ``max`` counts how many times an allocation failed because the cgroup or one of its ancestors hit ``dmem.max``. - ``dmem.events`` contains hierarchical counts. This file exists + ``dmem.events`` contains hierarchical counts. ``dmem.events.local`` + contains counts for only the cgroup itself. These files exist for all cgroups except root. HugeTLB diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c index 79d4c5d0a046..29f8719561e6 100644 --- a/kernel/cgroup/dmem.c +++ b/kernel/cgroup/dmem.c @@ -60,6 +60,7 @@ struct dmemcg_state { struct list_head pools; struct cgroup_file events_file; + struct cgroup_file events_local_file; }; enum dmemcg_memory_event { @@ -84,6 +85,7 @@ struct dmem_cgroup_pool_state { struct dmem_cgroup_pool_state *parent; atomic_long_t events[DMEMCG_NR_EVENTS]; + atomic_long_t events_local[DMEMCG_NR_EVENTS]; refcount_t ref; bool inited; @@ -196,6 +198,9 @@ static u64 get_resource_current(struct dmem_cgroup_pool_state *pool) static void dmemcg_memory_event(struct dmem_cgroup_pool_state *pool, enum dmemcg_memory_event event) { + atomic_long_inc(&pool->events_local[event]); + cgroup_file_notify(&pool->cs->events_local_file); + for (; pool; pool = pool->parent) { atomic_long_inc(&pool->events[event]); cgroup_file_notify(&pool->cs->events_file); @@ -203,11 +208,14 @@ static void dmemcg_memory_event(struct dmem_cgroup_pool_state *pool, } static long dmemcg_get_event(struct dmem_cgroup_pool_state *pool, - enum dmemcg_memory_event event) + enum dmemcg_memory_event event, bool local) { if (!pool) return 0; + if (local) + return atomic_long_read(&pool->events_local[event]); + return atomic_long_read(&pool->events[event]); } @@ -874,7 +882,7 @@ static int dmem_cgroup_region_max_show(struct seq_file *sf, void *v) return dmemcg_limit_show(sf, v, get_resource_max); } -static int dmem_cgroup_region_events_show(struct seq_file *sf, void *v) +static int dmemcg_events_show(struct seq_file *sf, void *v, bool local) { struct dmemcg_state *dmemcs = css_to_dmemcs(seq_css(sf)); struct dmem_cgroup_region *region; @@ -885,14 +893,24 @@ static int dmem_cgroup_region_events_show(struct seq_file *sf, void *v) seq_puts(sf, region->name); seq_printf(sf, " low %ld max %ld\n", - dmemcg_get_event(pool, DMEMCG_LOW), - dmemcg_get_event(pool, DMEMCG_MAX)); + dmemcg_get_event(pool, DMEMCG_LOW, local), + dmemcg_get_event(pool, DMEMCG_MAX, local)); } rcu_read_unlock(); return 0; } +static int dmem_cgroup_region_events_show(struct seq_file *sf, void *v) +{ + return dmemcg_events_show(sf, v, false); +} + +static int dmem_cgroup_region_events_local_show(struct seq_file *sf, void *v) +{ + return dmemcg_events_show(sf, v, true); +} + static ssize_t dmem_cgroup_region_max_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { @@ -933,6 +951,12 @@ static struct cftype files[] = { .file_offset = offsetof(struct dmemcg_state, events_file), .flags = CFTYPE_NOT_ON_ROOT, }, + { + .name = "events.local", + .seq_show = dmem_cgroup_region_events_local_show, + .file_offset = offsetof(struct dmemcg_state, events_local_file), + .flags = CFTYPE_NOT_ON_ROOT, + }, { } /* Zero entry terminates. */ }; -- 2.25.1
