[Devel] [PATCH RHEL COMMIT] mm: per-memcg negative dentries accounting

Konstantin Khorenko khorenko at virtuozzo.com
Thu Sep 30 17:44:05 MSK 2021


The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after ark-5.14
------>
commit 62a6cd4511cfa3c521a961b2e6ba84436367c6d0
Author: Vasily Averin <vvs at virtuozzo.com>
Date:   Thu Sep 30 17:44:05 2021 +0300

    mm: per-memcg negative dentries accounting
    
    This patch adds per-memcg negative dentries accounting
    and makes them visible in userspace via memcg statistic
    
    https://jira.sw.ru/browse/PSBM-104223
    https://bugs.openvz.org/browse/OVZ-7225
    Signed-off-by: Vasily Averin <vvs at virtuozzo.com>
    
    (cherry-picked from vz7 commit ("8d980b969c46 per-memcg negative dentries
    accounting"))
    
    conflicts:
            - mem_cgroup_from_kmem changed to mem_cgroup_from_obj
            - memcg->stat changed to memcg->vmstats_percpu
    
    https://jira.sw.ru/browse/PSBM-127858
    Signed-off-by: Valeriy Vdovin <valeriy.vdovin at virtuozzo.com>
    
    +++
    mm: memory.stat format fix "negative dentries"
    
    https://jira.sw.ru/browse/PSBM-125735
    
    Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn at virtuozzo.com>
    
    (cherry-picked from c59eb09a181a666cdf9d6e71ead567ba1f4eda20)
    https://jira.sw.ru/browse/PSBM-127858
    
    Signed-off-by: Valeriy Vdovin <valeriy.vdovin at virtuozzo.com>
    
    Cherry-picked from vz8 commit 12cf7352a1ce ("mm: per-memcg negative
    dentries accounting").
    
    Added empty static inline functions for !CONFIG_MEMCG case.
    
    Signed-off-by: Nikita Yushchenko <nikita.yushchenko at virtuozzo.com>
---
 fs/dcache.c                | 21 ++++++++++++++++-----
 include/linux/memcontrol.h | 12 ++++++++++++
 mm/memcontrol.c            | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index fa0a8fe12bfd..18e97f1c4d30 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -32,6 +32,7 @@
 #include <linux/bit_spinlock.h>
 #include <linux/rculist_bl.h>
 #include <linux/list_lru.h>
+#include <linux/memcontrol.h>
 #include "internal.h"
 #include "mount.h"
 
@@ -403,8 +404,10 @@ static void d_lru_add(struct dentry *dentry)
 	D_FLAG_VERIFY(dentry, 0);
 	dentry->d_flags |= DCACHE_LRU_LIST;
 	this_cpu_inc(nr_dentry_unused);
-	if (d_is_negative(dentry))
+	if (d_is_negative(dentry)) {
 		this_cpu_inc(nr_dentry_negative);
+		memcg_neg_dentry_inc(dentry);
+	}
 	WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
 }
 
@@ -413,8 +416,10 @@ static void d_lru_del(struct dentry *dentry)
 	D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
 	dentry->d_flags &= ~DCACHE_LRU_LIST;
 	this_cpu_dec(nr_dentry_unused);
-	if (d_is_negative(dentry))
+	if (d_is_negative(dentry)) {
 		this_cpu_dec(nr_dentry_negative);
+		memcg_neg_dentry_dec(dentry);
+	}
 	WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
 }
 
@@ -445,8 +450,10 @@ static void d_lru_isolate(struct list_lru_one *lru, struct dentry *dentry)
 	D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
 	dentry->d_flags &= ~DCACHE_LRU_LIST;
 	this_cpu_dec(nr_dentry_unused);
-	if (d_is_negative(dentry))
+	if (d_is_negative(dentry)) {
 		this_cpu_dec(nr_dentry_negative);
+		memcg_neg_dentry_dec(dentry);
+	}
 	list_lru_isolate(lru, &dentry->d_lru);
 }
 
@@ -455,8 +462,10 @@ static void d_lru_shrink_move(struct list_lru_one *lru, struct dentry *dentry,
 {
 	D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
 	dentry->d_flags |= DCACHE_SHRINK_LIST;
-	if (d_is_negative(dentry))
+	if (d_is_negative(dentry)) {
 		this_cpu_dec(nr_dentry_negative);
+		memcg_neg_dentry_dec(dentry);
+	}
 	list_lru_isolate_move(lru, &dentry->d_lru, list);
 }
 
@@ -1978,8 +1987,10 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
 	/*
 	 * Decrement negative dentry count if it was in the LRU list.
 	 */
-	if (dentry->d_flags & DCACHE_LRU_LIST)
+	if (dentry->d_flags & DCACHE_LRU_LIST) {
 		this_cpu_dec(nr_dentry_negative);
+		memcg_neg_dentry_dec(dentry);
+	}
 	hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
 	raw_write_seqcount_begin(&dentry->d_seq);
 	__d_set_inode_and_type(dentry, inode, add_flags);
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 46b92cc0bdc5..a4e0e9830d29 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -88,6 +88,7 @@ struct memcg_vmstats_percpu {
 	/* Cgroup1: threshold notifications & softlimit tree updates */
 	unsigned long		nr_page_events;
 	unsigned long		targets[MEM_CGROUP_NTARGETS];
+	unsigned long		nr_dentry_neg;
 };
 
 struct memcg_vmstats {
@@ -1163,6 +1164,9 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
 
 void mem_cgroup_fill_meminfo(struct mem_cgroup *memcg, struct meminfo *mi);
 
+void memcg_neg_dentry_inc(struct dentry *dentry);
+void memcg_neg_dentry_dec(struct dentry *dentry);
+
 #else /* CONFIG_MEMCG */
 
 #define MEM_CGROUP_ID_SHIFT	0
@@ -1556,6 +1560,14 @@ static void mem_cgroup_fill_meminfo(struct mem_cgroup *memcg, struct meminfo *mi
 {
 }
 
+static inline void memcg_neg_dentry_inc(struct dentry *dentry)
+{
+}
+
+static inline void memcg_neg_dentry_dec(struct dentry *dentry)
+{
+}
+
 #endif /* CONFIG_MEMCG */
 
 static inline void __inc_lruvec_kmem_state(void *p, enum node_stat_item idx)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e92919d8ce06..7cb3e3e8d9fc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3576,6 +3576,40 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
 	return nr_reclaimed;
 }
 
+static inline unsigned long
+mem_cgroup_read_nd(struct mem_cgroup *memcg)
+{
+	long val = 0;
+	int cpu;
+
+	/* Per-cpu values can be negative, use a signed accumulator */
+	for_each_possible_cpu(cpu)
+		val += per_cpu(memcg->vmstats_percpu->nr_dentry_neg, cpu);
+	/*
+	 * Summing races with updates, so val may be negative.  Avoid exposing
+	 * transient negative values.
+	 */
+	if (val < 0)
+		val = 0;
+	return val;
+}
+
+void memcg_neg_dentry_inc(struct dentry *dentry)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_obj(dentry);
+
+	if (memcg)
+		__this_cpu_inc(memcg->vmstats_percpu->nr_dentry_neg);
+}
+
+void memcg_neg_dentry_dec(struct dentry *dentry)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_obj(dentry);
+
+	if (memcg)
+		__this_cpu_dec(memcg->vmstats_percpu->nr_dentry_neg);
+}
+
 /*
  * Reclaims as many pages from the given memcg as possible.
  *
@@ -4177,6 +4211,7 @@ static int memcg_stat_show(struct seq_file *m, void *v)
 	else
 		seq_printf(m, "oom %lu\n",
 			atomic_long_read(&memcg->memory_events[MEMCG_OOM]));
+	seq_printf(m, "negative_dentries %lu\n", mem_cgroup_read_nd(memcg));
 
 	for (i = 0; i < NR_LRU_LISTS; i++)
 		seq_printf(m, "%s %lu\n", lru_list_name(i),


More information about the Devel mailing list