@@ -633,6 +633,58 @@ static inline struct dentry *lock_parent(struct dentry *dentry)
}
/*
+ * Called at first dput of each negative dentry.
+ * Prevents filling cache with never reused negative dentries.
+ *
+ * This clears reference and then looks at following dentries in hash chain.
+ * If they are negative, unused and unreferenced then keep two and kill third.
+ */
+static void trim_negative(struct dentry *dentry)
+ __releases(dentry->d_lock)
+{
+ struct dentry *victim, *parent;
+ struct hlist_bl_node *next;
+ int keep = 2;
+
+ rcu_read_lock();
+
+ dentry->d_flags &= ~DCACHE_REFERENCED;
+ spin_unlock(&dentry->d_lock);
+
+ next = rcu_dereference_raw(dentry->d_hash.next);
+ while (1) {
+ victim = hlist_bl_entry(next, struct dentry, d_hash);
+
+ if (!next || d_count(victim) || !d_is_negative(victim) ||
+ (victim->d_flags & DCACHE_REFERENCED)) {
+ rcu_read_unlock();
+ return;
+ }
+
+ if (!keep--)
+ break;
+
+ next = rcu_dereference_raw(next->next);
+ }
+
+ spin_lock(&victim->d_lock);
+ parent = lock_parent(victim);
+
+ rcu_read_unlock();
+
+ if (d_count(victim) || !d_is_negative(victim) ||
+ (victim->d_flags & DCACHE_REFERENCED)) {
+ if (parent)
+ spin_unlock(&parent->d_lock);
+ spin_unlock(&victim->d_lock);
+ return;
+ }
+
+ __dentry_kill(victim);
+ dput(parent);
+}
+
+/*
* Move cached negative dentry to the tail of parent->d_subdirs.
* This lets walkers skip them all together at first sight.
* Must be called at dput of negative dentry.
@@ -654,6 +706,8 @@ static void sweep_negative(struct dentry *dentry)
}
spin_unlock(&parent->d_lock);
+
+ return trim_negative(dentry);
}
out:
spin_unlock(&dentry->d_lock);