diff options
author | NeilBrown <neilb@suse.de> | 2014-10-13 18:52:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 20:18:16 -0400 |
commit | ef16cc5909c907586f4eba5455e183fd319637c8 (patch) | |
tree | 8c85bca785379b19f215b210a89717e7cd51c4c8 /fs/autofs4 | |
parent | 4d885f90e3784df77945101d8ec32dc798a49862 (diff) |
autofs4: d_manage() should return -EISDIR when appropriate in rcu-walk mode.
If rcu-walk mode we don't *have* to return -EISDIR for non-mount-traps
as we will simply drop into REF-walk and handling DCACHE_NEED_AUTOMOUNT
dentrys the slow way. But it is better if we do when possible.
In 'oz_mode', use the same condition as ref-walk: if not a mountpoint,
then it must be -EISDIR.
In regular mode there are most tests needed. Most of them can be
performed without taking any spinlocks. If we find a directory that
isn't obviously empty, and isn't mounted on, we need to call
'simple_empty()' which does take a spinlock. If this turned out to hurt
performance, some other approach could be found to signal when a
directory is known to be empty.
Signed-off-by: NeilBrown <neilb@suse.de>
Reviewed-by: Ian Kent <raven@themaw.net>
Tested-by: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/root.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 2296c8301b66..d76d083f2f06 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -433,8 +433,6 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) | |||
433 | 433 | ||
434 | /* The daemon never waits. */ | 434 | /* The daemon never waits. */ |
435 | if (autofs4_oz_mode(sbi)) { | 435 | if (autofs4_oz_mode(sbi)) { |
436 | if (rcu_walk) | ||
437 | return 0; | ||
438 | if (!d_mountpoint(dentry)) | 436 | if (!d_mountpoint(dentry)) |
439 | return -EISDIR; | 437 | return -EISDIR; |
440 | return 0; | 438 | return 0; |
@@ -452,12 +450,28 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) | |||
452 | if (status) | 450 | if (status) |
453 | return status; | 451 | return status; |
454 | 452 | ||
455 | if (rcu_walk) | 453 | if (rcu_walk) { |
456 | /* it is always safe to return 0 as the worst that | 454 | /* We don't need fs_lock in rcu_walk mode, |
457 | * will happen is we retry in REF-walk mode. | 455 | * just testing 'AUTOFS_INFO_NO_RCU' is enough. |
458 | * Better than always taking a lock. | 456 | * simple_empty() takes a spinlock, so leave it |
457 | * to last. | ||
458 | * We only return -EISDIR when certain this isn't | ||
459 | * a mount-trap. | ||
459 | */ | 460 | */ |
461 | struct inode *inode; | ||
462 | if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)) | ||
463 | return 0; | ||
464 | if (d_mountpoint(dentry)) | ||
465 | return 0; | ||
466 | inode = ACCESS_ONCE(dentry->d_inode); | ||
467 | if (inode && S_ISLNK(inode->i_mode)) | ||
468 | return -EISDIR; | ||
469 | if (list_empty(&dentry->d_subdirs)) | ||
470 | return 0; | ||
471 | if (!simple_empty(dentry)) | ||
472 | return -EISDIR; | ||
460 | return 0; | 473 | return 0; |
474 | } | ||
461 | 475 | ||
462 | spin_lock(&sbi->fs_lock); | 476 | spin_lock(&sbi->fs_lock); |
463 | /* | 477 | /* |