|
@@ -956,27 +956,29 @@ long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan)
|
|
|
return freed;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Mark all the dentries as on being the dispose list so we don't think they are
|
|
|
- * still on the LRU if we try to kill them from ascending the parent chain in
|
|
|
- * try_prune_one_dentry() rather than directly from the dispose list.
|
|
|
- */
|
|
|
-static void
|
|
|
-shrink_dcache_list(
|
|
|
- struct list_head *dispose)
|
|
|
+static enum lru_status dentry_lru_isolate_shrink(struct list_head *item,
|
|
|
+ spinlock_t *lru_lock, void *arg)
|
|
|
{
|
|
|
- struct dentry *dentry;
|
|
|
+ struct list_head *freeable = arg;
|
|
|
+ struct dentry *dentry = container_of(item, struct dentry, d_lru);
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
- list_for_each_entry_rcu(dentry, dispose, d_lru) {
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
- dentry->d_flags |= DCACHE_SHRINK_LIST;
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
- }
|
|
|
- rcu_read_unlock();
|
|
|
- shrink_dentry_list(dispose);
|
|
|
+ /*
|
|
|
+ * we are inverting the lru lock/dentry->d_lock here,
|
|
|
+ * so use a trylock. If we fail to get the lock, just skip
|
|
|
+ * it
|
|
|
+ */
|
|
|
+ if (!spin_trylock(&dentry->d_lock))
|
|
|
+ return LRU_SKIP;
|
|
|
+
|
|
|
+ dentry->d_flags |= DCACHE_SHRINK_LIST;
|
|
|
+ list_move_tail(&dentry->d_lru, freeable);
|
|
|
+ this_cpu_dec(nr_dentry_unused);
|
|
|
+ spin_unlock(&dentry->d_lock);
|
|
|
+
|
|
|
+ return LRU_REMOVED;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* shrink_dcache_sb - shrink dcache for a superblock
|
|
|
* @sb: superblock
|
|
@@ -986,10 +988,17 @@ shrink_dcache_list(
|
|
|
*/
|
|
|
void shrink_dcache_sb(struct super_block *sb)
|
|
|
{
|
|
|
- long disposed;
|
|
|
+ long freed;
|
|
|
+
|
|
|
+ do {
|
|
|
+ LIST_HEAD(dispose);
|
|
|
+
|
|
|
+ freed = list_lru_walk(&sb->s_dentry_lru,
|
|
|
+ dentry_lru_isolate_shrink, &dispose, UINT_MAX);
|
|
|
|
|
|
- disposed = list_lru_dispose_all(&sb->s_dentry_lru, shrink_dcache_list);
|
|
|
- this_cpu_sub(nr_dentry_unused, disposed);
|
|
|
+ this_cpu_sub(nr_dentry_unused, freed);
|
|
|
+ shrink_dentry_list(&dispose);
|
|
|
+ } while (freed > 0);
|
|
|
}
|
|
|
EXPORT_SYMBOL(shrink_dcache_sb);
|
|
|
|