aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c49
-rw-r--r--include/linux/list_lru.h17
-rw-r--r--mm/list_lru.c42
3 files changed, 29 insertions, 79 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 38a4a03499a2..d74b5bdff7f9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -956,27 +956,29 @@ long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan)
956 return freed; 956 return freed;
957} 957}
958 958
959/* 959static enum lru_status dentry_lru_isolate_shrink(struct list_head *item,
960 * Mark all the dentries as on being the dispose list so we don't think they are 960 spinlock_t *lru_lock, void *arg)
961 * still on the LRU if we try to kill them from ascending the parent chain in
962 * try_prune_one_dentry() rather than directly from the dispose list.
963 */
964static void
965shrink_dcache_list(
966 struct list_head *dispose)
967{ 961{
968 struct dentry *dentry; 962 struct list_head *freeable = arg;
963 struct dentry *dentry = container_of(item, struct dentry, d_lru);
969 964
970 rcu_read_lock(); 965 /*
971 list_for_each_entry_rcu(dentry, dispose, d_lru) { 966 * we are inverting the lru lock/dentry->d_lock here,
972 spin_lock(&dentry->d_lock); 967 * so use a trylock. If we fail to get the lock, just skip
973 dentry->d_flags |= DCACHE_SHRINK_LIST; 968 * it
974 spin_unlock(&dentry->d_lock); 969 */
975 } 970 if (!spin_trylock(&dentry->d_lock))
976 rcu_read_unlock(); 971 return LRU_SKIP;
977 shrink_dentry_list(dispose); 972
973 dentry->d_flags |= DCACHE_SHRINK_LIST;
974 list_move_tail(&dentry->d_lru, freeable);
975 this_cpu_dec(nr_dentry_unused);
976 spin_unlock(&dentry->d_lock);
977
978 return LRU_REMOVED;
978} 979}
979 980
981
980/** 982/**
981 * shrink_dcache_sb - shrink dcache for a superblock 983 * shrink_dcache_sb - shrink dcache for a superblock
982 * @sb: superblock 984 * @sb: superblock
@@ -986,10 +988,17 @@ shrink_dcache_list(
986 */ 988 */
987void shrink_dcache_sb(struct super_block *sb) 989void shrink_dcache_sb(struct super_block *sb)
988{ 990{
989 long disposed; 991 long freed;
992
993 do {
994 LIST_HEAD(dispose);
995
996 freed = list_lru_walk(&sb->s_dentry_lru,
997 dentry_lru_isolate_shrink, &dispose, UINT_MAX);
990 998
991 disposed = list_lru_dispose_all(&sb->s_dentry_lru, shrink_dcache_list); 999 this_cpu_sub(nr_dentry_unused, freed);
992 this_cpu_sub(nr_dentry_unused, disposed); 1000 shrink_dentry_list(&dispose);
1001 } while (freed > 0);
993} 1002}
994EXPORT_SYMBOL(shrink_dcache_sb); 1003EXPORT_SYMBOL(shrink_dcache_sb);
995 1004
diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h
index 2fe13e1a809a..4d02ad3badab 100644
--- a/include/linux/list_lru.h
+++ b/include/linux/list_lru.h
@@ -137,21 +137,4 @@ list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate,
137 } 137 }
138 return isolated; 138 return isolated;
139} 139}
140
141typedef void (*list_lru_dispose_cb)(struct list_head *dispose_list);
142/**
143 * list_lru_dispose_all: forceably flush all elements in an @lru
144 * @lru: the lru pointer
145 * @dispose: callback function to be called for each lru list.
146 *
147 * This function will forceably isolate all elements into the dispose list, and
148 * call the @dispose callback to flush the list. Please note that the callback
149 * should expect items in any state, clean or dirty, and be able to flush all of
150 * them.
151 *
152 * Return value: how many objects were freed. It should be equal to all objects
153 * in the list_lru.
154 */
155unsigned long
156list_lru_dispose_all(struct list_lru *lru, list_lru_dispose_cb dispose);
157#endif /* _LRU_LIST_H */ 140#endif /* _LRU_LIST_H */
diff --git a/mm/list_lru.c b/mm/list_lru.c
index 86cb55464f71..f91c24188573 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -112,48 +112,6 @@ restart:
112} 112}
113EXPORT_SYMBOL_GPL(list_lru_walk_node); 113EXPORT_SYMBOL_GPL(list_lru_walk_node);
114 114
115static unsigned long list_lru_dispose_all_node(struct list_lru *lru, int nid,
116 list_lru_dispose_cb dispose)
117{
118 struct list_lru_node *nlru = &lru->node[nid];
119 LIST_HEAD(dispose_list);
120 unsigned long disposed = 0;
121
122 spin_lock(&nlru->lock);
123 while (!list_empty(&nlru->list)) {
124 list_splice_init(&nlru->list, &dispose_list);
125 disposed += nlru->nr_items;
126 nlru->nr_items = 0;
127 node_clear(nid, lru->active_nodes);
128 spin_unlock(&nlru->lock);
129
130 dispose(&dispose_list);
131
132 spin_lock(&nlru->lock);
133 }
134 spin_unlock(&nlru->lock);
135 return disposed;
136}
137
138unsigned long list_lru_dispose_all(struct list_lru *lru,
139 list_lru_dispose_cb dispose)
140{
141 unsigned long disposed;
142 unsigned long total = 0;
143 int nid;
144
145 do {
146 disposed = 0;
147 for_each_node_mask(nid, lru->active_nodes) {
148 disposed += list_lru_dispose_all_node(lru, nid,
149 dispose);
150 }
151 total += disposed;
152 } while (disposed != 0);
153
154 return total;
155}
156
157int list_lru_init(struct list_lru *lru) 115int list_lru_init(struct list_lru *lru)
158{ 116{
159 int i; 117 int i;