aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index a88948b8bd17..10ba92def3f6 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -36,6 +36,7 @@
36#include <linux/bit_spinlock.h> 36#include <linux/bit_spinlock.h>
37#include <linux/rculist_bl.h> 37#include <linux/rculist_bl.h>
38#include <linux/prefetch.h> 38#include <linux/prefetch.h>
39#include <linux/ratelimit.h>
39#include "internal.h" 40#include "internal.h"
40 41
41/* 42/*
@@ -225,7 +226,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
225} 226}
226 227
227/* 228/*
228 * dentry_lru_(add|del|move_tail) must be called with d_lock held. 229 * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
229 */ 230 */
230static void dentry_lru_add(struct dentry *dentry) 231static void dentry_lru_add(struct dentry *dentry)
231{ 232{
@@ -245,6 +246,9 @@ static void __dentry_lru_del(struct dentry *dentry)
245 dentry_stat.nr_unused--; 246 dentry_stat.nr_unused--;
246} 247}
247 248
249/*
250 * Remove a dentry with references from the LRU.
251 */
248static void dentry_lru_del(struct dentry *dentry) 252static void dentry_lru_del(struct dentry *dentry)
249{ 253{
250 if (!list_empty(&dentry->d_lru)) { 254 if (!list_empty(&dentry->d_lru)) {
@@ -254,6 +258,23 @@ static void dentry_lru_del(struct dentry *dentry)
254 } 258 }
255} 259}
256 260
261/*
262 * Remove a dentry that is unreferenced and about to be pruned
263 * (unhashed and destroyed) from the LRU, and inform the file system.
264 * This wrapper should be called _prior_ to unhashing a victim dentry.
265 */
266static void dentry_lru_prune(struct dentry *dentry)
267{
268 if (!list_empty(&dentry->d_lru)) {
269 if (dentry->d_flags & DCACHE_OP_PRUNE)
270 dentry->d_op->d_prune(dentry);
271
272 spin_lock(&dcache_lru_lock);
273 __dentry_lru_del(dentry);
274 spin_unlock(&dcache_lru_lock);
275 }
276}
277
257static void dentry_lru_move_tail(struct dentry *dentry) 278static void dentry_lru_move_tail(struct dentry *dentry)
258{ 279{
259 spin_lock(&dcache_lru_lock); 280 spin_lock(&dcache_lru_lock);
@@ -403,8 +424,12 @@ relock:
403 424
404 if (ref) 425 if (ref)
405 dentry->d_count--; 426 dentry->d_count--;
406 /* if dentry was on the d_lru list delete it from there */ 427 /*
407 dentry_lru_del(dentry); 428 * if dentry was on the d_lru list delete it from there.
429 * inform the fs via d_prune that this dentry is about to be
430 * unhashed and destroyed.
431 */
432 dentry_lru_prune(dentry);
408 /* if it was on the hash then remove it */ 433 /* if it was on the hash then remove it */
409 __d_drop(dentry); 434 __d_drop(dentry);
410 return d_kill(dentry, parent); 435 return d_kill(dentry, parent);
@@ -522,9 +547,11 @@ int d_invalidate(struct dentry * dentry)
522 * would make it unreachable from the root, 547 * would make it unreachable from the root,
523 * we might still populate it if it was a 548 * we might still populate it if it was a
524 * working directory or similar). 549 * working directory or similar).
550 * We also need to leave mountpoints alone,
551 * directory or not.
525 */ 552 */
526 if (dentry->d_count > 1) { 553 if (dentry->d_count > 1 && dentry->d_inode) {
527 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 554 if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
528 spin_unlock(&dentry->d_lock); 555 spin_unlock(&dentry->d_lock);
529 return -EBUSY; 556 return -EBUSY;
530 } 557 }
@@ -854,8 +881,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
854 do { 881 do {
855 struct inode *inode; 882 struct inode *inode;
856 883
857 /* detach from the system */ 884 /*
858 dentry_lru_del(dentry); 885 * remove the dentry from the lru, and inform
886 * the fs that this dentry is about to be
887 * unhashed and destroyed.
888 */
889 dentry_lru_prune(dentry);
859 __d_shrink(dentry); 890 __d_shrink(dentry);
860 891
861 if (dentry->d_count != 0) { 892 if (dentry->d_count != 0) {
@@ -1283,6 +1314,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
1283 dentry->d_flags |= DCACHE_OP_REVALIDATE; 1314 dentry->d_flags |= DCACHE_OP_REVALIDATE;
1284 if (op->d_delete) 1315 if (op->d_delete)
1285 dentry->d_flags |= DCACHE_OP_DELETE; 1316 dentry->d_flags |= DCACHE_OP_DELETE;
1317 if (op->d_prune)
1318 dentry->d_flags |= DCACHE_OP_PRUNE;
1286 1319
1287} 1320}
1288EXPORT_SYMBOL(d_set_d_op); 1321EXPORT_SYMBOL(d_set_d_op);
@@ -2351,8 +2384,16 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
2351 actual = __d_unalias(inode, dentry, alias); 2384 actual = __d_unalias(inode, dentry, alias);
2352 } 2385 }
2353 write_sequnlock(&rename_lock); 2386 write_sequnlock(&rename_lock);
2354 if (IS_ERR(actual)) 2387 if (IS_ERR(actual)) {
2388 if (PTR_ERR(actual) == -ELOOP)
2389 pr_warn_ratelimited(
2390 "VFS: Lookup of '%s' in %s %s"
2391 " would have caused loop\n",
2392 dentry->d_name.name,
2393 inode->i_sb->s_type->name,
2394 inode->i_sb->s_id);
2355 dput(alias); 2395 dput(alias);
2396 }
2356 goto out_nolock; 2397 goto out_nolock;
2357 } 2398 }
2358 } 2399 }