diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 57 |
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 | */ |
| 230 | static void dentry_lru_add(struct dentry *dentry) | 231 | static 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 | */ | ||
| 248 | static void dentry_lru_del(struct dentry *dentry) | 252 | static 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 | */ | ||
| 266 | static 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 | |||
| 257 | static void dentry_lru_move_tail(struct dentry *dentry) | 278 | static 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 | } |
| 1288 | EXPORT_SYMBOL(d_set_d_op); | 1321 | EXPORT_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 | } |
