[rh7] mm/tcache, tswap: Don't try to shrink if tswap/tcache disabled.

Submitted by Andrey Ryabinin on Oct. 29, 2018, 8:34 a.m.

Details

Message ID 20181029083442.9188-1-aryabinin@virtuozzo.com
State New
Series "mm/tcache, tswap: Don't try to shrink if tswap/tcache disabled."
Headers show

Commit Message

Andrey Ryabinin Oct. 29, 2018, 8:34 a.m.
shrink_tcrutches() calls tcache/tswap_shrink_scan() regardless of wether
tcache/tswap enabled or have any pages. If tcache was disabled at via
tcache.enabled=0 boot parameter, it will crash:

 BUG: unable to handle kernel NULL pointer dereference at 0000000000000010
 IP: [<ffffffffbe03794b>] tcache_lru_isolate+0x2b/0x1e0

 Call Trace:
  tcache_shrink_scan+0x46/0x130
  shrink_tcrutches+0xe8/0x150
  balance_pgdat+0x434/0x810
  kswapd+0x173/0x440
  kthread+0xd1/0xe0
  ret_from_fork_nospec_begin+0x21/0x21
 RIP  [<ffffffffbe03794b>] tcache_lru_isolate+0x2b/0x1e0

Fix this by calling tcache/tswap_shrink_scan() only if tcache/tswap
enabled and have anything to reclaim.

https://jira.sw.ru/browse/HCI-168
Fixes: fe87c15bf3ac ("mm/vmscan: shrink tcache, tswap upfront everything else")
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 mm/internal.h | 28 ++++++++++++++++++++++++++--
 mm/tcache.c   |  4 ++--
 mm/tswap.c    |  4 ++--
 3 files changed, 30 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/mm/internal.h b/mm/internal.h
index c7265beced97..b34b03dc37f2 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -387,10 +387,22 @@  struct tlbflush_unmap_batch;
 #ifdef CONFIG_TCACHE
 unsigned long tswap_shrink_scan(struct shrinker *shrinker,
 				struct shrink_control *sc);
+unsigned long tswap_shrink_count(struct shrinker *shrink,
+				struct shrink_control *sc);
 
 static inline unsigned long tswap_shrink(struct shrink_control *sc)
 {
-	unsigned long ret = tswap_shrink_scan(NULL, sc);
+	unsigned long ret;
+	extern bool tswap_enabled;
+
+	if (!READ_ONCE(tswap_enabled))
+		return 0;
+
+	ret = tswap_shrink_count(NULL, sc);
+	if (!ret)
+		return ret;
+
+	ret = tswap_shrink_scan(NULL, sc);
 	if (ret == SHRINK_STOP)
 		ret = 0;
 	return ret;
@@ -403,10 +415,22 @@  static inline tswap_shrink(struct shrink_control *sc)
 #ifdef CONFIG_TSWAP
 unsigned long tcache_shrink_scan(struct shrinker *shrinker,
 			struct shrink_control *sc);
+unsigned long tcache_shrink_count(struct shrinker *shrink,
+				struct shrink_control *sc);
 
 static inline unsigned long tcache_shrink(struct shrink_control *sc)
 {
-	unsigned long ret = tcache_shrink_scan(NULL, sc);
+	unsigned long ret;
+	extern bool tcache_enabled;
+
+	if (!READ_ONCE(tcache_enabled))
+		return 0;
+
+	ret = tcache_shrink_count(NULL, sc);
+	if (!ret)
+		return ret;
+
+	ret = tcache_shrink_scan(NULL, sc);
 	if (ret == SHRINK_STOP)
 		ret = 0;
 	return ret;
diff --git a/mm/tcache.c b/mm/tcache.c
index 61f4a6ea26b3..a6afb0c510aa 100644
--- a/mm/tcache.c
+++ b/mm/tcache.c
@@ -177,7 +177,7 @@  static struct tcache_nodeinfo *tcache_nodeinfo;
  */
 
 /* Enable/disable tcache backend (set at boot time) */
-static bool tcache_enabled __read_mostly = true;
+bool tcache_enabled __read_mostly = true;
 module_param_named(enabled, tcache_enabled, bool, 0444);
 
 /* Enable/disable populating the cache */
@@ -1196,7 +1196,7 @@  static struct page *tcache_alloc_page(struct tcache_pool *pool)
 	return page;
 }
 
-static unsigned long tcache_shrink_count(struct shrinker *shrink,
+unsigned long tcache_shrink_count(struct shrinker *shrink,
 					 struct shrink_control *sc)
 {
 	atomic_long_t *nr_pages = &tcache_nodeinfo[sc->nid].nr_pages;
diff --git a/mm/tswap.c b/mm/tswap.c
index 73b1f85d5279..bf7644d5f033 100644
--- a/mm/tswap.c
+++ b/mm/tswap.c
@@ -35,7 +35,7 @@  struct tswap_lru {
 static struct tswap_lru *tswap_lru_node;
 
 /* Enable/disable tswap backend (set at boot time) */
-static bool tswap_enabled __read_mostly = true;
+bool tswap_enabled __read_mostly = true;
 module_param_named(enabled, tswap_enabled, bool, 0444);
 
 /* Enable/disable populating the cache */
@@ -126,7 +126,7 @@  static struct page *tswap_delete_page(swp_entry_t entry, struct page *expected)
 	return page;
 }
 
-static unsigned long tswap_shrink_count(struct shrinker *shrink,
+unsigned long tswap_shrink_count(struct shrinker *shrink,
 					struct shrink_control *sc)
 {
 	return tswap_lru_node[sc->nid].nr_items;