diff options
-rw-r--r-- | fs/dcache.c | 49 | ||||
-rw-r--r-- | include/linux/list_lru.h | 17 | ||||
-rw-r--r-- | mm/list_lru.c | 42 |
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 | /* | 959 | static 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 | */ | ||
964 | static void | ||
965 | shrink_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 | */ |
987 | void shrink_dcache_sb(struct super_block *sb) | 989 | void 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 | } |
994 | EXPORT_SYMBOL(shrink_dcache_sb); | 1003 | EXPORT_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 | |||
141 | typedef 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 | */ | ||
155 | unsigned long | ||
156 | list_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 | } |
113 | EXPORT_SYMBOL_GPL(list_lru_walk_node); | 113 | EXPORT_SYMBOL_GPL(list_lru_walk_node); |
114 | 114 | ||
115 | static 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 | |||
138 | unsigned 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 | |||
157 | int list_lru_init(struct list_lru *lru) | 115 | int list_lru_init(struct list_lru *lru) |
158 | { | 116 | { |
159 | int i; | 117 | int i; |