[RH7] per-memcg negative dentries accounting

Submitted by Vasily Averin on Jan. 13, 2021, 10:20 a.m.

Details

Message ID 5b0b6457-41b8-6781-7522-d8ee0c94fc40@virtuozzo.com
State New
Series "per-memcg negative dentries accounting"
Headers show

Commit Message

Vasily Averin Jan. 13, 2021, 10:20 a.m.
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@virtuozzo.com>
---
 fs/dcache.c                | 24 ++++++++++++++++++------
 include/linux/memcontrol.h |  3 +++
 mm/memcontrol.c            | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/dcache.c b/fs/dcache.c
index 96ac93f..a9a3bb5 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -393,8 +393,10 @@  static void dentry_unlink_inode(struct dentry * dentry)
 	struct inode *inode = dentry->d_inode;
 	__d_clear_type(dentry);
 	dentry->d_inode = NULL;
-	if (dentry->d_flags & DCACHE_LRU_LIST)
+	if (dentry->d_flags & DCACHE_LRU_LIST) {
 		this_cpu_inc(nr_dentry_negative);
+		memcg_neg_dentry_inc(dentry);
+	}
 	hlist_del_init(&dentry->d_alias);
 	dentry_rcuwalk_invalidate(dentry);
 	spin_unlock(&dentry->d_lock);
@@ -432,8 +434,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));
 }
 
@@ -442,8 +446,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));
 }
 
@@ -474,8 +480,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);
 }
 
@@ -484,8 +492,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);
 }
 
@@ -1871,8 +1881,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);
+	}
 	__d_set_type(dentry, add_flags);
 	if (inode)
 		hlist_add_head(&dentry->d_alias, &inode->i_dentry);
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 5e16658..f609a15 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -229,6 +229,9 @@  static inline void mem_cgroup_dec_page_stat(struct page *page,
 	mem_cgroup_update_page_stat(page, idx, -1);
 }
 
+void memcg_neg_dentry_inc(struct dentry *dentry);
+void memcg_neg_dentry_dec(struct dentry *dentry);
+
 void mem_cgroup_fill_vmstat(struct mem_cgroup *memcg, unsigned long *stats);
 
 unsigned long memcg_ws_activates(struct mem_cgroup *memcg);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 1c32810..1eae25d 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -183,6 +183,7 @@  struct mem_cgroup_stat_cpu {
 	unsigned long events[MEM_CGROUP_EVENTS_NSTATS];
 	unsigned long nr_page_events;
 	unsigned long targets[MEM_CGROUP_NTARGETS];
+	unsigned long nr_dentry_neg;
 };
 
 struct mem_cgroup_stat2_cpu {
@@ -1165,6 +1166,40 @@  mem_cgroup_read_stat2(struct mem_cgroup *memcg, enum mem_cgroup_stat2_index idx)
 	return percpu_counter_sum_positive(&memcg->stat2.counters[idx]);
 }
 
+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->stat->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_kmem(dentry);
+
+	if (memcg)
+		__this_cpu_inc(memcg->stat->nr_dentry_neg);
+}
+
+void memcg_neg_dentry_dec(struct dentry *dentry)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_kmem(dentry);
+
+	if (memcg)
+		__this_cpu_dec(memcg->stat->nr_dentry_neg);
+}
+
 unsigned long memcg_ws_activates(struct mem_cgroup *memcg)
 {
 	return percpu_counter_read_positive(&memcg->stat2.counters[MEM_CGROUP_STAT_WS_ACTIVATE]);
@@ -5738,6 +5773,7 @@  static int memcg_stat_show(struct cgroup *cont, struct cftype *cft,
 		seq_printf(m, "%s %lu\n", mem_cgroup_events_names[i],
 			   mem_cgroup_read_events(memcg, i));
 	seq_printf(m, "oom %lu\n", atomic_long_read(&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", mem_cgroup_lru_names[i],