diff options
| author | John Stultz <johnstul@us.ibm.com> | 2010-04-29 02:31:49 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2010-04-29 05:57:13 -0400 |
| commit | 4329d1ae261df5ae61f8a4db7253fbe316efb590 (patch) | |
| tree | 4558d10eb94d04defcde2225e440dc449d0dd531 | |
| parent | a0a59617869efb2ec0e80c6cf11cfc90735600f6 (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.c | 5 | ||||
| -rw-r--r-- | fs/dcache.c | 1 | ||||
| -rw-r--r-- | fs/libfs.c | 1 | ||||
| -rw-r--r-- | fs/namespace.c | 5 | ||||
| -rw-r--r-- | include/linux/dcache.h | 3 |
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 | ||
| 365 | static inline int d_mountpoint(struct dentry *dentry) | 366 | static 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 | ||
| 370 | extern struct vfsmount *lookup_mnt(struct path *); | 371 | extern struct vfsmount *lookup_mnt(struct path *); |
