diff options
| -rw-r--r-- | fs/autofs4/expire.c | 13 | ||||
| -rw-r--r-- | fs/dcache.c | 1 | ||||
| -rw-r--r-- | fs/namespace.c | 29 | ||||
| -rw-r--r-- | include/linux/dcache.h | 42 |
4 files changed, 58 insertions, 27 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 2f7951d67d16..cc1d01365905 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
| @@ -295,7 +295,9 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
| 295 | struct autofs_info *ino = autofs4_dentry_ino(root); | 295 | struct autofs_info *ino = autofs4_dentry_ino(root); |
| 296 | if (d_mountpoint(root)) { | 296 | if (d_mountpoint(root)) { |
| 297 | ino->flags |= AUTOFS_INF_MOUNTPOINT; | 297 | ino->flags |= AUTOFS_INF_MOUNTPOINT; |
| 298 | root->d_mounted--; | 298 | spin_lock(&root->d_lock); |
| 299 | root->d_flags &= ~DCACHE_MOUNTED; | ||
| 300 | spin_unlock(&root->d_lock); | ||
| 299 | } | 301 | } |
| 300 | ino->flags |= AUTOFS_INF_EXPIRING; | 302 | ino->flags |= AUTOFS_INF_EXPIRING; |
| 301 | init_completion(&ino->expire_complete); | 303 | init_completion(&ino->expire_complete); |
| @@ -503,7 +505,14 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
| 503 | 505 | ||
| 504 | spin_lock(&sbi->fs_lock); | 506 | spin_lock(&sbi->fs_lock); |
| 505 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | 507 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { |
| 506 | sb->s_root->d_mounted++; | 508 | spin_lock(&sb->s_root->d_lock); |
| 509 | /* | ||
| 510 | * If we haven't been expired away, then reset | ||
| 511 | * mounted status. | ||
| 512 | */ | ||
| 513 | if (mnt->mnt_parent != mnt) | ||
| 514 | sb->s_root->d_flags |= DCACHE_MOUNTED; | ||
| 515 | spin_unlock(&sb->s_root->d_lock); | ||
| 507 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | 516 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; |
| 508 | } | 517 | } |
| 509 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 518 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
diff --git a/fs/dcache.c b/fs/dcache.c index 187fea040108..1d5cf511e1c7 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -1265,7 +1265,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
| 1265 | dentry->d_sb = NULL; | 1265 | dentry->d_sb = NULL; |
| 1266 | dentry->d_op = NULL; | 1266 | dentry->d_op = NULL; |
| 1267 | dentry->d_fsdata = NULL; | 1267 | dentry->d_fsdata = NULL; |
| 1268 | dentry->d_mounted = 0; | ||
| 1269 | INIT_HLIST_NODE(&dentry->d_hash); | 1268 | INIT_HLIST_NODE(&dentry->d_hash); |
| 1270 | INIT_LIST_HEAD(&dentry->d_lru); | 1269 | INIT_LIST_HEAD(&dentry->d_lru); |
| 1271 | INIT_LIST_HEAD(&dentry->d_subdirs); | 1270 | INIT_LIST_HEAD(&dentry->d_subdirs); |
diff --git a/fs/namespace.c b/fs/namespace.c index 3dbfc072ec70..39a7d507fba0 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 | */ | ||
| 498 | static 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 | */ |
| 497 | static void detach_mnt(struct vfsmount *mnt, struct path *old_path) | 518 | static 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 | } |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c2e7390289cc..e4414693065e 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
| @@ -92,7 +92,6 @@ struct dentry { | |||
| 92 | unsigned int d_flags; /* protected by d_lock */ | 92 | unsigned int d_flags; /* protected by d_lock */ |
| 93 | spinlock_t d_lock; /* per dentry lock */ | 93 | spinlock_t d_lock; /* per dentry lock */ |
| 94 | seqcount_t d_seq; /* per dentry seqlock */ | 94 | seqcount_t d_seq; /* per dentry seqlock */ |
| 95 | int d_mounted; | ||
| 96 | struct inode *d_inode; /* Where the name belongs to - NULL is | 95 | struct inode *d_inode; /* Where the name belongs to - NULL is |
| 97 | * negative */ | 96 | * negative */ |
| 98 | /* | 97 | /* |
| @@ -156,33 +155,34 @@ struct dentry_operations { | |||
| 156 | 155 | ||
| 157 | /* d_flags entries */ | 156 | /* d_flags entries */ |
| 158 | #define DCACHE_AUTOFS_PENDING 0x0001 /* autofs: "under construction" */ | 157 | #define DCACHE_AUTOFS_PENDING 0x0001 /* autofs: "under construction" */ |
| 159 | #define DCACHE_NFSFS_RENAMED 0x0002 /* this dentry has been "silly | 158 | #define DCACHE_NFSFS_RENAMED 0x0002 |
| 160 | * renamed" and has to be | 159 | /* this dentry has been "silly renamed" and has to be deleted on the last |
| 161 | * deleted on the last dput() | 160 | * dput() */ |
| 162 | */ | 161 | |
| 163 | #define DCACHE_DISCONNECTED 0x0004 | 162 | #define DCACHE_DISCONNECTED 0x0004 |
| 164 | /* This dentry is possibly not currently connected to the dcache tree, | 163 | /* This dentry is possibly not currently connected to the dcache tree, in |
| 165 | * in which case its parent will either be itself, or will have this | 164 | * which case its parent will either be itself, or will have this flag as |
| 166 | * flag as well. nfsd will not use a dentry with this bit set, but will | 165 | * well. nfsd will not use a dentry with this bit set, but will first |
| 167 | * first endeavour to clear the bit either by discovering that it is | 166 | * endeavour to clear the bit either by discovering that it is connected, |
| 168 | * connected, or by performing lookup operations. Any filesystem which | 167 | * or by performing lookup operations. Any filesystem which supports |
| 169 | * supports nfsd_operations MUST have a lookup function which, if it finds | 168 | * nfsd_operations MUST have a lookup function which, if it finds a |
| 170 | * a directory inode with a DCACHE_DISCONNECTED dentry, will d_move | 169 | * directory inode with a DCACHE_DISCONNECTED dentry, will d_move that |
| 171 | * that dentry into place and return that dentry rather than the passed one, | 170 | * dentry into place and return that dentry rather than the passed one, |
| 172 | * typically using d_splice_alias. | 171 | * typically using d_splice_alias. */ |
| 173 | */ | ||
| 174 | 172 | ||
| 175 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ | 173 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ |
| 176 | #define DCACHE_UNHASHED 0x0010 | 174 | #define DCACHE_UNHASHED 0x0010 |
| 177 | 175 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 | |
| 178 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched by inotify */ | 176 | /* Parent inode is watched by inotify */ |
| 179 | 177 | ||
| 180 | #define DCACHE_COOKIE 0x0040 /* For use by dcookie subsystem */ | 178 | #define DCACHE_COOKIE 0x0040 /* For use by dcookie subsystem */ |
| 181 | 179 | #define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 | |
| 182 | #define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 /* Parent inode is watched by some fsnotify listener */ | 180 | /* Parent inode is watched by some fsnotify listener */ |
| 183 | 181 | ||
| 184 | #define DCACHE_CANT_MOUNT 0x0100 | 182 | #define DCACHE_CANT_MOUNT 0x0100 |
| 185 | #define DCACHE_GENOCIDE 0x0200 | 183 | #define DCACHE_GENOCIDE 0x0200 |
| 184 | #define DCACHE_MOUNTED 0x0400 /* is a mountpoint */ | ||
| 185 | |||
| 186 | 186 | ||
| 187 | extern spinlock_t dcache_inode_lock; | 187 | extern spinlock_t dcache_inode_lock; |
| 188 | extern seqlock_t rename_lock; | 188 | extern seqlock_t rename_lock; |
| @@ -372,7 +372,7 @@ extern void dput(struct dentry *); | |||
| 372 | 372 | ||
| 373 | static inline int d_mountpoint(struct dentry *dentry) | 373 | static inline int d_mountpoint(struct dentry *dentry) |
| 374 | { | 374 | { |
| 375 | return dentry->d_mounted; | 375 | return dentry->d_flags & DCACHE_MOUNTED; |
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | extern struct vfsmount *lookup_mnt(struct path *); | 378 | extern struct vfsmount *lookup_mnt(struct path *); |
