154 lines
5.0 KiB
Diff
154 lines
5.0 KiB
Diff
From 0b365505a88bc36f42e6e8f9a93608b345267128 Mon Sep 17 00:00:00 2001
|
|
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
Date: Thu, 29 Jan 2015 17:19:44 +0100
|
|
Subject: [PATCH] mm/workingset: do not protect workingset_shadow_nodes with
|
|
irq off
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.0/patches-4.0.5-rt3.tar.xz
|
|
|
|
workingset_shadow_nodes is protected by local_irq_disable(). Some users
|
|
use spin_lock_irq().
|
|
Replace the irq/on with a local_lock(). Rename workingset_shadow_nodes
|
|
so I catch users of it which will be introduced later.
|
|
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
include/linux/swap.h | 4 +++-
|
|
mm/filemap.c | 11 ++++++++---
|
|
mm/truncate.c | 7 +++++--
|
|
mm/workingset.c | 23 ++++++++++++-----------
|
|
4 files changed, 28 insertions(+), 17 deletions(-)
|
|
|
|
--- a/include/linux/swap.h
|
|
+++ b/include/linux/swap.h
|
|
@@ -11,6 +11,7 @@
|
|
#include <linux/fs.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/page-flags.h>
|
|
+#include <linux/locallock.h>
|
|
#include <asm/page.h>
|
|
|
|
struct notifier_block;
|
|
@@ -252,7 +253,8 @@ struct swap_info_struct {
|
|
void *workingset_eviction(struct address_space *mapping, struct page *page);
|
|
bool workingset_refault(void *shadow);
|
|
void workingset_activation(struct page *page);
|
|
-extern struct list_lru workingset_shadow_nodes;
|
|
+extern struct list_lru __workingset_shadow_nodes;
|
|
+DECLARE_LOCAL_IRQ_LOCK(workingset_shadow_lock);
|
|
|
|
static inline unsigned int workingset_node_pages(struct radix_tree_node *node)
|
|
{
|
|
--- a/mm/filemap.c
|
|
+++ b/mm/filemap.c
|
|
@@ -168,7 +168,9 @@ static void page_cache_tree_delete(struc
|
|
if (!workingset_node_pages(node) &&
|
|
list_empty(&node->private_list)) {
|
|
node->private_data = mapping;
|
|
- list_lru_add(&workingset_shadow_nodes, &node->private_list);
|
|
+ local_lock(workingset_shadow_lock);
|
|
+ list_lru_add(&__workingset_shadow_nodes, &node->private_list);
|
|
+ local_unlock(workingset_shadow_lock);
|
|
}
|
|
}
|
|
|
|
@@ -535,9 +537,12 @@ static int page_cache_tree_insert(struct
|
|
* node->private_list is protected by
|
|
* mapping->tree_lock.
|
|
*/
|
|
- if (!list_empty(&node->private_list))
|
|
- list_lru_del(&workingset_shadow_nodes,
|
|
+ if (!list_empty(&node->private_list)) {
|
|
+ local_lock(workingset_shadow_lock);
|
|
+ list_lru_del(&__workingset_shadow_nodes,
|
|
&node->private_list);
|
|
+ local_unlock(workingset_shadow_lock);
|
|
+ }
|
|
}
|
|
return 0;
|
|
}
|
|
--- a/mm/truncate.c
|
|
+++ b/mm/truncate.c
|
|
@@ -56,8 +56,11 @@ static void clear_exceptional_entry(stru
|
|
* protected by mapping->tree_lock.
|
|
*/
|
|
if (!workingset_node_shadows(node) &&
|
|
- !list_empty(&node->private_list))
|
|
- list_lru_del(&workingset_shadow_nodes, &node->private_list);
|
|
+ !list_empty(&node->private_list)) {
|
|
+ local_lock(workingset_shadow_lock);
|
|
+ list_lru_del(&__workingset_shadow_nodes, &node->private_list);
|
|
+ local_unlock(workingset_shadow_lock);
|
|
+ }
|
|
__radix_tree_delete_node(&mapping->page_tree, node);
|
|
unlock:
|
|
spin_unlock_irq(&mapping->tree_lock);
|
|
--- a/mm/workingset.c
|
|
+++ b/mm/workingset.c
|
|
@@ -264,7 +264,8 @@ void workingset_activation(struct page *
|
|
* point where they would still be useful.
|
|
*/
|
|
|
|
-struct list_lru workingset_shadow_nodes;
|
|
+struct list_lru __workingset_shadow_nodes;
|
|
+DEFINE_LOCAL_IRQ_LOCK(workingset_shadow_lock);
|
|
|
|
static unsigned long count_shadow_nodes(struct shrinker *shrinker,
|
|
struct shrink_control *sc)
|
|
@@ -274,9 +275,9 @@ static unsigned long count_shadow_nodes(
|
|
unsigned long pages;
|
|
|
|
/* list_lru lock nests inside IRQ-safe mapping->tree_lock */
|
|
- local_irq_disable();
|
|
- shadow_nodes = list_lru_shrink_count(&workingset_shadow_nodes, sc);
|
|
- local_irq_enable();
|
|
+ local_lock_irq(workingset_shadow_lock);
|
|
+ shadow_nodes = list_lru_shrink_count(&__workingset_shadow_nodes, sc);
|
|
+ local_unlock_irq(workingset_shadow_lock);
|
|
|
|
pages = node_present_pages(sc->nid);
|
|
/*
|
|
@@ -363,9 +364,9 @@ static enum lru_status shadow_lru_isolat
|
|
spin_unlock(&mapping->tree_lock);
|
|
ret = LRU_REMOVED_RETRY;
|
|
out:
|
|
- local_irq_enable();
|
|
+ local_unlock_irq(workingset_shadow_lock);
|
|
cond_resched();
|
|
- local_irq_disable();
|
|
+ local_lock_irq(workingset_shadow_lock);
|
|
spin_lock(lru_lock);
|
|
return ret;
|
|
}
|
|
@@ -376,10 +377,10 @@ static unsigned long scan_shadow_nodes(s
|
|
unsigned long ret;
|
|
|
|
/* list_lru lock nests inside IRQ-safe mapping->tree_lock */
|
|
- local_irq_disable();
|
|
- ret = list_lru_shrink_walk(&workingset_shadow_nodes, sc,
|
|
+ local_lock_irq(workingset_shadow_lock);
|
|
+ ret = list_lru_shrink_walk(&__workingset_shadow_nodes, sc,
|
|
shadow_lru_isolate, NULL);
|
|
- local_irq_enable();
|
|
+ local_unlock_irq(workingset_shadow_lock);
|
|
return ret;
|
|
}
|
|
|
|
@@ -400,7 +401,7 @@ static int __init workingset_init(void)
|
|
{
|
|
int ret;
|
|
|
|
- ret = list_lru_init_key(&workingset_shadow_nodes, &shadow_nodes_key);
|
|
+ ret = list_lru_init_key(&__workingset_shadow_nodes, &shadow_nodes_key);
|
|
if (ret)
|
|
goto err;
|
|
ret = register_shrinker(&workingset_shadow_shrinker);
|
|
@@ -408,7 +409,7 @@ static int __init workingset_init(void)
|
|
goto err_list_lru;
|
|
return 0;
|
|
err_list_lru:
|
|
- list_lru_destroy(&workingset_shadow_nodes);
|
|
+ list_lru_destroy(&__workingset_shadow_nodes);
|
|
err:
|
|
return ret;
|
|
}
|