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 *); |