aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stultz <johnstul@us.ibm.com>2010-04-29 02:31:49 -0400
committerThomas Gleixner <tglx@linutronix.de>2010-04-29 05:57:13 -0400
commit4329d1ae261df5ae61f8a4db7253fbe316efb590 (patch)
tree4558d10eb94d04defcde2225e440dc449d0dd531
parenta0a59617869efb2ec0e80c6cf11cfc90735600f6 (diff)
fs: Fix namespace related hangs
Nick converted the dentry->d_mounted counter to a flag, however with namespaces, dentries can be mounted multiple times (and more importantly unmounted multiple times). If a namespace was created and then released, the unmount_tree would remove the DCACHE_MOUNTED flag and that would make d_mountpoint fail, causing the mounts to be lost. This patch coverts it back to a counter, and adds some extra WARN_ONs to make sure things are accounted properly. Signed-off-by: John Stultz <johnstul@us.ibm.com> Cc: "Luis Claudio R. Goncalves" <lclaudio@uudg.org> Cc: Nick Piggin <npiggin@suse.de> LKML-Reference: <1272522942.1967.12.camel@work-vm> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--fs/autofs4/expire.c5
-rw-r--r--fs/dcache.c1
-rw-r--r--fs/libfs.c1
-rw-r--r--fs/namespace.c5
-rw-r--r--include/linux/dcache.h3
5 files changed, 10 insertions, 5 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index dc629eea0b91..60a7c6ce0a0d 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -296,7 +296,8 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
296 if (d_mountpoint(root)) { 296 if (d_mountpoint(root)) {
297 ino->flags |= AUTOFS_INF_MOUNTPOINT; 297 ino->flags |= AUTOFS_INF_MOUNTPOINT;
298 spin_lock(&root->d_lock); 298 spin_lock(&root->d_lock);
299 root->d_flags &= ~DCACHE_MOUNTED; 299 WARN_ON(root->d_mounted == 0);
300 root->d_mounted--;
300 spin_unlock(&root->d_lock); 301 spin_unlock(&root->d_lock);
301 } 302 }
302 ino->flags |= AUTOFS_INF_EXPIRING; 303 ino->flags |= AUTOFS_INF_EXPIRING;
@@ -536,7 +537,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
536 spin_lock(&sbi->fs_lock); 537 spin_lock(&sbi->fs_lock);
537 if (ino->flags & AUTOFS_INF_MOUNTPOINT) { 538 if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
538 spin_lock(&sb->s_root->d_lock); 539 spin_lock(&sb->s_root->d_lock);
539 sb->s_root->d_flags |= DCACHE_MOUNTED; 540 sb->s_root->d_mounted++;
540 spin_unlock(&sb->s_root->d_lock); 541 spin_unlock(&sb->s_root->d_lock);
541 ino->flags &= ~AUTOFS_INF_MOUNTPOINT; 542 ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
542 } 543 }
diff --git a/fs/dcache.c b/fs/dcache.c
index c2a4d2ebe0e4..89b9d1f14871 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1187,6 +1187,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
1187 dentry->d_sb = NULL; 1187 dentry->d_sb = NULL;
1188 dentry->d_op = NULL; 1188 dentry->d_op = NULL;
1189 dentry->d_fsdata = NULL; 1189 dentry->d_fsdata = NULL;
1190 dentry->d_mounted = 0;
1190 INIT_HLIST_NODE(&dentry->d_hash); 1191 INIT_HLIST_NODE(&dentry->d_hash);
1191 INIT_LIST_HEAD(&dentry->d_lru); 1192 INIT_LIST_HEAD(&dentry->d_lru);
1192 INIT_LIST_HEAD(&dentry->d_subdirs); 1193 INIT_LIST_HEAD(&dentry->d_subdirs);
diff --git a/fs/libfs.c b/fs/libfs.c
index 48fe7c883d27..98d2717e9027 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -265,6 +265,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name,
265 d_instantiate(dentry, root); 265 d_instantiate(dentry, root);
266 s->s_root = dentry; 266 s->s_root = dentry;
267 s->s_flags |= MS_ACTIVE; 267 s->s_flags |= MS_ACTIVE;
268 WARN_ON(mnt->mnt_flags & MNT_MOUNTED);
268 mnt->mnt_flags |= MNT_MOUNTED; 269 mnt->mnt_flags |= MNT_MOUNTED;
269 simple_set_mnt(mnt, s); 270 simple_set_mnt(mnt, s);
270 return 0; 271 return 0;
diff --git a/fs/namespace.c b/fs/namespace.c
index 6c115d86a157..64db957bb992 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -586,7 +586,8 @@ static void dentry_reset_mounted(struct vfsmount *mnt, struct dentry *dentry)
586{ 586{
587 if (!__lookup_mnt(mnt, dentry, 0)) { 587 if (!__lookup_mnt(mnt, dentry, 0)) {
588 spin_lock(&dentry->d_lock); 588 spin_lock(&dentry->d_lock);
589 dentry->d_flags &= ~DCACHE_MOUNTED; 589 WARN_ON(dentry->d_mounted == 0);
590 dentry->d_mounted--;
590 spin_unlock(&dentry->d_lock); 591 spin_unlock(&dentry->d_lock);
591 } 592 }
592} 593}
@@ -610,7 +611,7 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
610 child_mnt->mnt_parent = mntget(mnt); 611 child_mnt->mnt_parent = mntget(mnt);
611 spin_lock(&dentry->d_lock); 612 spin_lock(&dentry->d_lock);
612 child_mnt->mnt_mountpoint = dget_dlock(dentry); 613 child_mnt->mnt_mountpoint = dget_dlock(dentry);
613 dentry->d_flags |= DCACHE_MOUNTED; 614 dentry->d_mounted++;
614 spin_unlock(&dentry->d_lock); 615 spin_unlock(&dentry->d_lock);
615} 616}
616 617
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 39872ea86c6a..bc5a5ff141c8 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -99,6 +99,7 @@ struct dentry {
99 atomic_t d_count; 99 atomic_t d_count;
100 unsigned int d_flags; /* protected by d_lock */ 100 unsigned int d_flags; /* protected by d_lock */
101 spinlock_t d_lock; /* per dentry lock */ 101 spinlock_t d_lock; /* per dentry lock */
102 int d_mounted;
102 seqcount_t d_seq; /* per dentry seqlock */ 103 seqcount_t d_seq; /* per dentry seqlock */
103 struct inode *d_inode; /* Where the name belongs to - NULL is 104 struct inode *d_inode; /* Where the name belongs to - NULL is
104 * negative */ 105 * negative */
@@ -364,7 +365,7 @@ extern void dput(struct dentry *);
364 365
365static inline int d_mountpoint(struct dentry *dentry) 366static inline int d_mountpoint(struct dentry *dentry)
366{ 367{
367 return dentry->d_flags & DCACHE_MOUNTED; 368 return dentry->d_mounted;
368} 369}
369 370
370extern struct vfsmount *lookup_mnt(struct path *); 371extern struct vfsmount *lookup_mnt(struct path *);