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

Reply via email to