aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:54 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:28 -0500
commit5f57cbcc02cf18f6b22ef4066bb10afeb8f930ff (patch)
treef02e7ee57e6060f0af1bcda281baf2972d2da72f /fs/namespace.c
parentc28cc36469554dc55540f059fbdc7fa22a2c31fc (diff)
fs: dcache remove d_mounted
Rather than keep a d_mounted count in the dentry, set a dentry flag instead. The flag can be cleared by checking the hash table to see if there are any mounts left, which is not time critical because it is performed at detach time. The mounted state of a dentry is only used to speculatively take a look in the mount hash table if it is set -- before following the mount, vfsmount lock is taken and mount re-checked without races. This saves 4 bytes on 32-bit, nothing on 64-bit but it does provide a hole I might use later (and some configs have larger than 32-bit spinlocks which might make use of the hole). Autofs4 conversion and changelog by Ian Kent <raven@themaw.net>: In autofs4, when expring direct (or offset) mounts we need to ensure that we block user path walks into the autofs mount, which is covered by another mount. To do this we clear the mounted status so that follows stop before walking into the mount and are essentially blocked until the expire is completed. The automount daemon still finds the correct dentry for the umount due to the follow mount logic in fs/autofs4/root.c:autofs4_follow_link(), which is set as an inode operation for direct and offset mounts only and is called following the lookup that stopped at the covered mount. At the end of the expire the covering mount probably has gone away so the mounted status need not be restored. But we need to check this and only restore the mounted status if the expire failed. XXX: autofs may not work right if we have other mounts go over the top of it? Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 3dbfc072ec7..39a7d507fba 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -492,6 +492,27 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns)
492} 492}
493 493
494/* 494/*
495 * Clear dentry's mounted state if it has no remaining mounts.
496 * vfsmount_lock must be held for write.
497 */
498static void dentry_reset_mounted(struct vfsmount *mnt, struct dentry *dentry)
499{
500 unsigned u;
501
502 for (u = 0; u < HASH_SIZE; u++) {
503 struct vfsmount *p;
504
505 list_for_each_entry(p, &mount_hashtable[u], mnt_hash) {
506 if (p->mnt_mountpoint == dentry)
507 return;
508 }
509 }
510 spin_lock(&dentry->d_lock);
511 dentry->d_flags &= ~DCACHE_MOUNTED;
512 spin_unlock(&dentry->d_lock);
513}
514
515/*
495 * vfsmount lock must be held for write 516 * vfsmount lock must be held for write
496 */ 517 */
497static void detach_mnt(struct vfsmount *mnt, struct path *old_path) 518static void detach_mnt(struct vfsmount *mnt, struct path *old_path)
@@ -502,7 +523,7 @@ static void detach_mnt(struct vfsmount *mnt, struct path *old_path)
502 mnt->mnt_mountpoint = mnt->mnt_root; 523 mnt->mnt_mountpoint = mnt->mnt_root;
503 list_del_init(&mnt->mnt_child); 524 list_del_init(&mnt->mnt_child);
504 list_del_init(&mnt->mnt_hash); 525 list_del_init(&mnt->mnt_hash);
505 old_path->dentry->d_mounted--; 526 dentry_reset_mounted(old_path->mnt, old_path->dentry);
506} 527}
507 528
508/* 529/*
@@ -513,7 +534,9 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
513{ 534{
514 child_mnt->mnt_parent = mntget(mnt); 535 child_mnt->mnt_parent = mntget(mnt);
515 child_mnt->mnt_mountpoint = dget(dentry); 536 child_mnt->mnt_mountpoint = dget(dentry);
516 dentry->d_mounted++; 537 spin_lock(&dentry->d_lock);
538 dentry->d_flags |= DCACHE_MOUNTED;
539 spin_unlock(&dentry->d_lock);
517} 540}
518 541
519/* 542/*
@@ -1073,7 +1096,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1073 list_del_init(&p->mnt_child); 1096 list_del_init(&p->mnt_child);
1074 if (p->mnt_parent != p) { 1097 if (p->mnt_parent != p) {
1075 p->mnt_parent->mnt_ghosts++; 1098 p->mnt_parent->mnt_ghosts++;
1076 p->mnt_mountpoint->d_mounted--; 1099 dentry_reset_mounted(p->mnt_parent, p->mnt_mountpoint);
1077 } 1100 }
1078 change_mnt_propagation(p, MS_PRIVATE); 1101 change_mnt_propagation(p, MS_PRIVATE);
1079 } 1102 }