[Devel] [PATCH RHEL7 COMMIT] memcg: allow to disable cleancache per memcg

Konstantin Khorenko khorenko at virtuozzo.com
Tue Oct 20 04:59:31 PDT 2015


The commit is pushed to "branch-rh7-3.10.0-229.7.2.vz7.8.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-229.7.2.vz7.8.8
------>
commit 6157411c658b2aa2702432b018bd679a017e5416
Author: Vladimir Davydov <vdavydov at virtuozzo.com>
Date:   Tue Oct 20 15:59:31 2015 +0400

    memcg: allow to disable cleancache per memcg
    
    Currently, it is only possible to disable tcache system-wide, but it
    might be useful to disable it for a particular container while leaving
    it enabled for others, e.g. in case the container is known to generate
    tons of used-once page cache (backup).
    
    This patch introduces memory.disable_cleancache per memcg knob. Writing
    1 to it disables cleancache for the corresponding cgroup. Cleancache may
    be re-enabled by writing 0 to it.
    
    https://jira.sw.ru/browse/PSBM-34163
    
    Signed-off-by: Vladimir Davydov <vdavydov at virtuozzo.com>
    Reviewed-by: Kirill Tkhai <ktkhai at viztuozzo.com>
---
 include/linux/memcontrol.h |  6 ++++
 mm/cleancache.c            | 10 +++++--
 mm/memcontrol.c            | 71 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 0c85642..5835c8c 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -118,6 +118,7 @@ void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
  */
 int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec);
 bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg);
+bool mem_cgroup_cleancache_disabled(struct page *page);
 int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
 unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list);
 void mem_cgroup_update_lru_size(struct lruvec *, enum lru_list, int);
@@ -353,6 +354,11 @@ static inline bool mem_cgroup_low(struct mem_cgroup *root,
 	return false;
 }
 
+static inline bool mem_cgroup_cleancache_disabled(struct page *page)
+{
+	return false;
+}
+
 static inline unsigned long
 mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 {
diff --git a/mm/cleancache.c b/mm/cleancache.c
index a3308bc..16fc1d7 100644
--- a/mm/cleancache.c
+++ b/mm/cleancache.c
@@ -15,6 +15,7 @@
 #include <linux/fs.h>
 #include <linux/exportfs.h>
 #include <linux/mm.h>
+#include <linux/memcontrol.h>
 #include <linux/debugfs.h>
 #include <linux/cleancache.h>
 
@@ -227,8 +228,13 @@ void __cleancache_put_page(struct page *page)
 	pool_id = page->mapping->host->i_sb->cleancache_poolid;
 	if (pool_id >= 0 &&
 		cleancache_get_key(page->mapping->host, &key) >= 0) {
-		cleancache_ops->put_page(pool_id, key, page->index, page);
-		cleancache_puts++;
+		if (!mem_cgroup_cleancache_disabled(page)) {
+			cleancache_ops->put_page(pool_id, key,
+						 page->index, page);
+			cleancache_puts++;
+		} else
+			cleancache_ops->invalidate_page(pool_id, key,
+							page->index);
 	}
 }
 EXPORT_SYMBOL(__cleancache_put_page);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 14e6aee..234ed8d 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -315,6 +315,20 @@ struct mem_cgroup {
 	/* set when res.limit == memsw.limit */
 	bool		memsw_is_minimum;
 
+#ifdef CONFIG_CLEANCACHE
+	/*
+	 * cleancache_disabled_toggle: toggled by writing to
+	 * memory.disable_cleancache
+	 *
+	 * cleancache_disabled: set iff cleancache_disabled_toggle is
+	 * set in this cgroup or any of its ascendants; controls whether
+	 * cleancache callback is called when a page is evicted from
+	 * this cgroup
+	 */
+	bool cleancache_disabled_toggle;
+	bool cleancache_disabled;
+#endif
+
 	/* protect arrays of thresholds */
 	struct mutex thresholds_lock;
 
@@ -1578,6 +1592,27 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
 	return true;
 }
 
+#ifdef CONFIG_CLEANCACHE
+bool mem_cgroup_cleancache_disabled(struct page *page)
+{
+	struct page_cgroup *pc;
+	bool ret = false;
+
+	if (mem_cgroup_disabled())
+		return false;
+
+	pc = lookup_page_cgroup(page);
+	if (!PageCgroupUsed(pc))
+		return false;
+
+	lock_page_cgroup(pc);
+	if (likely(PageCgroupUsed(pc)))
+		ret = pc->mem_cgroup->cleancache_disabled;
+	unlock_page_cgroup(pc);
+	return ret;
+}
+#endif
+
 void mem_cgroup_note_oom_kill(struct mem_cgroup *root_memcg,
 			      struct task_struct *task)
 {
@@ -5191,6 +5226,31 @@ static int mem_cgroup_oom_guarantee_write(struct cgroup *cont,
 	return 0;
 }
 
+#ifdef CONFIG_CLEANCACHE
+static u64 mem_cgroup_disable_cleancache_read(struct cgroup *cgrp,
+					      struct cftype *cft)
+{
+	return mem_cgroup_from_cont(cgrp)->cleancache_disabled_toggle;
+}
+
+static int mem_cgroup_disable_cleancache_write(struct cgroup *cgrp,
+					       struct cftype *cft, u64 val)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *iter, *parent;
+
+	mutex_lock(&memcg_create_mutex);
+	memcg->cleancache_disabled_toggle = !!val;
+	for_each_mem_cgroup_tree(iter, memcg) {
+		parent = parent_mem_cgroup(iter);
+		iter->cleancache_disabled = parent->cleancache_disabled ||
+					iter->cleancache_disabled_toggle;
+	}
+	mutex_unlock(&memcg_create_mutex);
+	return 0;
+}
+#endif
+
 static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
 		unsigned long long *mem_limit, unsigned long long *memsw_limit)
 {
@@ -6131,6 +6191,14 @@ static struct cftype mem_cgroup_files[] = {
 		.read_seq_string = memcg_numa_stat_show,
 	},
 #endif
+#ifdef CONFIG_CLEANCACHE
+	{
+		.name = "disable_cleancache",
+		.flags = CFTYPE_NOT_ON_ROOT,
+		.read_u64 = mem_cgroup_disable_cleancache_read,
+		.write_u64 = mem_cgroup_disable_cleancache_write,
+	},
+#endif
 #ifdef CONFIG_MEMCG_KMEM
 	{
 		.name = "kmem.limit_in_bytes",
@@ -6385,6 +6453,9 @@ mem_cgroup_css_online(struct cgroup *cont)
 	memcg->use_hierarchy = parent->use_hierarchy;
 	memcg->oom_kill_disable = parent->oom_kill_disable;
 	memcg->swappiness = mem_cgroup_swappiness(parent);
+#ifdef CONFIG_CLEANCACHE
+	memcg->cleancache_disabled = parent->cleancache_disabled;
+#endif
 
 	if (parent->use_hierarchy) {
 		res_counter_init(&memcg->res, &parent->res);



More information about the Devel mailing list