summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/hwpoison-inject.c7
-rw-r--r--mm/internal.h1
-rw-r--r--mm/memory-failure.c46
3 files changed, 54 insertions, 0 deletions
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index c4dfd89f654a..c838735ac31d 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -112,6 +112,13 @@ static int pfn_inject_init(void)
if (!dentry)
goto fail;
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
+ dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
+ hwpoison_dir, &hwpoison_filter_memcg);
+ if (!dentry)
+ goto fail;
+#endif
+
return 0;
fail:
pfn_inject_exit();
diff --git a/mm/internal.h b/mm/internal.h
index b2027c73119b..5a6761bea6a6 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -257,3 +257,4 @@ extern u32 hwpoison_filter_dev_major;
extern u32 hwpoison_filter_dev_minor;
extern u64 hwpoison_filter_flags_mask;
extern u64 hwpoison_filter_flags_value;
+extern u64 hwpoison_filter_memcg;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 22d2b2028e54..117ef1598469 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -100,6 +100,49 @@ static int hwpoison_filter_flags(struct page *p)
return -EINVAL;
}
+/*
+ * This allows stress tests to limit test scope to a collection of tasks
+ * by putting them under some memcg. This prevents killing unrelated/important
+ * processes such as /sbin/init. Note that the target task may share clean
+ * pages with init (eg. libc text), which is harmless. If the target task
+ * share _dirty_ pages with another task B, the test scheme must make sure B
+ * is also included in the memcg. At last, due to race conditions this filter
+ * can only guarantee that the page either belongs to the memcg tasks, or is
+ * a freed page.
+ */
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
+u64 hwpoison_filter_memcg;
+EXPORT_SYMBOL_GPL(hwpoison_filter_memcg);
+static int hwpoison_filter_task(struct page *p)
+{
+ struct mem_cgroup *mem;
+ struct cgroup_subsys_state *css;
+ unsigned long ino;
+
+ if (!hwpoison_filter_memcg)
+ return 0;
+
+ mem = try_get_mem_cgroup_from_page(p);
+ if (!mem)
+ return -EINVAL;
+
+ css = mem_cgroup_css(mem);
+ /* root_mem_cgroup has NULL dentries */
+ if (!css->cgroup->dentry)
+ return -EINVAL;
+
+ ino = css->cgroup->dentry->d_inode->i_ino;
+ css_put(css);
+
+ if (ino != hwpoison_filter_memcg)
+ return -EINVAL;
+
+ return 0;
+}
+#else
+static int hwpoison_filter_task(struct page *p) { return 0; }
+#endif
+
int hwpoison_filter(struct page *p)
{
if (hwpoison_filter_dev(p))
@@ -108,6 +151,9 @@ int hwpoison_filter(struct page *p)
if (hwpoison_filter_flags(p))
return -EINVAL;
+ if (hwpoison_filter_task(p))
+ return -EINVAL;
+
return 0;
}
EXPORT_SYMBOL_GPL(hwpoison_filter);