diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-16 14:31:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-16 14:31:50 -0500 |
commit | f8206b925fb0eba3a11839419be118b09105d7b1 (patch) | |
tree | 5d41b356a043da09c816ed80bd79d1ea8b2b47e5 | |
parent | 1b59be2a6cdcb5a12e18d8315c07c94a624de48f (diff) | |
parent | f03c65993b98eeb909a4012ce7833c5857d74755 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (23 commits)
sanitize vfsmount refcounting changes
fix old umount_tree() breakage
autofs4: Merge the remaining dentry ops tables
Unexport do_add_mount() and add in follow_automount(), not ->d_automount()
Allow d_manage() to be used in RCU-walk mode
Remove a further kludge from __do_follow_link()
autofs4: Bump version
autofs4: Add v4 pseudo direct mount support
autofs4: Fix wait validation
autofs4: Clean up autofs4_free_ino()
autofs4: Clean up dentry operations
autofs4: Clean up inode operations
autofs4: Remove unused code
autofs4: Add d_manage() dentry operation
autofs4: Add d_automount() dentry operation
Remove the automount through follow_link() kludge code from pathwalk
CIFS: Use d_automount() rather than abusing follow_link()
NFS: Use d_automount() rather than abusing follow_link()
AFS: Use d_automount() rather than abusing follow_link()
Add an AT_NO_AUTOMOUNT flag to suppress terminal automount
...
40 files changed, 1009 insertions, 854 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index ef9349a4b5d1..651d5237c155 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -19,6 +19,8 @@ prototypes: | |||
19 | void (*d_release)(struct dentry *); | 19 | void (*d_release)(struct dentry *); |
20 | void (*d_iput)(struct dentry *, struct inode *); | 20 | void (*d_iput)(struct dentry *, struct inode *); |
21 | char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); | 21 | char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); |
22 | struct vfsmount *(*d_automount)(struct path *path); | ||
23 | int (*d_manage)(struct dentry *, bool); | ||
22 | 24 | ||
23 | locking rules: | 25 | locking rules: |
24 | rename_lock ->d_lock may block rcu-walk | 26 | rename_lock ->d_lock may block rcu-walk |
@@ -29,6 +31,8 @@ d_delete: no yes no no | |||
29 | d_release: no no yes no | 31 | d_release: no no yes no |
30 | d_iput: no no yes no | 32 | d_iput: no no yes no |
31 | d_dname: no no no no | 33 | d_dname: no no no no |
34 | d_automount: no no yes no | ||
35 | d_manage: no no yes (ref-walk) maybe | ||
32 | 36 | ||
33 | --------------------------- inode_operations --------------------------- | 37 | --------------------------- inode_operations --------------------------- |
34 | prototypes: | 38 | prototypes: |
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index cae6d27c9f5b..94cf97b901d7 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -864,6 +864,8 @@ struct dentry_operations { | |||
864 | void (*d_release)(struct dentry *); | 864 | void (*d_release)(struct dentry *); |
865 | void (*d_iput)(struct dentry *, struct inode *); | 865 | void (*d_iput)(struct dentry *, struct inode *); |
866 | char *(*d_dname)(struct dentry *, char *, int); | 866 | char *(*d_dname)(struct dentry *, char *, int); |
867 | struct vfsmount *(*d_automount)(struct path *); | ||
868 | int (*d_manage)(struct dentry *, bool, bool); | ||
867 | }; | 869 | }; |
868 | 870 | ||
869 | d_revalidate: called when the VFS needs to revalidate a dentry. This | 871 | d_revalidate: called when the VFS needs to revalidate a dentry. This |
@@ -930,6 +932,47 @@ struct dentry_operations { | |||
930 | at the end of the buffer, and returns a pointer to the first char. | 932 | at the end of the buffer, and returns a pointer to the first char. |
931 | dynamic_dname() helper function is provided to take care of this. | 933 | dynamic_dname() helper function is provided to take care of this. |
932 | 934 | ||
935 | d_automount: called when an automount dentry is to be traversed (optional). | ||
936 | This should create a new VFS mount record and return the record to the | ||
937 | caller. The caller is supplied with a path parameter giving the | ||
938 | automount directory to describe the automount target and the parent | ||
939 | VFS mount record to provide inheritable mount parameters. NULL should | ||
940 | be returned if someone else managed to make the automount first. If | ||
941 | the vfsmount creation failed, then an error code should be returned. | ||
942 | If -EISDIR is returned, then the directory will be treated as an | ||
943 | ordinary directory and returned to pathwalk to continue walking. | ||
944 | |||
945 | If a vfsmount is returned, the caller will attempt to mount it on the | ||
946 | mountpoint and will remove the vfsmount from its expiration list in | ||
947 | the case of failure. The vfsmount should be returned with 2 refs on | ||
948 | it to prevent automatic expiration - the caller will clean up the | ||
949 | additional ref. | ||
950 | |||
951 | This function is only used if DCACHE_NEED_AUTOMOUNT is set on the | ||
952 | dentry. This is set by __d_instantiate() if S_AUTOMOUNT is set on the | ||
953 | inode being added. | ||
954 | |||
955 | d_manage: called to allow the filesystem to manage the transition from a | ||
956 | dentry (optional). This allows autofs, for example, to hold up clients | ||
957 | waiting to explore behind a 'mountpoint' whilst letting the daemon go | ||
958 | past and construct the subtree there. 0 should be returned to let the | ||
959 | calling process continue. -EISDIR can be returned to tell pathwalk to | ||
960 | use this directory as an ordinary directory and to ignore anything | ||
961 | mounted on it and not to check the automount flag. Any other error | ||
962 | code will abort pathwalk completely. | ||
963 | |||
964 | If the 'mounting_here' parameter is true, then namespace_sem is being | ||
965 | held by the caller and the function should not initiate any mounts or | ||
966 | unmounts that it will then wait for. | ||
967 | |||
968 | If the 'rcu_walk' parameter is true, then the caller is doing a | ||
969 | pathwalk in RCU-walk mode. Sleeping is not permitted in this mode, | ||
970 | and the caller can be asked to leave it and call again by returing | ||
971 | -ECHILD. | ||
972 | |||
973 | This function is only used if DCACHE_MANAGE_TRANSIT is set on the | ||
974 | dentry being transited from. | ||
975 | |||
933 | Example : | 976 | Example : |
934 | 977 | ||
935 | static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen) | 978 | static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen) |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index ee4bb3330bdf..98240575a18d 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -1201,7 +1201,7 @@ err_unregister_chdev: | |||
1201 | static void __exit cleanup_mtdchar(void) | 1201 | static void __exit cleanup_mtdchar(void) |
1202 | { | 1202 | { |
1203 | unregister_mtd_user(&mtdchar_notifier); | 1203 | unregister_mtd_user(&mtdchar_notifier); |
1204 | mntput_long(mtd_inode_mnt); | 1204 | mntput(mtd_inode_mnt); |
1205 | unregister_filesystem(&mtd_inodefs_type); | 1205 | unregister_filesystem(&mtd_inodefs_type); |
1206 | __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); | 1206 | __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); |
1207 | } | 1207 | } |
diff --git a/drivers/staging/autofs/dirhash.c b/drivers/staging/autofs/dirhash.c index d3f42c8325f7..a08bd7355035 100644 --- a/drivers/staging/autofs/dirhash.c +++ b/drivers/staging/autofs/dirhash.c | |||
@@ -88,14 +88,13 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, | |||
88 | } | 88 | } |
89 | path.mnt = mnt; | 89 | path.mnt = mnt; |
90 | path_get(&path); | 90 | path_get(&path); |
91 | if (!follow_down(&path)) { | 91 | if (!follow_down_one(&path)) { |
92 | path_put(&path); | 92 | path_put(&path); |
93 | DPRINTK(("autofs: not expirable\ | 93 | DPRINTK(("autofs: not expirable\ |
94 | (not a mounted directory): %s\n", ent->name)); | 94 | (not a mounted directory): %s\n", ent->name)); |
95 | continue; | 95 | continue; |
96 | } | 96 | } |
97 | while (d_mountpoint(path.dentry) && follow_down(&path)) | 97 | follow_down(&path, false); // TODO: need to check error |
98 | ; | ||
99 | umount_ok = may_umount(path.mnt); | 98 | umount_ok = may_umount(path.mnt); |
100 | path_put(&path); | 99 | path_put(&path); |
101 | 100 | ||
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index e6a4ab980e31..20c106f24927 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -66,6 +66,7 @@ const struct dentry_operations afs_fs_dentry_operations = { | |||
66 | .d_revalidate = afs_d_revalidate, | 66 | .d_revalidate = afs_d_revalidate, |
67 | .d_delete = afs_d_delete, | 67 | .d_delete = afs_d_delete, |
68 | .d_release = afs_d_release, | 68 | .d_release = afs_d_release, |
69 | .d_automount = afs_d_automount, | ||
69 | }; | 70 | }; |
70 | 71 | ||
71 | #define AFS_DIR_HASHTBL_SIZE 128 | 72 | #define AFS_DIR_HASHTBL_SIZE 128 |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 0747339011c3..db66c5201474 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -184,7 +184,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name, | |||
184 | inode->i_generation = 0; | 184 | inode->i_generation = 0; |
185 | 185 | ||
186 | set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); | 186 | set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); |
187 | inode->i_flags |= S_NOATIME; | 187 | set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); |
188 | inode->i_flags |= S_AUTOMOUNT | S_NOATIME; | ||
188 | unlock_new_inode(inode); | 189 | unlock_new_inode(inode); |
189 | _leave(" = %p", inode); | 190 | _leave(" = %p", inode); |
190 | return inode; | 191 | return inode; |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 58c633b80246..5a9b6843bac1 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -592,6 +592,7 @@ extern const struct inode_operations afs_mntpt_inode_operations; | |||
592 | extern const struct inode_operations afs_autocell_inode_operations; | 592 | extern const struct inode_operations afs_autocell_inode_operations; |
593 | extern const struct file_operations afs_mntpt_file_operations; | 593 | extern const struct file_operations afs_mntpt_file_operations; |
594 | 594 | ||
595 | extern struct vfsmount *afs_d_automount(struct path *); | ||
595 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); | 596 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
596 | extern void afs_mntpt_kill_timer(void); | 597 | extern void afs_mntpt_kill_timer(void); |
597 | 598 | ||
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index e83c0336e7b5..aa59184151d0 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -24,7 +24,6 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, | |||
24 | struct dentry *dentry, | 24 | struct dentry *dentry, |
25 | struct nameidata *nd); | 25 | struct nameidata *nd); |
26 | static int afs_mntpt_open(struct inode *inode, struct file *file); | 26 | static int afs_mntpt_open(struct inode *inode, struct file *file); |
27 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); | ||
28 | static void afs_mntpt_expiry_timed_out(struct work_struct *work); | 27 | static void afs_mntpt_expiry_timed_out(struct work_struct *work); |
29 | 28 | ||
30 | const struct file_operations afs_mntpt_file_operations = { | 29 | const struct file_operations afs_mntpt_file_operations = { |
@@ -34,13 +33,11 @@ const struct file_operations afs_mntpt_file_operations = { | |||
34 | 33 | ||
35 | const struct inode_operations afs_mntpt_inode_operations = { | 34 | const struct inode_operations afs_mntpt_inode_operations = { |
36 | .lookup = afs_mntpt_lookup, | 35 | .lookup = afs_mntpt_lookup, |
37 | .follow_link = afs_mntpt_follow_link, | ||
38 | .readlink = page_readlink, | 36 | .readlink = page_readlink, |
39 | .getattr = afs_getattr, | 37 | .getattr = afs_getattr, |
40 | }; | 38 | }; |
41 | 39 | ||
42 | const struct inode_operations afs_autocell_inode_operations = { | 40 | const struct inode_operations afs_autocell_inode_operations = { |
43 | .follow_link = afs_mntpt_follow_link, | ||
44 | .getattr = afs_getattr, | 41 | .getattr = afs_getattr, |
45 | }; | 42 | }; |
46 | 43 | ||
@@ -88,6 +85,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) | |||
88 | _debug("symlink is a mountpoint"); | 85 | _debug("symlink is a mountpoint"); |
89 | spin_lock(&vnode->lock); | 86 | spin_lock(&vnode->lock); |
90 | set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); | 87 | set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); |
88 | vnode->vfs_inode.i_flags |= S_AUTOMOUNT; | ||
91 | spin_unlock(&vnode->lock); | 89 | spin_unlock(&vnode->lock); |
92 | } | 90 | } |
93 | 91 | ||
@@ -238,52 +236,24 @@ error_no_devname: | |||
238 | } | 236 | } |
239 | 237 | ||
240 | /* | 238 | /* |
241 | * follow a link from a mountpoint directory, thus causing it to be mounted | 239 | * handle an automount point |
242 | */ | 240 | */ |
243 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | 241 | struct vfsmount *afs_d_automount(struct path *path) |
244 | { | 242 | { |
245 | struct vfsmount *newmnt; | 243 | struct vfsmount *newmnt; |
246 | int err; | ||
247 | 244 | ||
248 | _enter("%p{%s},{%s:%p{%s},}", | 245 | _enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name); |
249 | dentry, | ||
250 | dentry->d_name.name, | ||
251 | nd->path.mnt->mnt_devname, | ||
252 | dentry, | ||
253 | nd->path.dentry->d_name.name); | ||
254 | |||
255 | dput(nd->path.dentry); | ||
256 | nd->path.dentry = dget(dentry); | ||
257 | |||
258 | newmnt = afs_mntpt_do_automount(nd->path.dentry); | ||
259 | if (IS_ERR(newmnt)) { | ||
260 | path_put(&nd->path); | ||
261 | return (void *)newmnt; | ||
262 | } | ||
263 | 246 | ||
264 | mntget(newmnt); | 247 | newmnt = afs_mntpt_do_automount(path->dentry); |
265 | err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts); | 248 | if (IS_ERR(newmnt)) |
266 | switch (err) { | 249 | return newmnt; |
267 | case 0: | ||
268 | path_put(&nd->path); | ||
269 | nd->path.mnt = newmnt; | ||
270 | nd->path.dentry = dget(newmnt->mnt_root); | ||
271 | queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, | ||
272 | afs_mntpt_expiry_timeout * HZ); | ||
273 | break; | ||
274 | case -EBUSY: | ||
275 | /* someone else made a mount here whilst we were busy */ | ||
276 | while (d_mountpoint(nd->path.dentry) && | ||
277 | follow_down(&nd->path)) | ||
278 | ; | ||
279 | err = 0; | ||
280 | default: | ||
281 | mntput(newmnt); | ||
282 | break; | ||
283 | } | ||
284 | 250 | ||
285 | _leave(" = %d", err); | 251 | mntget(newmnt); /* prevent immediate expiration */ |
286 | return ERR_PTR(err); | 252 | mnt_set_expiry(newmnt, &afs_vfsmounts); |
253 | queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, | ||
254 | afs_mntpt_expiry_timeout * HZ); | ||
255 | _leave(" = %p {%s}", newmnt, newmnt->mnt_devname); | ||
256 | return newmnt; | ||
287 | } | 257 | } |
288 | 258 | ||
289 | /* | 259 | /* |
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index cbe57f3c4d89..c5567cb78432 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -233,7 +233,7 @@ static int __init anon_inode_init(void) | |||
233 | return 0; | 233 | return 0; |
234 | 234 | ||
235 | err_mntput: | 235 | err_mntput: |
236 | mntput_long(anon_inode_mnt); | 236 | mntput(anon_inode_mnt); |
237 | err_unregister_filesystem: | 237 | err_unregister_filesystem: |
238 | unregister_filesystem(&anon_inode_fs_type); | 238 | unregister_filesystem(&anon_inode_fs_type); |
239 | err_exit: | 239 | err_exit: |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 0fffe1c24cec..1f016bfb42d5 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -99,7 +99,6 @@ struct autofs_info { | |||
99 | }; | 99 | }; |
100 | 100 | ||
101 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ | 101 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ |
102 | #define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ | ||
103 | #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ | 102 | #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ |
104 | 103 | ||
105 | struct autofs_wait_queue { | 104 | struct autofs_wait_queue { |
@@ -176,13 +175,6 @@ static inline int autofs4_ispending(struct dentry *dentry) | |||
176 | return 0; | 175 | return 0; |
177 | } | 176 | } |
178 | 177 | ||
179 | static inline void autofs4_copy_atime(struct file *src, struct file *dst) | ||
180 | { | ||
181 | dst->f_path.dentry->d_inode->i_atime = | ||
182 | src->f_path.dentry->d_inode->i_atime; | ||
183 | return; | ||
184 | } | ||
185 | |||
186 | struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *); | 178 | struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *); |
187 | void autofs4_free_ino(struct autofs_info *); | 179 | void autofs4_free_ino(struct autofs_info *); |
188 | 180 | ||
@@ -212,11 +204,83 @@ void autofs_dev_ioctl_exit(void); | |||
212 | 204 | ||
213 | extern const struct inode_operations autofs4_symlink_inode_operations; | 205 | extern const struct inode_operations autofs4_symlink_inode_operations; |
214 | extern const struct inode_operations autofs4_dir_inode_operations; | 206 | extern const struct inode_operations autofs4_dir_inode_operations; |
215 | extern const struct inode_operations autofs4_root_inode_operations; | ||
216 | extern const struct inode_operations autofs4_indirect_root_inode_operations; | ||
217 | extern const struct inode_operations autofs4_direct_root_inode_operations; | ||
218 | extern const struct file_operations autofs4_dir_operations; | 207 | extern const struct file_operations autofs4_dir_operations; |
219 | extern const struct file_operations autofs4_root_operations; | 208 | extern const struct file_operations autofs4_root_operations; |
209 | extern const struct dentry_operations autofs4_dentry_operations; | ||
210 | |||
211 | /* VFS automount flags management functions */ | ||
212 | |||
213 | static inline void __managed_dentry_set_automount(struct dentry *dentry) | ||
214 | { | ||
215 | dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; | ||
216 | } | ||
217 | |||
218 | static inline void managed_dentry_set_automount(struct dentry *dentry) | ||
219 | { | ||
220 | spin_lock(&dentry->d_lock); | ||
221 | __managed_dentry_set_automount(dentry); | ||
222 | spin_unlock(&dentry->d_lock); | ||
223 | } | ||
224 | |||
225 | static inline void __managed_dentry_clear_automount(struct dentry *dentry) | ||
226 | { | ||
227 | dentry->d_flags &= ~DCACHE_NEED_AUTOMOUNT; | ||
228 | } | ||
229 | |||
230 | static inline void managed_dentry_clear_automount(struct dentry *dentry) | ||
231 | { | ||
232 | spin_lock(&dentry->d_lock); | ||
233 | __managed_dentry_clear_automount(dentry); | ||
234 | spin_unlock(&dentry->d_lock); | ||
235 | } | ||
236 | |||
237 | static inline void __managed_dentry_set_transit(struct dentry *dentry) | ||
238 | { | ||
239 | dentry->d_flags |= DCACHE_MANAGE_TRANSIT; | ||
240 | } | ||
241 | |||
242 | static inline void managed_dentry_set_transit(struct dentry *dentry) | ||
243 | { | ||
244 | spin_lock(&dentry->d_lock); | ||
245 | __managed_dentry_set_transit(dentry); | ||
246 | spin_unlock(&dentry->d_lock); | ||
247 | } | ||
248 | |||
249 | static inline void __managed_dentry_clear_transit(struct dentry *dentry) | ||
250 | { | ||
251 | dentry->d_flags &= ~DCACHE_MANAGE_TRANSIT; | ||
252 | } | ||
253 | |||
254 | static inline void managed_dentry_clear_transit(struct dentry *dentry) | ||
255 | { | ||
256 | spin_lock(&dentry->d_lock); | ||
257 | __managed_dentry_clear_transit(dentry); | ||
258 | spin_unlock(&dentry->d_lock); | ||
259 | } | ||
260 | |||
261 | static inline void __managed_dentry_set_managed(struct dentry *dentry) | ||
262 | { | ||
263 | dentry->d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT); | ||
264 | } | ||
265 | |||
266 | static inline void managed_dentry_set_managed(struct dentry *dentry) | ||
267 | { | ||
268 | spin_lock(&dentry->d_lock); | ||
269 | __managed_dentry_set_managed(dentry); | ||
270 | spin_unlock(&dentry->d_lock); | ||
271 | } | ||
272 | |||
273 | static inline void __managed_dentry_clear_managed(struct dentry *dentry) | ||
274 | { | ||
275 | dentry->d_flags &= ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT); | ||
276 | } | ||
277 | |||
278 | static inline void managed_dentry_clear_managed(struct dentry *dentry) | ||
279 | { | ||
280 | spin_lock(&dentry->d_lock); | ||
281 | __managed_dentry_clear_managed(dentry); | ||
282 | spin_unlock(&dentry->d_lock); | ||
283 | } | ||
220 | 284 | ||
221 | /* Initializing function */ | 285 | /* Initializing function */ |
222 | 286 | ||
@@ -229,19 +293,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); | |||
229 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); | 293 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); |
230 | void autofs4_catatonic_mode(struct autofs_sb_info *); | 294 | void autofs4_catatonic_mode(struct autofs_sb_info *); |
231 | 295 | ||
232 | static inline int autofs4_follow_mount(struct path *path) | ||
233 | { | ||
234 | int res = 0; | ||
235 | |||
236 | while (d_mountpoint(path->dentry)) { | ||
237 | int followed = follow_down(path); | ||
238 | if (!followed) | ||
239 | break; | ||
240 | res = 1; | ||
241 | } | ||
242 | return res; | ||
243 | } | ||
244 | |||
245 | static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) | 296 | static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) |
246 | { | 297 | { |
247 | return new_encode_dev(sbi->sb->s_dev); | 298 | return new_encode_dev(sbi->sb->s_dev); |
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index eff9a419469a..1442da4860e5 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c | |||
@@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, | |||
551 | 551 | ||
552 | err = have_submounts(path.dentry); | 552 | err = have_submounts(path.dentry); |
553 | 553 | ||
554 | if (follow_down(&path)) | 554 | if (follow_down_one(&path)) |
555 | magic = path.mnt->mnt_sb->s_magic; | 555 | magic = path.mnt->mnt_sb->s_magic; |
556 | } | 556 | } |
557 | 557 | ||
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index cc1d01365905..3ed79d76c233 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry, | |||
26 | if (ino == NULL) | 26 | if (ino == NULL) |
27 | return 0; | 27 | return 0; |
28 | 28 | ||
29 | /* No point expiring a pending mount */ | ||
30 | if (ino->flags & AUTOFS_INF_PENDING) | ||
31 | return 0; | ||
32 | |||
33 | if (!do_now) { | 29 | if (!do_now) { |
34 | /* Too young to die */ | 30 | /* Too young to die */ |
35 | if (!timeout || time_after(ino->last_used + timeout, now)) | 31 | if (!timeout || time_after(ino->last_used + timeout, now)) |
@@ -56,7 +52,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
56 | 52 | ||
57 | path_get(&path); | 53 | path_get(&path); |
58 | 54 | ||
59 | if (!follow_down(&path)) | 55 | if (!follow_down_one(&path)) |
60 | goto done; | 56 | goto done; |
61 | 57 | ||
62 | if (is_autofs4_dentry(path.dentry)) { | 58 | if (is_autofs4_dentry(path.dentry)) { |
@@ -283,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
283 | unsigned long timeout; | 279 | unsigned long timeout; |
284 | struct dentry *root = dget(sb->s_root); | 280 | struct dentry *root = dget(sb->s_root); |
285 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 281 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
282 | struct autofs_info *ino; | ||
286 | 283 | ||
287 | if (!root) | 284 | if (!root) |
288 | return NULL; | 285 | return NULL; |
@@ -291,19 +288,21 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
291 | timeout = sbi->exp_timeout; | 288 | timeout = sbi->exp_timeout; |
292 | 289 | ||
293 | spin_lock(&sbi->fs_lock); | 290 | spin_lock(&sbi->fs_lock); |
291 | ino = autofs4_dentry_ino(root); | ||
292 | /* No point expiring a pending mount */ | ||
293 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
294 | spin_unlock(&sbi->fs_lock); | ||
295 | return NULL; | ||
296 | } | ||
297 | managed_dentry_set_transit(root); | ||
294 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 298 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
295 | struct autofs_info *ino = autofs4_dentry_ino(root); | 299 | struct autofs_info *ino = autofs4_dentry_ino(root); |
296 | if (d_mountpoint(root)) { | ||
297 | ino->flags |= AUTOFS_INF_MOUNTPOINT; | ||
298 | spin_lock(&root->d_lock); | ||
299 | root->d_flags &= ~DCACHE_MOUNTED; | ||
300 | spin_unlock(&root->d_lock); | ||
301 | } | ||
302 | ino->flags |= AUTOFS_INF_EXPIRING; | 300 | ino->flags |= AUTOFS_INF_EXPIRING; |
303 | init_completion(&ino->expire_complete); | 301 | init_completion(&ino->expire_complete); |
304 | spin_unlock(&sbi->fs_lock); | 302 | spin_unlock(&sbi->fs_lock); |
305 | return root; | 303 | return root; |
306 | } | 304 | } |
305 | managed_dentry_clear_transit(root); | ||
307 | spin_unlock(&sbi->fs_lock); | 306 | spin_unlock(&sbi->fs_lock); |
308 | dput(root); | 307 | dput(root); |
309 | 308 | ||
@@ -340,6 +339,10 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
340 | while ((dentry = get_next_positive_dentry(dentry, root))) { | 339 | while ((dentry = get_next_positive_dentry(dentry, root))) { |
341 | spin_lock(&sbi->fs_lock); | 340 | spin_lock(&sbi->fs_lock); |
342 | ino = autofs4_dentry_ino(dentry); | 341 | ino = autofs4_dentry_ino(dentry); |
342 | /* No point expiring a pending mount */ | ||
343 | if (ino->flags & AUTOFS_INF_PENDING) | ||
344 | goto cont; | ||
345 | managed_dentry_set_transit(dentry); | ||
343 | 346 | ||
344 | /* | 347 | /* |
345 | * Case 1: (i) indirect mount or top level pseudo direct mount | 348 | * Case 1: (i) indirect mount or top level pseudo direct mount |
@@ -399,6 +402,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
399 | } | 402 | } |
400 | } | 403 | } |
401 | next: | 404 | next: |
405 | managed_dentry_clear_transit(dentry); | ||
406 | cont: | ||
402 | spin_unlock(&sbi->fs_lock); | 407 | spin_unlock(&sbi->fs_lock); |
403 | } | 408 | } |
404 | return NULL; | 409 | return NULL; |
@@ -479,6 +484,8 @@ int autofs4_expire_run(struct super_block *sb, | |||
479 | spin_lock(&sbi->fs_lock); | 484 | spin_lock(&sbi->fs_lock); |
480 | ino = autofs4_dentry_ino(dentry); | 485 | ino = autofs4_dentry_ino(dentry); |
481 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 486 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
487 | if (!d_unhashed(dentry)) | ||
488 | managed_dentry_clear_transit(dentry); | ||
482 | complete_all(&ino->expire_complete); | 489 | complete_all(&ino->expire_complete); |
483 | spin_unlock(&sbi->fs_lock); | 490 | spin_unlock(&sbi->fs_lock); |
484 | 491 | ||
@@ -504,18 +511,18 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
504 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); | 511 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); |
505 | 512 | ||
506 | spin_lock(&sbi->fs_lock); | 513 | spin_lock(&sbi->fs_lock); |
507 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | ||
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); | ||
516 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | ||
517 | } | ||
518 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 514 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
515 | spin_lock(&dentry->d_lock); | ||
516 | if (ret) | ||
517 | __managed_dentry_clear_transit(dentry); | ||
518 | else { | ||
519 | if ((IS_ROOT(dentry) || | ||
520 | (autofs_type_indirect(sbi->type) && | ||
521 | IS_ROOT(dentry->d_parent))) && | ||
522 | !(dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | ||
523 | __managed_dentry_set_automount(dentry); | ||
524 | } | ||
525 | spin_unlock(&dentry->d_lock); | ||
519 | complete_all(&ino->expire_complete); | 526 | complete_all(&ino->expire_complete); |
520 | spin_unlock(&sbi->fs_lock); | 527 | spin_unlock(&sbi->fs_lock); |
521 | dput(dentry); | 528 | dput(dentry); |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index a7bdb9dcac84..9e1a9dad23e1 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -45,7 +45,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
45 | 45 | ||
46 | if (!reinit) { | 46 | if (!reinit) { |
47 | ino->flags = 0; | 47 | ino->flags = 0; |
48 | ino->inode = NULL; | ||
49 | ino->dentry = NULL; | 48 | ino->dentry = NULL; |
50 | ino->size = 0; | 49 | ino->size = 0; |
51 | INIT_LIST_HEAD(&ino->active); | 50 | INIT_LIST_HEAD(&ino->active); |
@@ -76,19 +75,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
76 | 75 | ||
77 | void autofs4_free_ino(struct autofs_info *ino) | 76 | void autofs4_free_ino(struct autofs_info *ino) |
78 | { | 77 | { |
79 | struct autofs_info *p_ino; | ||
80 | |||
81 | if (ino->dentry) { | 78 | if (ino->dentry) { |
82 | ino->dentry->d_fsdata = NULL; | 79 | ino->dentry->d_fsdata = NULL; |
83 | if (ino->dentry->d_inode) { | ||
84 | struct dentry *parent = ino->dentry->d_parent; | ||
85 | if (atomic_dec_and_test(&ino->count)) { | ||
86 | p_ino = autofs4_dentry_ino(parent); | ||
87 | if (p_ino && parent != ino->dentry) | ||
88 | atomic_dec(&p_ino->count); | ||
89 | } | ||
90 | dput(ino->dentry); | ||
91 | } | ||
92 | ino->dentry = NULL; | 80 | ino->dentry = NULL; |
93 | } | 81 | } |
94 | if (ino->free) | 82 | if (ino->free) |
@@ -251,10 +239,6 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) | |||
251 | return ino; | 239 | return ino; |
252 | } | 240 | } |
253 | 241 | ||
254 | static const struct dentry_operations autofs4_sb_dentry_operations = { | ||
255 | .d_release = autofs4_dentry_release, | ||
256 | }; | ||
257 | |||
258 | int autofs4_fill_super(struct super_block *s, void *data, int silent) | 242 | int autofs4_fill_super(struct super_block *s, void *data, int silent) |
259 | { | 243 | { |
260 | struct inode * root_inode; | 244 | struct inode * root_inode; |
@@ -292,6 +276,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
292 | s->s_blocksize_bits = 10; | 276 | s->s_blocksize_bits = 10; |
293 | s->s_magic = AUTOFS_SUPER_MAGIC; | 277 | s->s_magic = AUTOFS_SUPER_MAGIC; |
294 | s->s_op = &autofs4_sops; | 278 | s->s_op = &autofs4_sops; |
279 | s->s_d_op = &autofs4_dentry_operations; | ||
295 | s->s_time_gran = 1; | 280 | s->s_time_gran = 1; |
296 | 281 | ||
297 | /* | 282 | /* |
@@ -309,7 +294,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
309 | goto fail_iput; | 294 | goto fail_iput; |
310 | pipe = NULL; | 295 | pipe = NULL; |
311 | 296 | ||
312 | d_set_d_op(root, &autofs4_sb_dentry_operations); | ||
313 | root->d_fsdata = ino; | 297 | root->d_fsdata = ino; |
314 | 298 | ||
315 | /* Can this call block? */ | 299 | /* Can this call block? */ |
@@ -320,10 +304,11 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
320 | goto fail_dput; | 304 | goto fail_dput; |
321 | } | 305 | } |
322 | 306 | ||
307 | if (autofs_type_trigger(sbi->type)) | ||
308 | __managed_dentry_set_managed(root); | ||
309 | |||
323 | root_inode->i_fop = &autofs4_root_operations; | 310 | root_inode->i_fop = &autofs4_root_operations; |
324 | root_inode->i_op = autofs_type_trigger(sbi->type) ? | 311 | root_inode->i_op = &autofs4_dir_inode_operations; |
325 | &autofs4_direct_root_inode_operations : | ||
326 | &autofs4_indirect_root_inode_operations; | ||
327 | 312 | ||
328 | /* Couldn't this be tested earlier? */ | 313 | /* Couldn't this be tested earlier? */ |
329 | if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION || | 314 | if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION || |
@@ -391,7 +376,6 @@ struct inode *autofs4_get_inode(struct super_block *sb, | |||
391 | if (inode == NULL) | 376 | if (inode == NULL) |
392 | return NULL; | 377 | return NULL; |
393 | 378 | ||
394 | inf->inode = inode; | ||
395 | inode->i_mode = inf->mode; | 379 | inode->i_mode = inf->mode; |
396 | if (sb->s_root) { | 380 | if (sb->s_root) { |
397 | inode->i_uid = sb->s_root->d_inode->i_uid; | 381 | inode->i_uid = sb->s_root->d_inode->i_uid; |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 651e4ef563b1..1dba035fc376 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -35,10 +35,8 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long); | |||
35 | #endif | 35 | #endif |
36 | static int autofs4_dir_open(struct inode *inode, struct file *file); | 36 | static int autofs4_dir_open(struct inode *inode, struct file *file); |
37 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 37 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
38 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); | 38 | static struct vfsmount *autofs4_d_automount(struct path *); |
39 | 39 | static int autofs4_d_manage(struct dentry *, bool, bool); | |
40 | #define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) | ||
41 | #define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE) | ||
42 | 40 | ||
43 | const struct file_operations autofs4_root_operations = { | 41 | const struct file_operations autofs4_root_operations = { |
44 | .open = dcache_dir_open, | 42 | .open = dcache_dir_open, |
@@ -60,7 +58,7 @@ const struct file_operations autofs4_dir_operations = { | |||
60 | .llseek = dcache_dir_lseek, | 58 | .llseek = dcache_dir_lseek, |
61 | }; | 59 | }; |
62 | 60 | ||
63 | const struct inode_operations autofs4_indirect_root_inode_operations = { | 61 | const struct inode_operations autofs4_dir_inode_operations = { |
64 | .lookup = autofs4_lookup, | 62 | .lookup = autofs4_lookup, |
65 | .unlink = autofs4_dir_unlink, | 63 | .unlink = autofs4_dir_unlink, |
66 | .symlink = autofs4_dir_symlink, | 64 | .symlink = autofs4_dir_symlink, |
@@ -68,20 +66,10 @@ const struct inode_operations autofs4_indirect_root_inode_operations = { | |||
68 | .rmdir = autofs4_dir_rmdir, | 66 | .rmdir = autofs4_dir_rmdir, |
69 | }; | 67 | }; |
70 | 68 | ||
71 | const struct inode_operations autofs4_direct_root_inode_operations = { | 69 | const struct dentry_operations autofs4_dentry_operations = { |
72 | .lookup = autofs4_lookup, | 70 | .d_automount = autofs4_d_automount, |
73 | .unlink = autofs4_dir_unlink, | 71 | .d_manage = autofs4_d_manage, |
74 | .mkdir = autofs4_dir_mkdir, | 72 | .d_release = autofs4_dentry_release, |
75 | .rmdir = autofs4_dir_rmdir, | ||
76 | .follow_link = autofs4_follow_link, | ||
77 | }; | ||
78 | |||
79 | const struct inode_operations autofs4_dir_inode_operations = { | ||
80 | .lookup = autofs4_lookup, | ||
81 | .unlink = autofs4_dir_unlink, | ||
82 | .symlink = autofs4_dir_symlink, | ||
83 | .mkdir = autofs4_dir_mkdir, | ||
84 | .rmdir = autofs4_dir_rmdir, | ||
85 | }; | 73 | }; |
86 | 74 | ||
87 | static void autofs4_add_active(struct dentry *dentry) | 75 | static void autofs4_add_active(struct dentry *dentry) |
@@ -116,14 +104,6 @@ static void autofs4_del_active(struct dentry *dentry) | |||
116 | return; | 104 | return; |
117 | } | 105 | } |
118 | 106 | ||
119 | static unsigned int autofs4_need_mount(unsigned int flags) | ||
120 | { | ||
121 | unsigned int res = 0; | ||
122 | if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS)) | ||
123 | res = 1; | ||
124 | return res; | ||
125 | } | ||
126 | |||
127 | static int autofs4_dir_open(struct inode *inode, struct file *file) | 107 | static int autofs4_dir_open(struct inode *inode, struct file *file) |
128 | { | 108 | { |
129 | struct dentry *dentry = file->f_path.dentry; | 109 | struct dentry *dentry = file->f_path.dentry; |
@@ -158,239 +138,6 @@ out: | |||
158 | return dcache_dir_open(inode, file); | 138 | return dcache_dir_open(inode, file); |
159 | } | 139 | } |
160 | 140 | ||
161 | static int try_to_fill_dentry(struct dentry *dentry, int flags) | ||
162 | { | ||
163 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
164 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
165 | int status; | ||
166 | |||
167 | DPRINTK("dentry=%p %.*s ino=%p", | ||
168 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | ||
169 | |||
170 | /* | ||
171 | * Wait for a pending mount, triggering one if there | ||
172 | * isn't one already | ||
173 | */ | ||
174 | if (dentry->d_inode == NULL) { | ||
175 | DPRINTK("waiting for mount name=%.*s", | ||
176 | dentry->d_name.len, dentry->d_name.name); | ||
177 | |||
178 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | ||
179 | |||
180 | DPRINTK("mount done status=%d", status); | ||
181 | |||
182 | /* Turn this into a real negative dentry? */ | ||
183 | if (status == -ENOENT) { | ||
184 | spin_lock(&sbi->fs_lock); | ||
185 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
186 | spin_unlock(&sbi->fs_lock); | ||
187 | return status; | ||
188 | } else if (status) { | ||
189 | /* Return a negative dentry, but leave it "pending" */ | ||
190 | return status; | ||
191 | } | ||
192 | /* Trigger mount for path component or follow link */ | ||
193 | } else if (ino->flags & AUTOFS_INF_PENDING || | ||
194 | autofs4_need_mount(flags)) { | ||
195 | DPRINTK("waiting for mount name=%.*s", | ||
196 | dentry->d_name.len, dentry->d_name.name); | ||
197 | |||
198 | spin_lock(&sbi->fs_lock); | ||
199 | ino->flags |= AUTOFS_INF_PENDING; | ||
200 | spin_unlock(&sbi->fs_lock); | ||
201 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | ||
202 | |||
203 | DPRINTK("mount done status=%d", status); | ||
204 | |||
205 | if (status) { | ||
206 | spin_lock(&sbi->fs_lock); | ||
207 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
208 | spin_unlock(&sbi->fs_lock); | ||
209 | return status; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /* Initialize expiry counter after successful mount */ | ||
214 | ino->last_used = jiffies; | ||
215 | |||
216 | spin_lock(&sbi->fs_lock); | ||
217 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
218 | spin_unlock(&sbi->fs_lock); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /* For autofs direct mounts the follow link triggers the mount */ | ||
224 | static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
225 | { | ||
226 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
227 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
228 | int oz_mode = autofs4_oz_mode(sbi); | ||
229 | unsigned int lookup_type; | ||
230 | int status; | ||
231 | |||
232 | DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d", | ||
233 | dentry, dentry->d_name.len, dentry->d_name.name, oz_mode, | ||
234 | nd->flags); | ||
235 | /* | ||
236 | * For an expire of a covered direct or offset mount we need | ||
237 | * to break out of follow_down() at the autofs mount trigger | ||
238 | * (d_mounted--), so we can see the expiring flag, and manage | ||
239 | * the blocking and following here until the expire is completed. | ||
240 | */ | ||
241 | if (oz_mode) { | ||
242 | spin_lock(&sbi->fs_lock); | ||
243 | if (ino->flags & AUTOFS_INF_EXPIRING) { | ||
244 | spin_unlock(&sbi->fs_lock); | ||
245 | /* Follow down to our covering mount. */ | ||
246 | if (!follow_down(&nd->path)) | ||
247 | goto done; | ||
248 | goto follow; | ||
249 | } | ||
250 | spin_unlock(&sbi->fs_lock); | ||
251 | goto done; | ||
252 | } | ||
253 | |||
254 | /* If an expire request is pending everyone must wait. */ | ||
255 | autofs4_expire_wait(dentry); | ||
256 | |||
257 | /* We trigger a mount for almost all flags */ | ||
258 | lookup_type = autofs4_need_mount(nd->flags); | ||
259 | spin_lock(&sbi->fs_lock); | ||
260 | spin_lock(&autofs4_lock); | ||
261 | spin_lock(&dentry->d_lock); | ||
262 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | ||
263 | spin_unlock(&dentry->d_lock); | ||
264 | spin_unlock(&autofs4_lock); | ||
265 | spin_unlock(&sbi->fs_lock); | ||
266 | goto follow; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * If the dentry contains directories then it is an autofs | ||
271 | * multi-mount with no root mount offset. So don't try to | ||
272 | * mount it again. | ||
273 | */ | ||
274 | if (ino->flags & AUTOFS_INF_PENDING || | ||
275 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { | ||
276 | spin_unlock(&dentry->d_lock); | ||
277 | spin_unlock(&autofs4_lock); | ||
278 | spin_unlock(&sbi->fs_lock); | ||
279 | |||
280 | status = try_to_fill_dentry(dentry, nd->flags); | ||
281 | if (status) | ||
282 | goto out_error; | ||
283 | |||
284 | goto follow; | ||
285 | } | ||
286 | spin_unlock(&dentry->d_lock); | ||
287 | spin_unlock(&autofs4_lock); | ||
288 | spin_unlock(&sbi->fs_lock); | ||
289 | follow: | ||
290 | /* | ||
291 | * If there is no root mount it must be an autofs | ||
292 | * multi-mount with no root offset so we don't need | ||
293 | * to follow it. | ||
294 | */ | ||
295 | if (d_mountpoint(dentry)) { | ||
296 | if (!autofs4_follow_mount(&nd->path)) { | ||
297 | status = -ENOENT; | ||
298 | goto out_error; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | done: | ||
303 | return NULL; | ||
304 | |||
305 | out_error: | ||
306 | path_put(&nd->path); | ||
307 | return ERR_PTR(status); | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * Revalidate is called on every cache lookup. Some of those | ||
312 | * cache lookups may actually happen while the dentry is not | ||
313 | * yet completely filled in, and revalidate has to delay such | ||
314 | * lookups.. | ||
315 | */ | ||
316 | static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
317 | { | ||
318 | struct inode *dir; | ||
319 | struct autofs_sb_info *sbi; | ||
320 | int oz_mode; | ||
321 | int flags = nd ? nd->flags : 0; | ||
322 | int status = 1; | ||
323 | |||
324 | if (flags & LOOKUP_RCU) | ||
325 | return -ECHILD; | ||
326 | |||
327 | dir = dentry->d_parent->d_inode; | ||
328 | sbi = autofs4_sbi(dir->i_sb); | ||
329 | oz_mode = autofs4_oz_mode(sbi); | ||
330 | |||
331 | /* Pending dentry */ | ||
332 | spin_lock(&sbi->fs_lock); | ||
333 | if (autofs4_ispending(dentry)) { | ||
334 | /* The daemon never causes a mount to trigger */ | ||
335 | spin_unlock(&sbi->fs_lock); | ||
336 | |||
337 | if (oz_mode) | ||
338 | return 1; | ||
339 | |||
340 | /* | ||
341 | * If the directory has gone away due to an expire | ||
342 | * we have been called as ->d_revalidate() and so | ||
343 | * we need to return false and proceed to ->lookup(). | ||
344 | */ | ||
345 | if (autofs4_expire_wait(dentry) == -EAGAIN) | ||
346 | return 0; | ||
347 | |||
348 | /* | ||
349 | * A zero status is success otherwise we have a | ||
350 | * negative error code. | ||
351 | */ | ||
352 | status = try_to_fill_dentry(dentry, flags); | ||
353 | if (status == 0) | ||
354 | return 1; | ||
355 | |||
356 | return status; | ||
357 | } | ||
358 | spin_unlock(&sbi->fs_lock); | ||
359 | |||
360 | /* Negative dentry.. invalidate if "old" */ | ||
361 | if (dentry->d_inode == NULL) | ||
362 | return 0; | ||
363 | |||
364 | /* Check for a non-mountpoint directory with no contents */ | ||
365 | spin_lock(&autofs4_lock); | ||
366 | spin_lock(&dentry->d_lock); | ||
367 | if (S_ISDIR(dentry->d_inode->i_mode) && | ||
368 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | ||
369 | DPRINTK("dentry=%p %.*s, emptydir", | ||
370 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
371 | spin_unlock(&dentry->d_lock); | ||
372 | spin_unlock(&autofs4_lock); | ||
373 | |||
374 | /* The daemon never causes a mount to trigger */ | ||
375 | if (oz_mode) | ||
376 | return 1; | ||
377 | |||
378 | /* | ||
379 | * A zero status is success otherwise we have a | ||
380 | * negative error code. | ||
381 | */ | ||
382 | status = try_to_fill_dentry(dentry, flags); | ||
383 | if (status == 0) | ||
384 | return 1; | ||
385 | |||
386 | return status; | ||
387 | } | ||
388 | spin_unlock(&dentry->d_lock); | ||
389 | spin_unlock(&autofs4_lock); | ||
390 | |||
391 | return 1; | ||
392 | } | ||
393 | |||
394 | void autofs4_dentry_release(struct dentry *de) | 141 | void autofs4_dentry_release(struct dentry *de) |
395 | { | 142 | { |
396 | struct autofs_info *inf; | 143 | struct autofs_info *inf; |
@@ -398,11 +145,8 @@ void autofs4_dentry_release(struct dentry *de) | |||
398 | DPRINTK("releasing %p", de); | 145 | DPRINTK("releasing %p", de); |
399 | 146 | ||
400 | inf = autofs4_dentry_ino(de); | 147 | inf = autofs4_dentry_ino(de); |
401 | de->d_fsdata = NULL; | ||
402 | |||
403 | if (inf) { | 148 | if (inf) { |
404 | struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); | 149 | struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); |
405 | |||
406 | if (sbi) { | 150 | if (sbi) { |
407 | spin_lock(&sbi->lookup_lock); | 151 | spin_lock(&sbi->lookup_lock); |
408 | if (!list_empty(&inf->active)) | 152 | if (!list_empty(&inf->active)) |
@@ -411,26 +155,10 @@ void autofs4_dentry_release(struct dentry *de) | |||
411 | list_del(&inf->expiring); | 155 | list_del(&inf->expiring); |
412 | spin_unlock(&sbi->lookup_lock); | 156 | spin_unlock(&sbi->lookup_lock); |
413 | } | 157 | } |
414 | |||
415 | inf->dentry = NULL; | ||
416 | inf->inode = NULL; | ||
417 | |||
418 | autofs4_free_ino(inf); | 158 | autofs4_free_ino(inf); |
419 | } | 159 | } |
420 | } | 160 | } |
421 | 161 | ||
422 | /* For dentries of directories in the root dir */ | ||
423 | static const struct dentry_operations autofs4_root_dentry_operations = { | ||
424 | .d_revalidate = autofs4_revalidate, | ||
425 | .d_release = autofs4_dentry_release, | ||
426 | }; | ||
427 | |||
428 | /* For other dentries */ | ||
429 | static const struct dentry_operations autofs4_dentry_operations = { | ||
430 | .d_revalidate = autofs4_revalidate, | ||
431 | .d_release = autofs4_dentry_release, | ||
432 | }; | ||
433 | |||
434 | static struct dentry *autofs4_lookup_active(struct dentry *dentry) | 162 | static struct dentry *autofs4_lookup_active(struct dentry *dentry) |
435 | { | 163 | { |
436 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 164 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
@@ -541,50 +269,244 @@ next: | |||
541 | return NULL; | 269 | return NULL; |
542 | } | 270 | } |
543 | 271 | ||
272 | static int autofs4_mount_wait(struct dentry *dentry) | ||
273 | { | ||
274 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
275 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
276 | int status; | ||
277 | |||
278 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
279 | DPRINTK("waiting for mount name=%.*s", | ||
280 | dentry->d_name.len, dentry->d_name.name); | ||
281 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | ||
282 | DPRINTK("mount wait done status=%d", status); | ||
283 | ino->last_used = jiffies; | ||
284 | return status; | ||
285 | } | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int do_expire_wait(struct dentry *dentry) | ||
290 | { | ||
291 | struct dentry *expiring; | ||
292 | |||
293 | expiring = autofs4_lookup_expiring(dentry); | ||
294 | if (!expiring) | ||
295 | return autofs4_expire_wait(dentry); | ||
296 | else { | ||
297 | /* | ||
298 | * If we are racing with expire the request might not | ||
299 | * be quite complete, but the directory has been removed | ||
300 | * so it must have been successful, just wait for it. | ||
301 | */ | ||
302 | autofs4_expire_wait(expiring); | ||
303 | autofs4_del_expiring(expiring); | ||
304 | dput(expiring); | ||
305 | } | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static struct dentry *autofs4_mountpoint_changed(struct path *path) | ||
310 | { | ||
311 | struct dentry *dentry = path->dentry; | ||
312 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
313 | |||
314 | /* | ||
315 | * If this is an indirect mount the dentry could have gone away | ||
316 | * as a result of an expire and a new one created. | ||
317 | */ | ||
318 | if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { | ||
319 | struct dentry *parent = dentry->d_parent; | ||
320 | struct dentry *new = d_lookup(parent, &dentry->d_name); | ||
321 | if (!new) | ||
322 | return NULL; | ||
323 | dput(path->dentry); | ||
324 | path->dentry = new; | ||
325 | } | ||
326 | return path->dentry; | ||
327 | } | ||
328 | |||
329 | static struct vfsmount *autofs4_d_automount(struct path *path) | ||
330 | { | ||
331 | struct dentry *dentry = path->dentry; | ||
332 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
333 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
334 | int status; | ||
335 | |||
336 | DPRINTK("dentry=%p %.*s", | ||
337 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
338 | |||
339 | /* | ||
340 | * Someone may have manually umounted this or it was a submount | ||
341 | * that has gone away. | ||
342 | */ | ||
343 | spin_lock(&dentry->d_lock); | ||
344 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | ||
345 | if (!(dentry->d_flags & DCACHE_MANAGE_TRANSIT) && | ||
346 | (dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | ||
347 | __managed_dentry_set_transit(path->dentry); | ||
348 | } | ||
349 | spin_unlock(&dentry->d_lock); | ||
350 | |||
351 | /* The daemon never triggers a mount. */ | ||
352 | if (autofs4_oz_mode(sbi)) | ||
353 | return NULL; | ||
354 | |||
355 | /* | ||
356 | * If an expire request is pending everyone must wait. | ||
357 | * If the expire fails we're still mounted so continue | ||
358 | * the follow and return. A return of -EAGAIN (which only | ||
359 | * happens with indirect mounts) means the expire completed | ||
360 | * and the directory was removed, so just go ahead and try | ||
361 | * the mount. | ||
362 | */ | ||
363 | status = do_expire_wait(dentry); | ||
364 | if (status && status != -EAGAIN) | ||
365 | return NULL; | ||
366 | |||
367 | /* Callback to the daemon to perform the mount or wait */ | ||
368 | spin_lock(&sbi->fs_lock); | ||
369 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
370 | spin_unlock(&sbi->fs_lock); | ||
371 | status = autofs4_mount_wait(dentry); | ||
372 | if (status) | ||
373 | return ERR_PTR(status); | ||
374 | spin_lock(&sbi->fs_lock); | ||
375 | goto done; | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * If the dentry is a symlink it's equivalent to a directory | ||
380 | * having d_mountpoint() true, so there's no need to call back | ||
381 | * to the daemon. | ||
382 | */ | ||
383 | if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) | ||
384 | goto done; | ||
385 | if (!d_mountpoint(dentry)) { | ||
386 | /* | ||
387 | * It's possible that user space hasn't removed directories | ||
388 | * after umounting a rootless multi-mount, although it | ||
389 | * should. For v5 have_submounts() is sufficient to handle | ||
390 | * this because the leaves of the directory tree under the | ||
391 | * mount never trigger mounts themselves (they have an autofs | ||
392 | * trigger mount mounted on them). But v4 pseudo direct mounts | ||
393 | * do need the leaves to to trigger mounts. In this case we | ||
394 | * have no choice but to use the list_empty() check and | ||
395 | * require user space behave. | ||
396 | */ | ||
397 | if (sbi->version > 4) { | ||
398 | if (have_submounts(dentry)) | ||
399 | goto done; | ||
400 | } else { | ||
401 | spin_lock(&dentry->d_lock); | ||
402 | if (!list_empty(&dentry->d_subdirs)) { | ||
403 | spin_unlock(&dentry->d_lock); | ||
404 | goto done; | ||
405 | } | ||
406 | spin_unlock(&dentry->d_lock); | ||
407 | } | ||
408 | ino->flags |= AUTOFS_INF_PENDING; | ||
409 | spin_unlock(&sbi->fs_lock); | ||
410 | status = autofs4_mount_wait(dentry); | ||
411 | if (status) | ||
412 | return ERR_PTR(status); | ||
413 | spin_lock(&sbi->fs_lock); | ||
414 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
415 | } | ||
416 | done: | ||
417 | if (!(ino->flags & AUTOFS_INF_EXPIRING)) { | ||
418 | /* | ||
419 | * Any needed mounting has been completed and the path updated | ||
420 | * so turn this into a normal dentry so we don't continually | ||
421 | * call ->d_automount() and ->d_manage(). | ||
422 | */ | ||
423 | spin_lock(&dentry->d_lock); | ||
424 | __managed_dentry_clear_transit(dentry); | ||
425 | /* | ||
426 | * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and | ||
427 | * symlinks as in all other cases the dentry will be covered by | ||
428 | * an actual mount so ->d_automount() won't be called during | ||
429 | * the follow. | ||
430 | */ | ||
431 | if ((!d_mountpoint(dentry) && | ||
432 | !list_empty(&dentry->d_subdirs)) || | ||
433 | (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))) | ||
434 | __managed_dentry_clear_automount(dentry); | ||
435 | spin_unlock(&dentry->d_lock); | ||
436 | } | ||
437 | spin_unlock(&sbi->fs_lock); | ||
438 | |||
439 | /* Mount succeeded, check if we ended up with a new dentry */ | ||
440 | dentry = autofs4_mountpoint_changed(path); | ||
441 | if (!dentry) | ||
442 | return ERR_PTR(-ENOENT); | ||
443 | |||
444 | return NULL; | ||
445 | } | ||
446 | |||
447 | int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk) | ||
448 | { | ||
449 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
450 | |||
451 | DPRINTK("dentry=%p %.*s", | ||
452 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
453 | |||
454 | /* The daemon never waits. */ | ||
455 | if (autofs4_oz_mode(sbi) || mounting_here) { | ||
456 | if (!d_mountpoint(dentry)) | ||
457 | return -EISDIR; | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /* We need to sleep, so we need pathwalk to be in ref-mode */ | ||
462 | if (rcu_walk) | ||
463 | return -ECHILD; | ||
464 | |||
465 | /* Wait for pending expires */ | ||
466 | do_expire_wait(dentry); | ||
467 | |||
468 | /* | ||
469 | * This dentry may be under construction so wait on mount | ||
470 | * completion. | ||
471 | */ | ||
472 | return autofs4_mount_wait(dentry); | ||
473 | } | ||
474 | |||
544 | /* Lookups in the root directory */ | 475 | /* Lookups in the root directory */ |
545 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 476 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
546 | { | 477 | { |
547 | struct autofs_sb_info *sbi; | 478 | struct autofs_sb_info *sbi; |
548 | struct autofs_info *ino; | 479 | struct autofs_info *ino; |
549 | struct dentry *expiring, *active; | 480 | struct dentry *active; |
550 | int oz_mode; | ||
551 | 481 | ||
552 | DPRINTK("name = %.*s", | 482 | DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name); |
553 | dentry->d_name.len, dentry->d_name.name); | ||
554 | 483 | ||
555 | /* File name too long to exist */ | 484 | /* File name too long to exist */ |
556 | if (dentry->d_name.len > NAME_MAX) | 485 | if (dentry->d_name.len > NAME_MAX) |
557 | return ERR_PTR(-ENAMETOOLONG); | 486 | return ERR_PTR(-ENAMETOOLONG); |
558 | 487 | ||
559 | sbi = autofs4_sbi(dir->i_sb); | 488 | sbi = autofs4_sbi(dir->i_sb); |
560 | oz_mode = autofs4_oz_mode(sbi); | ||
561 | 489 | ||
562 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", | 490 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", |
563 | current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); | 491 | current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); |
564 | 492 | ||
565 | active = autofs4_lookup_active(dentry); | 493 | active = autofs4_lookup_active(dentry); |
566 | if (active) { | 494 | if (active) { |
567 | dentry = active; | 495 | return active; |
568 | ino = autofs4_dentry_ino(dentry); | ||
569 | } else { | 496 | } else { |
570 | /* | 497 | /* |
571 | * Mark the dentry incomplete but don't hash it. We do this | 498 | * A dentry that is not within the root can never trigger a |
572 | * to serialize our inode creation operations (symlink and | 499 | * mount operation, unless the directory already exists, so we |
573 | * mkdir) which prevents deadlock during the callback to | 500 | * can return fail immediately. The daemon however does need |
574 | * the daemon. Subsequent user space lookups for the same | 501 | * to create directories within the file system. |
575 | * dentry are placed on the wait queue while the daemon | ||
576 | * itself is allowed passage unresticted so the create | ||
577 | * operation itself can then hash the dentry. Finally, | ||
578 | * we check for the hashed dentry and return the newly | ||
579 | * hashed dentry. | ||
580 | */ | 502 | */ |
581 | d_set_d_op(dentry, &autofs4_root_dentry_operations); | 503 | if (!autofs4_oz_mode(sbi) && !IS_ROOT(dentry->d_parent)) |
504 | return ERR_PTR(-ENOENT); | ||
505 | |||
506 | /* Mark entries in the root as mount triggers */ | ||
507 | if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) | ||
508 | __managed_dentry_set_managed(dentry); | ||
582 | 509 | ||
583 | /* | ||
584 | * And we need to ensure that the same dentry is used for | ||
585 | * all following lookup calls until it is hashed so that | ||
586 | * the dentry flags are persistent throughout the request. | ||
587 | */ | ||
588 | ino = autofs4_init_ino(NULL, sbi, 0555); | 510 | ino = autofs4_init_ino(NULL, sbi, 0555); |
589 | if (!ino) | 511 | if (!ino) |
590 | return ERR_PTR(-ENOMEM); | 512 | return ERR_PTR(-ENOMEM); |
@@ -596,82 +518,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
596 | 518 | ||
597 | d_instantiate(dentry, NULL); | 519 | d_instantiate(dentry, NULL); |
598 | } | 520 | } |
599 | |||
600 | if (!oz_mode) { | ||
601 | mutex_unlock(&dir->i_mutex); | ||
602 | expiring = autofs4_lookup_expiring(dentry); | ||
603 | if (expiring) { | ||
604 | /* | ||
605 | * If we are racing with expire the request might not | ||
606 | * be quite complete but the directory has been removed | ||
607 | * so it must have been successful, so just wait for it. | ||
608 | */ | ||
609 | autofs4_expire_wait(expiring); | ||
610 | autofs4_del_expiring(expiring); | ||
611 | dput(expiring); | ||
612 | } | ||
613 | |||
614 | spin_lock(&sbi->fs_lock); | ||
615 | ino->flags |= AUTOFS_INF_PENDING; | ||
616 | spin_unlock(&sbi->fs_lock); | ||
617 | if (dentry->d_op && dentry->d_op->d_revalidate) | ||
618 | (dentry->d_op->d_revalidate)(dentry, nd); | ||
619 | mutex_lock(&dir->i_mutex); | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * If we are still pending, check if we had to handle | ||
624 | * a signal. If so we can force a restart.. | ||
625 | */ | ||
626 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
627 | /* See if we were interrupted */ | ||
628 | if (signal_pending(current)) { | ||
629 | sigset_t *sigset = ¤t->pending.signal; | ||
630 | if (sigismember (sigset, SIGKILL) || | ||
631 | sigismember (sigset, SIGQUIT) || | ||
632 | sigismember (sigset, SIGINT)) { | ||
633 | if (active) | ||
634 | dput(active); | ||
635 | return ERR_PTR(-ERESTARTNOINTR); | ||
636 | } | ||
637 | } | ||
638 | if (!oz_mode) { | ||
639 | spin_lock(&sbi->fs_lock); | ||
640 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
641 | spin_unlock(&sbi->fs_lock); | ||
642 | } | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * If this dentry is unhashed, then we shouldn't honour this | ||
647 | * lookup. Returning ENOENT here doesn't do the right thing | ||
648 | * for all system calls, but it should be OK for the operations | ||
649 | * we permit from an autofs. | ||
650 | */ | ||
651 | if (!oz_mode && d_unhashed(dentry)) { | ||
652 | /* | ||
653 | * A user space application can (and has done in the past) | ||
654 | * remove and re-create this directory during the callback. | ||
655 | * This can leave us with an unhashed dentry, but a | ||
656 | * successful mount! So we need to perform another | ||
657 | * cached lookup in case the dentry now exists. | ||
658 | */ | ||
659 | struct dentry *parent = dentry->d_parent; | ||
660 | struct dentry *new = d_lookup(parent, &dentry->d_name); | ||
661 | if (new != NULL) | ||
662 | dentry = new; | ||
663 | else | ||
664 | dentry = ERR_PTR(-ENOENT); | ||
665 | |||
666 | if (active) | ||
667 | dput(active); | ||
668 | |||
669 | return dentry; | ||
670 | } | ||
671 | |||
672 | if (active) | ||
673 | return active; | ||
674 | |||
675 | return NULL; | 521 | return NULL; |
676 | } | 522 | } |
677 | 523 | ||
@@ -716,18 +562,12 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
716 | } | 562 | } |
717 | d_add(dentry, inode); | 563 | d_add(dentry, inode); |
718 | 564 | ||
719 | if (dir == dir->i_sb->s_root->d_inode) | ||
720 | d_set_d_op(dentry, &autofs4_root_dentry_operations); | ||
721 | else | ||
722 | d_set_d_op(dentry, &autofs4_dentry_operations); | ||
723 | |||
724 | dentry->d_fsdata = ino; | 565 | dentry->d_fsdata = ino; |
725 | ino->dentry = dget(dentry); | 566 | ino->dentry = dget(dentry); |
726 | atomic_inc(&ino->count); | 567 | atomic_inc(&ino->count); |
727 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 568 | p_ino = autofs4_dentry_ino(dentry->d_parent); |
728 | if (p_ino && dentry->d_parent != dentry) | 569 | if (p_ino && dentry->d_parent != dentry) |
729 | atomic_inc(&p_ino->count); | 570 | atomic_inc(&p_ino->count); |
730 | ino->inode = inode; | ||
731 | 571 | ||
732 | ino->u.symlink = cp; | 572 | ino->u.symlink = cp; |
733 | dir->i_mtime = CURRENT_TIME; | 573 | dir->i_mtime = CURRENT_TIME; |
@@ -782,6 +622,58 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
782 | return 0; | 622 | return 0; |
783 | } | 623 | } |
784 | 624 | ||
625 | /* | ||
626 | * Version 4 of autofs provides a pseudo direct mount implementation | ||
627 | * that relies on directories at the leaves of a directory tree under | ||
628 | * an indirect mount to trigger mounts. To allow for this we need to | ||
629 | * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves | ||
630 | * of the directory tree. There is no need to clear the automount flag | ||
631 | * following a mount or restore it after an expire because these mounts | ||
632 | * are always covered. However, it is neccessary to ensure that these | ||
633 | * flags are clear on non-empty directories to avoid unnecessary calls | ||
634 | * during path walks. | ||
635 | */ | ||
636 | static void autofs_set_leaf_automount_flags(struct dentry *dentry) | ||
637 | { | ||
638 | struct dentry *parent; | ||
639 | |||
640 | /* root and dentrys in the root are already handled */ | ||
641 | if (IS_ROOT(dentry->d_parent)) | ||
642 | return; | ||
643 | |||
644 | managed_dentry_set_managed(dentry); | ||
645 | |||
646 | parent = dentry->d_parent; | ||
647 | /* only consider parents below dentrys in the root */ | ||
648 | if (IS_ROOT(parent->d_parent)) | ||
649 | return; | ||
650 | managed_dentry_clear_managed(parent); | ||
651 | return; | ||
652 | } | ||
653 | |||
654 | static void autofs_clear_leaf_automount_flags(struct dentry *dentry) | ||
655 | { | ||
656 | struct list_head *d_child; | ||
657 | struct dentry *parent; | ||
658 | |||
659 | /* flags for dentrys in the root are handled elsewhere */ | ||
660 | if (IS_ROOT(dentry->d_parent)) | ||
661 | return; | ||
662 | |||
663 | managed_dentry_clear_managed(dentry); | ||
664 | |||
665 | parent = dentry->d_parent; | ||
666 | /* only consider parents below dentrys in the root */ | ||
667 | if (IS_ROOT(parent->d_parent)) | ||
668 | return; | ||
669 | d_child = &dentry->d_u.d_child; | ||
670 | /* Set parent managed if it's becoming empty */ | ||
671 | if (d_child->next == &parent->d_subdirs && | ||
672 | d_child->prev == &parent->d_subdirs) | ||
673 | managed_dentry_set_managed(parent); | ||
674 | return; | ||
675 | } | ||
676 | |||
785 | static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | 677 | static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) |
786 | { | 678 | { |
787 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 679 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
@@ -809,6 +701,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
809 | spin_unlock(&dentry->d_lock); | 701 | spin_unlock(&dentry->d_lock); |
810 | spin_unlock(&autofs4_lock); | 702 | spin_unlock(&autofs4_lock); |
811 | 703 | ||
704 | if (sbi->version < 5) | ||
705 | autofs_clear_leaf_automount_flags(dentry); | ||
706 | |||
812 | if (atomic_dec_and_test(&ino->count)) { | 707 | if (atomic_dec_and_test(&ino->count)) { |
813 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 708 | p_ino = autofs4_dentry_ino(dentry->d_parent); |
814 | if (p_ino && dentry->d_parent != dentry) | 709 | if (p_ino && dentry->d_parent != dentry) |
@@ -851,10 +746,8 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
851 | } | 746 | } |
852 | d_add(dentry, inode); | 747 | d_add(dentry, inode); |
853 | 748 | ||
854 | if (dir == dir->i_sb->s_root->d_inode) | 749 | if (sbi->version < 5) |
855 | d_set_d_op(dentry, &autofs4_root_dentry_operations); | 750 | autofs_set_leaf_automount_flags(dentry); |
856 | else | ||
857 | d_set_d_op(dentry, &autofs4_dentry_operations); | ||
858 | 751 | ||
859 | dentry->d_fsdata = ino; | 752 | dentry->d_fsdata = ino; |
860 | ino->dentry = dget(dentry); | 753 | ino->dentry = dget(dentry); |
@@ -862,7 +755,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
862 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 755 | p_ino = autofs4_dentry_ino(dentry->d_parent); |
863 | if (p_ino && dentry->d_parent != dentry) | 756 | if (p_ino && dentry->d_parent != dentry) |
864 | atomic_inc(&p_ino->count); | 757 | atomic_inc(&p_ino->count); |
865 | ino->inode = inode; | ||
866 | inc_nlink(dir); | 758 | inc_nlink(dir); |
867 | dir->i_mtime = CURRENT_TIME; | 759 | dir->i_mtime = CURRENT_TIME; |
868 | 760 | ||
@@ -944,8 +836,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) | |||
944 | int is_autofs4_dentry(struct dentry *dentry) | 836 | int is_autofs4_dentry(struct dentry *dentry) |
945 | { | 837 | { |
946 | return dentry && dentry->d_inode && | 838 | return dentry && dentry->d_inode && |
947 | (dentry->d_op == &autofs4_root_dentry_operations || | 839 | dentry->d_op == &autofs4_dentry_operations && |
948 | dentry->d_op == &autofs4_dentry_operations) && | ||
949 | dentry->d_fsdata != NULL; | 840 | dentry->d_fsdata != NULL; |
950 | } | 841 | } |
951 | 842 | ||
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index c5f8459c905e..56010056b2e6 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -309,6 +309,9 @@ static int validate_request(struct autofs_wait_queue **wait, | |||
309 | * completed while we waited on the mutex ... | 309 | * completed while we waited on the mutex ... |
310 | */ | 310 | */ |
311 | if (notify == NFY_MOUNT) { | 311 | if (notify == NFY_MOUNT) { |
312 | struct dentry *new = NULL; | ||
313 | int valid = 1; | ||
314 | |||
312 | /* | 315 | /* |
313 | * If the dentry was successfully mounted while we slept | 316 | * If the dentry was successfully mounted while we slept |
314 | * on the wait queue mutex we can return success. If it | 317 | * on the wait queue mutex we can return success. If it |
@@ -316,8 +319,20 @@ static int validate_request(struct autofs_wait_queue **wait, | |||
316 | * a multi-mount with no mount at it's base) we can | 319 | * a multi-mount with no mount at it's base) we can |
317 | * continue on and create a new request. | 320 | * continue on and create a new request. |
318 | */ | 321 | */ |
322 | if (!IS_ROOT(dentry)) { | ||
323 | if (dentry->d_inode && d_unhashed(dentry)) { | ||
324 | struct dentry *parent = dentry->d_parent; | ||
325 | new = d_lookup(parent, &dentry->d_name); | ||
326 | if (new) | ||
327 | dentry = new; | ||
328 | } | ||
329 | } | ||
319 | if (have_submounts(dentry)) | 330 | if (have_submounts(dentry)) |
320 | return 0; | 331 | valid = 0; |
332 | |||
333 | if (new) | ||
334 | dput(new); | ||
335 | return valid; | ||
321 | } | 336 | } |
322 | 337 | ||
323 | return 1; | 338 | return 1; |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index c68a056f27fd..7ed36536e754 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -255,35 +255,6 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, | |||
255 | 255 | ||
256 | } | 256 | } |
257 | 257 | ||
258 | static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | ||
259 | struct list_head *mntlist) | ||
260 | { | ||
261 | /* stolen from afs code */ | ||
262 | int err; | ||
263 | |||
264 | mntget(newmnt); | ||
265 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist); | ||
266 | switch (err) { | ||
267 | case 0: | ||
268 | path_put(&nd->path); | ||
269 | nd->path.mnt = newmnt; | ||
270 | nd->path.dentry = dget(newmnt->mnt_root); | ||
271 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
272 | cifs_dfs_mountpoint_expiry_timeout); | ||
273 | break; | ||
274 | case -EBUSY: | ||
275 | /* someone else made a mount here whilst we were busy */ | ||
276 | while (d_mountpoint(nd->path.dentry) && | ||
277 | follow_down(&nd->path)) | ||
278 | ; | ||
279 | err = 0; | ||
280 | default: | ||
281 | mntput(newmnt); | ||
282 | break; | ||
283 | } | ||
284 | return err; | ||
285 | } | ||
286 | |||
287 | static void dump_referral(const struct dfs_info3_param *ref) | 258 | static void dump_referral(const struct dfs_info3_param *ref) |
288 | { | 259 | { |
289 | cFYI(1, "DFS: ref path: %s", ref->path_name); | 260 | cFYI(1, "DFS: ref path: %s", ref->path_name); |
@@ -293,45 +264,43 @@ static void dump_referral(const struct dfs_info3_param *ref) | |||
293 | ref->path_consumed); | 264 | ref->path_consumed); |
294 | } | 265 | } |
295 | 266 | ||
296 | 267 | /* | |
297 | static void* | 268 | * Create a vfsmount that we can automount |
298 | cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | 269 | */ |
270 | static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) | ||
299 | { | 271 | { |
300 | struct dfs_info3_param *referrals = NULL; | 272 | struct dfs_info3_param *referrals = NULL; |
301 | unsigned int num_referrals = 0; | 273 | unsigned int num_referrals = 0; |
302 | struct cifs_sb_info *cifs_sb; | 274 | struct cifs_sb_info *cifs_sb; |
303 | struct cifsSesInfo *ses; | 275 | struct cifsSesInfo *ses; |
304 | char *full_path = NULL; | 276 | char *full_path; |
305 | int xid, i; | 277 | int xid, i; |
306 | int rc = 0; | 278 | int rc; |
307 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 279 | struct vfsmount *mnt; |
308 | struct tcon_link *tlink; | 280 | struct tcon_link *tlink; |
309 | 281 | ||
310 | cFYI(1, "in %s", __func__); | 282 | cFYI(1, "in %s", __func__); |
311 | BUG_ON(IS_ROOT(dentry)); | 283 | BUG_ON(IS_ROOT(mntpt)); |
312 | 284 | ||
313 | xid = GetXid(); | 285 | xid = GetXid(); |
314 | 286 | ||
315 | dput(nd->path.dentry); | ||
316 | nd->path.dentry = dget(dentry); | ||
317 | |||
318 | /* | 287 | /* |
319 | * The MSDFS spec states that paths in DFS referral requests and | 288 | * The MSDFS spec states that paths in DFS referral requests and |
320 | * responses must be prefixed by a single '\' character instead of | 289 | * responses must be prefixed by a single '\' character instead of |
321 | * the double backslashes usually used in the UNC. This function | 290 | * the double backslashes usually used in the UNC. This function |
322 | * gives us the latter, so we must adjust the result. | 291 | * gives us the latter, so we must adjust the result. |
323 | */ | 292 | */ |
324 | full_path = build_path_from_dentry(dentry); | 293 | mnt = ERR_PTR(-ENOMEM); |
325 | if (full_path == NULL) { | 294 | full_path = build_path_from_dentry(mntpt); |
326 | rc = -ENOMEM; | 295 | if (full_path == NULL) |
327 | goto out_err; | 296 | goto free_xid; |
328 | } | ||
329 | 297 | ||
330 | cifs_sb = CIFS_SB(dentry->d_inode->i_sb); | 298 | cifs_sb = CIFS_SB(mntpt->d_inode->i_sb); |
331 | tlink = cifs_sb_tlink(cifs_sb); | 299 | tlink = cifs_sb_tlink(cifs_sb); |
300 | mnt = ERR_PTR(-EINVAL); | ||
332 | if (IS_ERR(tlink)) { | 301 | if (IS_ERR(tlink)) { |
333 | rc = PTR_ERR(tlink); | 302 | mnt = ERR_CAST(tlink); |
334 | goto out_err; | 303 | goto free_full_path; |
335 | } | 304 | } |
336 | ses = tlink_tcon(tlink)->ses; | 305 | ses = tlink_tcon(tlink)->ses; |
337 | 306 | ||
@@ -341,46 +310,63 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
341 | 310 | ||
342 | cifs_put_tlink(tlink); | 311 | cifs_put_tlink(tlink); |
343 | 312 | ||
313 | mnt = ERR_PTR(-ENOENT); | ||
344 | for (i = 0; i < num_referrals; i++) { | 314 | for (i = 0; i < num_referrals; i++) { |
345 | int len; | 315 | int len; |
346 | dump_referral(referrals+i); | 316 | dump_referral(referrals + i); |
347 | /* connect to a node */ | 317 | /* connect to a node */ |
348 | len = strlen(referrals[i].node_name); | 318 | len = strlen(referrals[i].node_name); |
349 | if (len < 2) { | 319 | if (len < 2) { |
350 | cERROR(1, "%s: Net Address path too short: %s", | 320 | cERROR(1, "%s: Net Address path too short: %s", |
351 | __func__, referrals[i].node_name); | 321 | __func__, referrals[i].node_name); |
352 | rc = -EINVAL; | 322 | mnt = ERR_PTR(-EINVAL); |
353 | goto out_err; | 323 | break; |
354 | } | 324 | } |
355 | mnt = cifs_dfs_do_refmount(cifs_sb, | 325 | mnt = cifs_dfs_do_refmount(cifs_sb, |
356 | full_path, referrals + i); | 326 | full_path, referrals + i); |
357 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, | 327 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, |
358 | referrals[i].node_name, mnt); | 328 | referrals[i].node_name, mnt); |
359 | |||
360 | /* complete mount procedure if we accured submount */ | ||
361 | if (!IS_ERR(mnt)) | 329 | if (!IS_ERR(mnt)) |
362 | break; | 330 | goto success; |
363 | } | 331 | } |
364 | 332 | ||
365 | /* we need it cause for() above could exit without valid submount */ | 333 | /* no valid submounts were found; return error from get_dfs_path() by |
366 | rc = PTR_ERR(mnt); | 334 | * preference */ |
367 | if (IS_ERR(mnt)) | 335 | if (rc != 0) |
368 | goto out_err; | 336 | mnt = ERR_PTR(rc); |
369 | |||
370 | rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); | ||
371 | 337 | ||
372 | out: | 338 | success: |
373 | FreeXid(xid); | ||
374 | free_dfs_info_array(referrals, num_referrals); | 339 | free_dfs_info_array(referrals, num_referrals); |
340 | free_full_path: | ||
375 | kfree(full_path); | 341 | kfree(full_path); |
342 | free_xid: | ||
343 | FreeXid(xid); | ||
376 | cFYI(1, "leaving %s" , __func__); | 344 | cFYI(1, "leaving %s" , __func__); |
377 | return ERR_PTR(rc); | 345 | return mnt; |
378 | out_err: | 346 | } |
379 | path_put(&nd->path); | 347 | |
380 | goto out; | 348 | /* |
349 | * Attempt to automount the referral | ||
350 | */ | ||
351 | struct vfsmount *cifs_dfs_d_automount(struct path *path) | ||
352 | { | ||
353 | struct vfsmount *newmnt; | ||
354 | |||
355 | cFYI(1, "in %s", __func__); | ||
356 | |||
357 | newmnt = cifs_dfs_do_automount(path->dentry); | ||
358 | if (IS_ERR(newmnt)) { | ||
359 | cFYI(1, "leaving %s [automount failed]" , __func__); | ||
360 | return newmnt; | ||
361 | } | ||
362 | |||
363 | mntget(newmnt); /* prevent immediate expiration */ | ||
364 | mnt_set_expiry(newmnt, &cifs_dfs_automount_list); | ||
365 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
366 | cifs_dfs_mountpoint_expiry_timeout); | ||
367 | cFYI(1, "leaving %s [ok]" , __func__); | ||
368 | return newmnt; | ||
381 | } | 369 | } |
382 | 370 | ||
383 | const struct inode_operations cifs_dfs_referral_inode_operations = { | 371 | const struct inode_operations cifs_dfs_referral_inode_operations = { |
384 | .follow_link = cifs_dfs_follow_mountpoint, | ||
385 | }; | 372 | }; |
386 | |||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 897b2b2b28b5..851030f74939 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -93,6 +93,12 @@ extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); | |||
93 | extern const struct dentry_operations cifs_dentry_ops; | 93 | extern const struct dentry_operations cifs_dentry_ops; |
94 | extern const struct dentry_operations cifs_ci_dentry_ops; | 94 | extern const struct dentry_operations cifs_ci_dentry_ops; |
95 | 95 | ||
96 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
97 | extern struct vfsmount *cifs_dfs_d_automount(struct path *path); | ||
98 | #else | ||
99 | #define cifs_dfs_d_automount NULL | ||
100 | #endif | ||
101 | |||
96 | /* Functions related to symlinks */ | 102 | /* Functions related to symlinks */ |
97 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); | 103 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); |
98 | extern void cifs_put_link(struct dentry *direntry, | 104 | extern void cifs_put_link(struct dentry *direntry, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 1e95dd635632..dd5f22918c33 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -675,6 +675,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
675 | 675 | ||
676 | const struct dentry_operations cifs_dentry_ops = { | 676 | const struct dentry_operations cifs_dentry_ops = { |
677 | .d_revalidate = cifs_d_revalidate, | 677 | .d_revalidate = cifs_d_revalidate, |
678 | .d_automount = cifs_dfs_d_automount, | ||
678 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ | 679 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ |
679 | }; | 680 | }; |
680 | 681 | ||
@@ -711,4 +712,5 @@ const struct dentry_operations cifs_ci_dentry_ops = { | |||
711 | .d_revalidate = cifs_d_revalidate, | 712 | .d_revalidate = cifs_d_revalidate, |
712 | .d_hash = cifs_ci_hash, | 713 | .d_hash = cifs_ci_hash, |
713 | .d_compare = cifs_ci_compare, | 714 | .d_compare = cifs_ci_compare, |
715 | .d_automount = cifs_dfs_d_automount, | ||
714 | }; | 716 | }; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index b06b60620240..6c9ee8014ff0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include "fscache.h" | 32 | #include "fscache.h" |
33 | 33 | ||
34 | 34 | ||
35 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | 35 | static void cifs_set_ops(struct inode *inode) |
36 | { | 36 | { |
37 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 37 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
38 | 38 | ||
@@ -60,7 +60,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | |||
60 | break; | 60 | break; |
61 | case S_IFDIR: | 61 | case S_IFDIR: |
62 | #ifdef CONFIG_CIFS_DFS_UPCALL | 62 | #ifdef CONFIG_CIFS_DFS_UPCALL |
63 | if (is_dfs_referral) { | 63 | if (IS_AUTOMOUNT(inode)) { |
64 | inode->i_op = &cifs_dfs_referral_inode_operations; | 64 | inode->i_op = &cifs_dfs_referral_inode_operations; |
65 | } else { | 65 | } else { |
66 | #else /* NO DFS support, treat as a directory */ | 66 | #else /* NO DFS support, treat as a directory */ |
@@ -167,7 +167,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
167 | } | 167 | } |
168 | spin_unlock(&inode->i_lock); | 168 | spin_unlock(&inode->i_lock); |
169 | 169 | ||
170 | cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); | 170 | if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) |
171 | inode->i_flags |= S_AUTOMOUNT; | ||
172 | cifs_set_ops(inode); | ||
171 | } | 173 | } |
172 | 174 | ||
173 | void | 175 | void |
diff --git a/fs/dcache.c b/fs/dcache.c index 274a22250380..9f493ee4dcba 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1380,8 +1380,11 @@ EXPORT_SYMBOL(d_set_d_op); | |||
1380 | static void __d_instantiate(struct dentry *dentry, struct inode *inode) | 1380 | static void __d_instantiate(struct dentry *dentry, struct inode *inode) |
1381 | { | 1381 | { |
1382 | spin_lock(&dentry->d_lock); | 1382 | spin_lock(&dentry->d_lock); |
1383 | if (inode) | 1383 | if (inode) { |
1384 | if (unlikely(IS_AUTOMOUNT(inode))) | ||
1385 | dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; | ||
1384 | list_add(&dentry->d_alias, &inode->i_dentry); | 1386 | list_add(&dentry->d_alias, &inode->i_dentry); |
1387 | } | ||
1385 | dentry->d_inode = inode; | 1388 | dentry->d_inode = inode; |
1386 | dentry_rcuwalk_barrier(dentry); | 1389 | dentry_rcuwalk_barrier(dentry); |
1387 | spin_unlock(&dentry->d_lock); | 1390 | spin_unlock(&dentry->d_lock); |
diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 68ca487bedb1..78b519c13536 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c | |||
@@ -4,6 +4,19 @@ | |||
4 | #include <linux/path.h> | 4 | #include <linux/path.h> |
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/fs_struct.h> | 6 | #include <linux/fs_struct.h> |
7 | #include "internal.h" | ||
8 | |||
9 | static inline void path_get_longterm(struct path *path) | ||
10 | { | ||
11 | path_get(path); | ||
12 | mnt_make_longterm(path->mnt); | ||
13 | } | ||
14 | |||
15 | static inline void path_put_longterm(struct path *path) | ||
16 | { | ||
17 | mnt_make_shortterm(path->mnt); | ||
18 | path_put(path); | ||
19 | } | ||
7 | 20 | ||
8 | /* | 21 | /* |
9 | * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. | 22 | * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. |
@@ -17,11 +30,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) | |||
17 | write_seqcount_begin(&fs->seq); | 30 | write_seqcount_begin(&fs->seq); |
18 | old_root = fs->root; | 31 | old_root = fs->root; |
19 | fs->root = *path; | 32 | fs->root = *path; |
20 | path_get_long(path); | 33 | path_get_longterm(path); |
21 | write_seqcount_end(&fs->seq); | 34 | write_seqcount_end(&fs->seq); |
22 | spin_unlock(&fs->lock); | 35 | spin_unlock(&fs->lock); |
23 | if (old_root.dentry) | 36 | if (old_root.dentry) |
24 | path_put_long(&old_root); | 37 | path_put_longterm(&old_root); |
25 | } | 38 | } |
26 | 39 | ||
27 | /* | 40 | /* |
@@ -36,12 +49,12 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) | |||
36 | write_seqcount_begin(&fs->seq); | 49 | write_seqcount_begin(&fs->seq); |
37 | old_pwd = fs->pwd; | 50 | old_pwd = fs->pwd; |
38 | fs->pwd = *path; | 51 | fs->pwd = *path; |
39 | path_get_long(path); | 52 | path_get_longterm(path); |
40 | write_seqcount_end(&fs->seq); | 53 | write_seqcount_end(&fs->seq); |
41 | spin_unlock(&fs->lock); | 54 | spin_unlock(&fs->lock); |
42 | 55 | ||
43 | if (old_pwd.dentry) | 56 | if (old_pwd.dentry) |
44 | path_put_long(&old_pwd); | 57 | path_put_longterm(&old_pwd); |
45 | } | 58 | } |
46 | 59 | ||
47 | void chroot_fs_refs(struct path *old_root, struct path *new_root) | 60 | void chroot_fs_refs(struct path *old_root, struct path *new_root) |
@@ -59,13 +72,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) | |||
59 | write_seqcount_begin(&fs->seq); | 72 | write_seqcount_begin(&fs->seq); |
60 | if (fs->root.dentry == old_root->dentry | 73 | if (fs->root.dentry == old_root->dentry |
61 | && fs->root.mnt == old_root->mnt) { | 74 | && fs->root.mnt == old_root->mnt) { |
62 | path_get_long(new_root); | 75 | path_get_longterm(new_root); |
63 | fs->root = *new_root; | 76 | fs->root = *new_root; |
64 | count++; | 77 | count++; |
65 | } | 78 | } |
66 | if (fs->pwd.dentry == old_root->dentry | 79 | if (fs->pwd.dentry == old_root->dentry |
67 | && fs->pwd.mnt == old_root->mnt) { | 80 | && fs->pwd.mnt == old_root->mnt) { |
68 | path_get_long(new_root); | 81 | path_get_longterm(new_root); |
69 | fs->pwd = *new_root; | 82 | fs->pwd = *new_root; |
70 | count++; | 83 | count++; |
71 | } | 84 | } |
@@ -76,13 +89,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) | |||
76 | } while_each_thread(g, p); | 89 | } while_each_thread(g, p); |
77 | read_unlock(&tasklist_lock); | 90 | read_unlock(&tasklist_lock); |
78 | while (count--) | 91 | while (count--) |
79 | path_put_long(old_root); | 92 | path_put_longterm(old_root); |
80 | } | 93 | } |
81 | 94 | ||
82 | void free_fs_struct(struct fs_struct *fs) | 95 | void free_fs_struct(struct fs_struct *fs) |
83 | { | 96 | { |
84 | path_put_long(&fs->root); | 97 | path_put_longterm(&fs->root); |
85 | path_put_long(&fs->pwd); | 98 | path_put_longterm(&fs->pwd); |
86 | kmem_cache_free(fs_cachep, fs); | 99 | kmem_cache_free(fs_cachep, fs); |
87 | } | 100 | } |
88 | 101 | ||
@@ -118,9 +131,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) | |||
118 | 131 | ||
119 | spin_lock(&old->lock); | 132 | spin_lock(&old->lock); |
120 | fs->root = old->root; | 133 | fs->root = old->root; |
121 | path_get_long(&fs->root); | 134 | path_get_longterm(&fs->root); |
122 | fs->pwd = old->pwd; | 135 | fs->pwd = old->pwd; |
123 | path_get_long(&fs->pwd); | 136 | path_get_longterm(&fs->pwd); |
124 | spin_unlock(&old->lock); | 137 | spin_unlock(&old->lock); |
125 | } | 138 | } |
126 | return fs; | 139 | return fs; |
diff --git a/fs/internal.h b/fs/internal.h index 9687c2ee2735..12ccb86edef7 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -70,6 +70,11 @@ extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, | |||
70 | extern void release_mounts(struct list_head *); | 70 | extern void release_mounts(struct list_head *); |
71 | extern void umount_tree(struct vfsmount *, int, struct list_head *); | 71 | extern void umount_tree(struct vfsmount *, int, struct list_head *); |
72 | extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); | 72 | extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); |
73 | extern int do_add_mount(struct vfsmount *, struct path *, int); | ||
74 | extern void mnt_clear_expiry(struct vfsmount *); | ||
75 | |||
76 | extern void mnt_make_longterm(struct vfsmount *); | ||
77 | extern void mnt_make_shortterm(struct vfsmount *); | ||
73 | 78 | ||
74 | extern void __init mnt_init(void); | 79 | extern void __init mnt_init(void); |
75 | 80 | ||
diff --git a/fs/namei.c b/fs/namei.c index 8df7a78ace58..8f7b41a14882 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -368,18 +368,6 @@ void path_get(struct path *path) | |||
368 | EXPORT_SYMBOL(path_get); | 368 | EXPORT_SYMBOL(path_get); |
369 | 369 | ||
370 | /** | 370 | /** |
371 | * path_get_long - get a long reference to a path | ||
372 | * @path: path to get the reference to | ||
373 | * | ||
374 | * Given a path increment the reference count to the dentry and the vfsmount. | ||
375 | */ | ||
376 | void path_get_long(struct path *path) | ||
377 | { | ||
378 | mntget_long(path->mnt); | ||
379 | dget(path->dentry); | ||
380 | } | ||
381 | |||
382 | /** | ||
383 | * path_put - put a reference to a path | 371 | * path_put - put a reference to a path |
384 | * @path: path to put the reference to | 372 | * @path: path to put the reference to |
385 | * | 373 | * |
@@ -393,18 +381,6 @@ void path_put(struct path *path) | |||
393 | EXPORT_SYMBOL(path_put); | 381 | EXPORT_SYMBOL(path_put); |
394 | 382 | ||
395 | /** | 383 | /** |
396 | * path_put_long - put a long reference to a path | ||
397 | * @path: path to put the reference to | ||
398 | * | ||
399 | * Given a path decrement the reference count to the dentry and the vfsmount. | ||
400 | */ | ||
401 | void path_put_long(struct path *path) | ||
402 | { | ||
403 | dput(path->dentry); | ||
404 | mntput_long(path->mnt); | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * nameidata_drop_rcu - drop this nameidata out of rcu-walk | 384 | * nameidata_drop_rcu - drop this nameidata out of rcu-walk |
409 | * @nd: nameidata pathwalk data to drop | 385 | * @nd: nameidata pathwalk data to drop |
410 | * Returns: 0 on success, -ECHILD on failure | 386 | * Returns: 0 on success, -ECHILD on failure |
@@ -800,12 +776,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | |||
800 | touch_atime(link->mnt, dentry); | 776 | touch_atime(link->mnt, dentry); |
801 | nd_set_link(nd, NULL); | 777 | nd_set_link(nd, NULL); |
802 | 778 | ||
803 | if (link->mnt != nd->path.mnt) { | 779 | if (link->mnt == nd->path.mnt) |
804 | path_to_nameidata(link, nd); | 780 | mntget(link->mnt); |
805 | nd->inode = nd->path.dentry->d_inode; | ||
806 | dget(dentry); | ||
807 | } | ||
808 | mntget(link->mnt); | ||
809 | 781 | ||
810 | nd->last_type = LAST_BIND; | 782 | nd->last_type = LAST_BIND; |
811 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); | 783 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); |
@@ -896,54 +868,169 @@ int follow_up(struct path *path) | |||
896 | } | 868 | } |
897 | 869 | ||
898 | /* | 870 | /* |
899 | * serialization is taken care of in namespace.c | 871 | * Perform an automount |
872 | * - return -EISDIR to tell follow_managed() to stop and return the path we | ||
873 | * were called with. | ||
900 | */ | 874 | */ |
901 | static void __follow_mount_rcu(struct nameidata *nd, struct path *path, | 875 | static int follow_automount(struct path *path, unsigned flags, |
902 | struct inode **inode) | 876 | bool *need_mntput) |
903 | { | 877 | { |
904 | while (d_mountpoint(path->dentry)) { | 878 | struct vfsmount *mnt; |
905 | struct vfsmount *mounted; | 879 | int err; |
906 | mounted = __lookup_mnt(path->mnt, path->dentry, 1); | 880 | |
907 | if (!mounted) | 881 | if (!path->dentry->d_op || !path->dentry->d_op->d_automount) |
908 | return; | 882 | return -EREMOTE; |
909 | path->mnt = mounted; | 883 | |
910 | path->dentry = mounted->mnt_root; | 884 | /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT |
911 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); | 885 | * and this is the terminal part of the path. |
912 | *inode = path->dentry->d_inode; | 886 | */ |
887 | if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE)) | ||
888 | return -EISDIR; /* we actually want to stop here */ | ||
889 | |||
890 | /* We want to mount if someone is trying to open/create a file of any | ||
891 | * type under the mountpoint, wants to traverse through the mountpoint | ||
892 | * or wants to open the mounted directory. | ||
893 | * | ||
894 | * We don't want to mount if someone's just doing a stat and they've | ||
895 | * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and | ||
896 | * appended a '/' to the name. | ||
897 | */ | ||
898 | if (!(flags & LOOKUP_FOLLOW) && | ||
899 | !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | | ||
900 | LOOKUP_OPEN | LOOKUP_CREATE))) | ||
901 | return -EISDIR; | ||
902 | |||
903 | current->total_link_count++; | ||
904 | if (current->total_link_count >= 40) | ||
905 | return -ELOOP; | ||
906 | |||
907 | mnt = path->dentry->d_op->d_automount(path); | ||
908 | if (IS_ERR(mnt)) { | ||
909 | /* | ||
910 | * The filesystem is allowed to return -EISDIR here to indicate | ||
911 | * it doesn't want to automount. For instance, autofs would do | ||
912 | * this so that its userspace daemon can mount on this dentry. | ||
913 | * | ||
914 | * However, we can only permit this if it's a terminal point in | ||
915 | * the path being looked up; if it wasn't then the remainder of | ||
916 | * the path is inaccessible and we should say so. | ||
917 | */ | ||
918 | if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE)) | ||
919 | return -EREMOTE; | ||
920 | return PTR_ERR(mnt); | ||
913 | } | 921 | } |
914 | } | ||
915 | 922 | ||
916 | static int __follow_mount(struct path *path) | 923 | if (!mnt) /* mount collision */ |
917 | { | 924 | return 0; |
918 | int res = 0; | 925 | |
919 | while (d_mountpoint(path->dentry)) { | 926 | /* The new mount record should have at least 2 refs to prevent it being |
920 | struct vfsmount *mounted = lookup_mnt(path); | 927 | * expired before we get a chance to add it |
921 | if (!mounted) | 928 | */ |
922 | break; | 929 | BUG_ON(mnt_get_count(mnt) < 2); |
930 | |||
931 | if (mnt->mnt_sb == path->mnt->mnt_sb && | ||
932 | mnt->mnt_root == path->dentry) { | ||
933 | mnt_clear_expiry(mnt); | ||
934 | mntput(mnt); | ||
935 | mntput(mnt); | ||
936 | return -ELOOP; | ||
937 | } | ||
938 | |||
939 | /* We need to add the mountpoint to the parent. The filesystem may | ||
940 | * have placed it on an expiry list, and so we need to make sure it | ||
941 | * won't be expired under us if do_add_mount() fails (do_add_mount() | ||
942 | * will eat a reference unconditionally). | ||
943 | */ | ||
944 | mntget(mnt); | ||
945 | err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE); | ||
946 | switch (err) { | ||
947 | case -EBUSY: | ||
948 | /* Someone else made a mount here whilst we were busy */ | ||
949 | err = 0; | ||
950 | default: | ||
951 | mnt_clear_expiry(mnt); | ||
952 | mntput(mnt); | ||
953 | mntput(mnt); | ||
954 | return err; | ||
955 | case 0: | ||
956 | mntput(mnt); | ||
923 | dput(path->dentry); | 957 | dput(path->dentry); |
924 | if (res) | 958 | if (*need_mntput) |
925 | mntput(path->mnt); | 959 | mntput(path->mnt); |
926 | path->mnt = mounted; | 960 | path->mnt = mnt; |
927 | path->dentry = dget(mounted->mnt_root); | 961 | path->dentry = dget(mnt->mnt_root); |
928 | res = 1; | 962 | *need_mntput = true; |
963 | return 0; | ||
929 | } | 964 | } |
930 | return res; | ||
931 | } | 965 | } |
932 | 966 | ||
933 | static void follow_mount(struct path *path) | 967 | /* |
968 | * Handle a dentry that is managed in some way. | ||
969 | * - Flagged for transit management (autofs) | ||
970 | * - Flagged as mountpoint | ||
971 | * - Flagged as automount point | ||
972 | * | ||
973 | * This may only be called in refwalk mode. | ||
974 | * | ||
975 | * Serialization is taken care of in namespace.c | ||
976 | */ | ||
977 | static int follow_managed(struct path *path, unsigned flags) | ||
934 | { | 978 | { |
935 | while (d_mountpoint(path->dentry)) { | 979 | unsigned managed; |
936 | struct vfsmount *mounted = lookup_mnt(path); | 980 | bool need_mntput = false; |
937 | if (!mounted) | 981 | int ret; |
938 | break; | 982 | |
939 | dput(path->dentry); | 983 | /* Given that we're not holding a lock here, we retain the value in a |
940 | mntput(path->mnt); | 984 | * local variable for each dentry as we look at it so that we don't see |
941 | path->mnt = mounted; | 985 | * the components of that value change under us */ |
942 | path->dentry = dget(mounted->mnt_root); | 986 | while (managed = ACCESS_ONCE(path->dentry->d_flags), |
987 | managed &= DCACHE_MANAGED_DENTRY, | ||
988 | unlikely(managed != 0)) { | ||
989 | /* Allow the filesystem to manage the transit without i_mutex | ||
990 | * being held. */ | ||
991 | if (managed & DCACHE_MANAGE_TRANSIT) { | ||
992 | BUG_ON(!path->dentry->d_op); | ||
993 | BUG_ON(!path->dentry->d_op->d_manage); | ||
994 | ret = path->dentry->d_op->d_manage(path->dentry, | ||
995 | false, false); | ||
996 | if (ret < 0) | ||
997 | return ret == -EISDIR ? 0 : ret; | ||
998 | } | ||
999 | |||
1000 | /* Transit to a mounted filesystem. */ | ||
1001 | if (managed & DCACHE_MOUNTED) { | ||
1002 | struct vfsmount *mounted = lookup_mnt(path); | ||
1003 | if (mounted) { | ||
1004 | dput(path->dentry); | ||
1005 | if (need_mntput) | ||
1006 | mntput(path->mnt); | ||
1007 | path->mnt = mounted; | ||
1008 | path->dentry = dget(mounted->mnt_root); | ||
1009 | need_mntput = true; | ||
1010 | continue; | ||
1011 | } | ||
1012 | |||
1013 | /* Something is mounted on this dentry in another | ||
1014 | * namespace and/or whatever was mounted there in this | ||
1015 | * namespace got unmounted before we managed to get the | ||
1016 | * vfsmount_lock */ | ||
1017 | } | ||
1018 | |||
1019 | /* Handle an automount point */ | ||
1020 | if (managed & DCACHE_NEED_AUTOMOUNT) { | ||
1021 | ret = follow_automount(path, flags, &need_mntput); | ||
1022 | if (ret < 0) | ||
1023 | return ret == -EISDIR ? 0 : ret; | ||
1024 | continue; | ||
1025 | } | ||
1026 | |||
1027 | /* We didn't change the current path point */ | ||
1028 | break; | ||
943 | } | 1029 | } |
1030 | return 0; | ||
944 | } | 1031 | } |
945 | 1032 | ||
946 | int follow_down(struct path *path) | 1033 | int follow_down_one(struct path *path) |
947 | { | 1034 | { |
948 | struct vfsmount *mounted; | 1035 | struct vfsmount *mounted; |
949 | 1036 | ||
@@ -958,13 +1045,41 @@ int follow_down(struct path *path) | |||
958 | return 0; | 1045 | return 0; |
959 | } | 1046 | } |
960 | 1047 | ||
1048 | /* | ||
1049 | * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we | ||
1050 | * meet a managed dentry and we're not walking to "..". True is returned to | ||
1051 | * continue, false to abort. | ||
1052 | */ | ||
1053 | static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | ||
1054 | struct inode **inode, bool reverse_transit) | ||
1055 | { | ||
1056 | while (d_mountpoint(path->dentry)) { | ||
1057 | struct vfsmount *mounted; | ||
1058 | if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) && | ||
1059 | !reverse_transit && | ||
1060 | path->dentry->d_op->d_manage(path->dentry, false, true) < 0) | ||
1061 | return false; | ||
1062 | mounted = __lookup_mnt(path->mnt, path->dentry, 1); | ||
1063 | if (!mounted) | ||
1064 | break; | ||
1065 | path->mnt = mounted; | ||
1066 | path->dentry = mounted->mnt_root; | ||
1067 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); | ||
1068 | *inode = path->dentry->d_inode; | ||
1069 | } | ||
1070 | |||
1071 | if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | ||
1072 | return reverse_transit; | ||
1073 | return true; | ||
1074 | } | ||
1075 | |||
961 | static int follow_dotdot_rcu(struct nameidata *nd) | 1076 | static int follow_dotdot_rcu(struct nameidata *nd) |
962 | { | 1077 | { |
963 | struct inode *inode = nd->inode; | 1078 | struct inode *inode = nd->inode; |
964 | 1079 | ||
965 | set_root_rcu(nd); | 1080 | set_root_rcu(nd); |
966 | 1081 | ||
967 | while(1) { | 1082 | while (1) { |
968 | if (nd->path.dentry == nd->root.dentry && | 1083 | if (nd->path.dentry == nd->root.dentry && |
969 | nd->path.mnt == nd->root.mnt) { | 1084 | nd->path.mnt == nd->root.mnt) { |
970 | break; | 1085 | break; |
@@ -987,12 +1102,80 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
987 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1102 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
988 | inode = nd->path.dentry->d_inode; | 1103 | inode = nd->path.dentry->d_inode; |
989 | } | 1104 | } |
990 | __follow_mount_rcu(nd, &nd->path, &inode); | 1105 | __follow_mount_rcu(nd, &nd->path, &inode, true); |
991 | nd->inode = inode; | 1106 | nd->inode = inode; |
992 | 1107 | ||
993 | return 0; | 1108 | return 0; |
994 | } | 1109 | } |
995 | 1110 | ||
1111 | /* | ||
1112 | * Follow down to the covering mount currently visible to userspace. At each | ||
1113 | * point, the filesystem owning that dentry may be queried as to whether the | ||
1114 | * caller is permitted to proceed or not. | ||
1115 | * | ||
1116 | * Care must be taken as namespace_sem may be held (indicated by mounting_here | ||
1117 | * being true). | ||
1118 | */ | ||
1119 | int follow_down(struct path *path, bool mounting_here) | ||
1120 | { | ||
1121 | unsigned managed; | ||
1122 | int ret; | ||
1123 | |||
1124 | while (managed = ACCESS_ONCE(path->dentry->d_flags), | ||
1125 | unlikely(managed & DCACHE_MANAGED_DENTRY)) { | ||
1126 | /* Allow the filesystem to manage the transit without i_mutex | ||
1127 | * being held. | ||
1128 | * | ||
1129 | * We indicate to the filesystem if someone is trying to mount | ||
1130 | * something here. This gives autofs the chance to deny anyone | ||
1131 | * other than its daemon the right to mount on its | ||
1132 | * superstructure. | ||
1133 | * | ||
1134 | * The filesystem may sleep at this point. | ||
1135 | */ | ||
1136 | if (managed & DCACHE_MANAGE_TRANSIT) { | ||
1137 | BUG_ON(!path->dentry->d_op); | ||
1138 | BUG_ON(!path->dentry->d_op->d_manage); | ||
1139 | ret = path->dentry->d_op->d_manage( | ||
1140 | path->dentry, mounting_here, false); | ||
1141 | if (ret < 0) | ||
1142 | return ret == -EISDIR ? 0 : ret; | ||
1143 | } | ||
1144 | |||
1145 | /* Transit to a mounted filesystem. */ | ||
1146 | if (managed & DCACHE_MOUNTED) { | ||
1147 | struct vfsmount *mounted = lookup_mnt(path); | ||
1148 | if (!mounted) | ||
1149 | break; | ||
1150 | dput(path->dentry); | ||
1151 | mntput(path->mnt); | ||
1152 | path->mnt = mounted; | ||
1153 | path->dentry = dget(mounted->mnt_root); | ||
1154 | continue; | ||
1155 | } | ||
1156 | |||
1157 | /* Don't handle automount points here */ | ||
1158 | break; | ||
1159 | } | ||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() | ||
1165 | */ | ||
1166 | static void follow_mount(struct path *path) | ||
1167 | { | ||
1168 | while (d_mountpoint(path->dentry)) { | ||
1169 | struct vfsmount *mounted = lookup_mnt(path); | ||
1170 | if (!mounted) | ||
1171 | break; | ||
1172 | dput(path->dentry); | ||
1173 | mntput(path->mnt); | ||
1174 | path->mnt = mounted; | ||
1175 | path->dentry = dget(mounted->mnt_root); | ||
1176 | } | ||
1177 | } | ||
1178 | |||
996 | static void follow_dotdot(struct nameidata *nd) | 1179 | static void follow_dotdot(struct nameidata *nd) |
997 | { | 1180 | { |
998 | set_root(nd); | 1181 | set_root(nd); |
@@ -1057,12 +1240,14 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1057 | struct vfsmount *mnt = nd->path.mnt; | 1240 | struct vfsmount *mnt = nd->path.mnt; |
1058 | struct dentry *dentry, *parent = nd->path.dentry; | 1241 | struct dentry *dentry, *parent = nd->path.dentry; |
1059 | struct inode *dir; | 1242 | struct inode *dir; |
1243 | int err; | ||
1244 | |||
1060 | /* | 1245 | /* |
1061 | * See if the low-level filesystem might want | 1246 | * See if the low-level filesystem might want |
1062 | * to use its own hash.. | 1247 | * to use its own hash.. |
1063 | */ | 1248 | */ |
1064 | if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { | 1249 | if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { |
1065 | int err = parent->d_op->d_hash(parent, nd->inode, name); | 1250 | err = parent->d_op->d_hash(parent, nd->inode, name); |
1066 | if (err < 0) | 1251 | if (err < 0) |
1067 | return err; | 1252 | return err; |
1068 | } | 1253 | } |
@@ -1089,22 +1274,28 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1089 | nd->seq = seq; | 1274 | nd->seq = seq; |
1090 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | 1275 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) |
1091 | goto need_revalidate; | 1276 | goto need_revalidate; |
1277 | done2: | ||
1092 | path->mnt = mnt; | 1278 | path->mnt = mnt; |
1093 | path->dentry = dentry; | 1279 | path->dentry = dentry; |
1094 | __follow_mount_rcu(nd, path, inode); | 1280 | if (likely(__follow_mount_rcu(nd, path, inode, false))) |
1095 | } else { | 1281 | return 0; |
1096 | dentry = __d_lookup(parent, name); | 1282 | if (nameidata_drop_rcu(nd)) |
1097 | if (!dentry) | 1283 | return -ECHILD; |
1098 | goto need_lookup; | 1284 | /* fallthru */ |
1285 | } | ||
1286 | dentry = __d_lookup(parent, name); | ||
1287 | if (!dentry) | ||
1288 | goto need_lookup; | ||
1099 | found: | 1289 | found: |
1100 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | 1290 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) |
1101 | goto need_revalidate; | 1291 | goto need_revalidate; |
1102 | done: | 1292 | done: |
1103 | path->mnt = mnt; | 1293 | path->mnt = mnt; |
1104 | path->dentry = dentry; | 1294 | path->dentry = dentry; |
1105 | __follow_mount(path); | 1295 | err = follow_managed(path, nd->flags); |
1106 | *inode = path->dentry->d_inode; | 1296 | if (unlikely(err < 0)) |
1107 | } | 1297 | return err; |
1298 | *inode = path->dentry->d_inode; | ||
1108 | return 0; | 1299 | return 0; |
1109 | 1300 | ||
1110 | need_lookup: | 1301 | need_lookup: |
@@ -1143,6 +1334,8 @@ need_revalidate: | |||
1143 | goto need_lookup; | 1334 | goto need_lookup; |
1144 | if (IS_ERR(dentry)) | 1335 | if (IS_ERR(dentry)) |
1145 | goto fail; | 1336 | goto fail; |
1337 | if (nd->flags & LOOKUP_RCU) | ||
1338 | goto done2; | ||
1146 | goto done; | 1339 | goto done; |
1147 | 1340 | ||
1148 | fail: | 1341 | fail: |
@@ -1150,17 +1343,6 @@ fail: | |||
1150 | } | 1343 | } |
1151 | 1344 | ||
1152 | /* | 1345 | /* |
1153 | * This is a temporary kludge to deal with "automount" symlinks; proper | ||
1154 | * solution is to trigger them on follow_mount(), so that do_lookup() | ||
1155 | * would DTRT. To be killed before 2.6.34-final. | ||
1156 | */ | ||
1157 | static inline int follow_on_final(struct inode *inode, unsigned lookup_flags) | ||
1158 | { | ||
1159 | return inode && unlikely(inode->i_op->follow_link) && | ||
1160 | ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode)); | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * Name resolution. | 1346 | * Name resolution. |
1165 | * This is the basic name resolution function, turning a pathname into | 1347 | * This is the basic name resolution function, turning a pathname into |
1166 | * the final dentry. We expect 'base' to be positive and a directory. | 1348 | * the final dentry. We expect 'base' to be positive and a directory. |
@@ -1298,7 +1480,8 @@ last_component: | |||
1298 | err = do_lookup(nd, &this, &next, &inode); | 1480 | err = do_lookup(nd, &this, &next, &inode); |
1299 | if (err) | 1481 | if (err) |
1300 | break; | 1482 | break; |
1301 | if (follow_on_final(inode, lookup_flags)) { | 1483 | if (inode && unlikely(inode->i_op->follow_link) && |
1484 | (lookup_flags & LOOKUP_FOLLOW)) { | ||
1302 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | 1485 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) |
1303 | return -ECHILD; | 1486 | return -ECHILD; |
1304 | BUG_ON(inode != next.dentry->d_inode); | 1487 | BUG_ON(inode != next.dentry->d_inode); |
@@ -2200,11 +2383,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2200 | if (open_flag & O_EXCL) | 2383 | if (open_flag & O_EXCL) |
2201 | goto exit_dput; | 2384 | goto exit_dput; |
2202 | 2385 | ||
2203 | if (__follow_mount(path)) { | 2386 | error = follow_managed(path, nd->flags); |
2204 | error = -ELOOP; | 2387 | if (error < 0) |
2205 | if (open_flag & O_NOFOLLOW) | 2388 | goto exit_dput; |
2206 | goto exit_dput; | ||
2207 | } | ||
2208 | 2389 | ||
2209 | error = -ENOENT; | 2390 | error = -ENOENT; |
2210 | if (!path->dentry->d_inode) | 2391 | if (!path->dentry->d_inode) |
@@ -2353,8 +2534,7 @@ reval: | |||
2353 | struct inode *linki = link.dentry->d_inode; | 2534 | struct inode *linki = link.dentry->d_inode; |
2354 | void *cookie; | 2535 | void *cookie; |
2355 | error = -ELOOP; | 2536 | error = -ELOOP; |
2356 | /* S_ISDIR part is a temporary automount kludge */ | 2537 | if (!(nd.flags & LOOKUP_FOLLOW)) |
2357 | if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(linki->i_mode)) | ||
2358 | goto exit_dput; | 2538 | goto exit_dput; |
2359 | if (count++ == 32) | 2539 | if (count++ == 32) |
2360 | goto exit_dput; | 2540 | goto exit_dput; |
@@ -3413,6 +3593,7 @@ const struct inode_operations page_symlink_inode_operations = { | |||
3413 | }; | 3593 | }; |
3414 | 3594 | ||
3415 | EXPORT_SYMBOL(user_path_at); | 3595 | EXPORT_SYMBOL(user_path_at); |
3596 | EXPORT_SYMBOL(follow_down_one); | ||
3416 | EXPORT_SYMBOL(follow_down); | 3597 | EXPORT_SYMBOL(follow_down); |
3417 | EXPORT_SYMBOL(follow_up); | 3598 | EXPORT_SYMBOL(follow_up); |
3418 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ | 3599 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ |
diff --git a/fs/namespace.c b/fs/namespace.c index 3ddfd9046c44..48809e21f270 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -183,7 +183,7 @@ static inline void mnt_dec_count(struct vfsmount *mnt) | |||
183 | unsigned int mnt_get_count(struct vfsmount *mnt) | 183 | unsigned int mnt_get_count(struct vfsmount *mnt) |
184 | { | 184 | { |
185 | #ifdef CONFIG_SMP | 185 | #ifdef CONFIG_SMP |
186 | unsigned int count = atomic_read(&mnt->mnt_longrefs); | 186 | unsigned int count = 0; |
187 | int cpu; | 187 | int cpu; |
188 | 188 | ||
189 | for_each_possible_cpu(cpu) { | 189 | for_each_possible_cpu(cpu) { |
@@ -217,7 +217,7 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
217 | if (!mnt->mnt_pcp) | 217 | if (!mnt->mnt_pcp) |
218 | goto out_free_devname; | 218 | goto out_free_devname; |
219 | 219 | ||
220 | atomic_set(&mnt->mnt_longrefs, 1); | 220 | this_cpu_add(mnt->mnt_pcp->mnt_count, 1); |
221 | #else | 221 | #else |
222 | mnt->mnt_count = 1; | 222 | mnt->mnt_count = 1; |
223 | mnt->mnt_writers = 0; | 223 | mnt->mnt_writers = 0; |
@@ -624,8 +624,11 @@ static void commit_tree(struct vfsmount *mnt) | |||
624 | BUG_ON(parent == mnt); | 624 | BUG_ON(parent == mnt); |
625 | 625 | ||
626 | list_add_tail(&head, &mnt->mnt_list); | 626 | list_add_tail(&head, &mnt->mnt_list); |
627 | list_for_each_entry(m, &head, mnt_list) | 627 | list_for_each_entry(m, &head, mnt_list) { |
628 | m->mnt_ns = n; | 628 | m->mnt_ns = n; |
629 | atomic_inc(&m->mnt_longterm); | ||
630 | } | ||
631 | |||
629 | list_splice(&head, n->list.prev); | 632 | list_splice(&head, n->list.prev); |
630 | 633 | ||
631 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 634 | list_add_tail(&mnt->mnt_hash, mount_hashtable + |
@@ -734,51 +737,30 @@ static inline void mntfree(struct vfsmount *mnt) | |||
734 | deactivate_super(sb); | 737 | deactivate_super(sb); |
735 | } | 738 | } |
736 | 739 | ||
737 | #ifdef CONFIG_SMP | 740 | static void mntput_no_expire(struct vfsmount *mnt) |
738 | static inline void __mntput(struct vfsmount *mnt, int longrefs) | ||
739 | { | 741 | { |
740 | if (!longrefs) { | ||
741 | put_again: | 742 | put_again: |
742 | br_read_lock(vfsmount_lock); | 743 | #ifdef CONFIG_SMP |
743 | if (likely(atomic_read(&mnt->mnt_longrefs))) { | 744 | br_read_lock(vfsmount_lock); |
744 | mnt_dec_count(mnt); | 745 | if (likely(atomic_read(&mnt->mnt_longterm))) { |
745 | br_read_unlock(vfsmount_lock); | 746 | mnt_dec_count(mnt); |
746 | return; | ||
747 | } | ||
748 | br_read_unlock(vfsmount_lock); | 747 | br_read_unlock(vfsmount_lock); |
749 | } else { | 748 | return; |
750 | BUG_ON(!atomic_read(&mnt->mnt_longrefs)); | ||
751 | if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1)) | ||
752 | return; | ||
753 | } | 749 | } |
750 | br_read_unlock(vfsmount_lock); | ||
754 | 751 | ||
755 | br_write_lock(vfsmount_lock); | 752 | br_write_lock(vfsmount_lock); |
756 | if (!longrefs) | 753 | mnt_dec_count(mnt); |
757 | mnt_dec_count(mnt); | ||
758 | else | ||
759 | atomic_dec(&mnt->mnt_longrefs); | ||
760 | if (mnt_get_count(mnt)) { | 754 | if (mnt_get_count(mnt)) { |
761 | br_write_unlock(vfsmount_lock); | 755 | br_write_unlock(vfsmount_lock); |
762 | return; | 756 | return; |
763 | } | 757 | } |
764 | if (unlikely(mnt->mnt_pinned)) { | ||
765 | mnt_add_count(mnt, mnt->mnt_pinned + 1); | ||
766 | mnt->mnt_pinned = 0; | ||
767 | br_write_unlock(vfsmount_lock); | ||
768 | acct_auto_close_mnt(mnt); | ||
769 | goto put_again; | ||
770 | } | ||
771 | br_write_unlock(vfsmount_lock); | ||
772 | mntfree(mnt); | ||
773 | } | ||
774 | #else | 758 | #else |
775 | static inline void __mntput(struct vfsmount *mnt, int longrefs) | ||
776 | { | ||
777 | put_again: | ||
778 | mnt_dec_count(mnt); | 759 | mnt_dec_count(mnt); |
779 | if (likely(mnt_get_count(mnt))) | 760 | if (likely(mnt_get_count(mnt))) |
780 | return; | 761 | return; |
781 | br_write_lock(vfsmount_lock); | 762 | br_write_lock(vfsmount_lock); |
763 | #endif | ||
782 | if (unlikely(mnt->mnt_pinned)) { | 764 | if (unlikely(mnt->mnt_pinned)) { |
783 | mnt_add_count(mnt, mnt->mnt_pinned + 1); | 765 | mnt_add_count(mnt, mnt->mnt_pinned + 1); |
784 | mnt->mnt_pinned = 0; | 766 | mnt->mnt_pinned = 0; |
@@ -789,12 +771,6 @@ put_again: | |||
789 | br_write_unlock(vfsmount_lock); | 771 | br_write_unlock(vfsmount_lock); |
790 | mntfree(mnt); | 772 | mntfree(mnt); |
791 | } | 773 | } |
792 | #endif | ||
793 | |||
794 | static void mntput_no_expire(struct vfsmount *mnt) | ||
795 | { | ||
796 | __mntput(mnt, 0); | ||
797 | } | ||
798 | 774 | ||
799 | void mntput(struct vfsmount *mnt) | 775 | void mntput(struct vfsmount *mnt) |
800 | { | 776 | { |
@@ -802,7 +778,7 @@ void mntput(struct vfsmount *mnt) | |||
802 | /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ | 778 | /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ |
803 | if (unlikely(mnt->mnt_expiry_mark)) | 779 | if (unlikely(mnt->mnt_expiry_mark)) |
804 | mnt->mnt_expiry_mark = 0; | 780 | mnt->mnt_expiry_mark = 0; |
805 | __mntput(mnt, 0); | 781 | mntput_no_expire(mnt); |
806 | } | 782 | } |
807 | } | 783 | } |
808 | EXPORT_SYMBOL(mntput); | 784 | EXPORT_SYMBOL(mntput); |
@@ -815,33 +791,6 @@ struct vfsmount *mntget(struct vfsmount *mnt) | |||
815 | } | 791 | } |
816 | EXPORT_SYMBOL(mntget); | 792 | EXPORT_SYMBOL(mntget); |
817 | 793 | ||
818 | void mntput_long(struct vfsmount *mnt) | ||
819 | { | ||
820 | #ifdef CONFIG_SMP | ||
821 | if (mnt) { | ||
822 | /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ | ||
823 | if (unlikely(mnt->mnt_expiry_mark)) | ||
824 | mnt->mnt_expiry_mark = 0; | ||
825 | __mntput(mnt, 1); | ||
826 | } | ||
827 | #else | ||
828 | mntput(mnt); | ||
829 | #endif | ||
830 | } | ||
831 | EXPORT_SYMBOL(mntput_long); | ||
832 | |||
833 | struct vfsmount *mntget_long(struct vfsmount *mnt) | ||
834 | { | ||
835 | #ifdef CONFIG_SMP | ||
836 | if (mnt) | ||
837 | atomic_inc(&mnt->mnt_longrefs); | ||
838 | return mnt; | ||
839 | #else | ||
840 | return mntget(mnt); | ||
841 | #endif | ||
842 | } | ||
843 | EXPORT_SYMBOL(mntget_long); | ||
844 | |||
845 | void mnt_pin(struct vfsmount *mnt) | 794 | void mnt_pin(struct vfsmount *mnt) |
846 | { | 795 | { |
847 | br_write_lock(vfsmount_lock); | 796 | br_write_lock(vfsmount_lock); |
@@ -1216,7 +1165,7 @@ void release_mounts(struct list_head *head) | |||
1216 | dput(dentry); | 1165 | dput(dentry); |
1217 | mntput(m); | 1166 | mntput(m); |
1218 | } | 1167 | } |
1219 | mntput_long(mnt); | 1168 | mntput(mnt); |
1220 | } | 1169 | } |
1221 | } | 1170 | } |
1222 | 1171 | ||
@@ -1226,19 +1175,21 @@ void release_mounts(struct list_head *head) | |||
1226 | */ | 1175 | */ |
1227 | void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | 1176 | void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) |
1228 | { | 1177 | { |
1178 | LIST_HEAD(tmp_list); | ||
1229 | struct vfsmount *p; | 1179 | struct vfsmount *p; |
1230 | 1180 | ||
1231 | for (p = mnt; p; p = next_mnt(p, mnt)) | 1181 | for (p = mnt; p; p = next_mnt(p, mnt)) |
1232 | list_move(&p->mnt_hash, kill); | 1182 | list_move(&p->mnt_hash, &tmp_list); |
1233 | 1183 | ||
1234 | if (propagate) | 1184 | if (propagate) |
1235 | propagate_umount(kill); | 1185 | propagate_umount(&tmp_list); |
1236 | 1186 | ||
1237 | list_for_each_entry(p, kill, mnt_hash) { | 1187 | list_for_each_entry(p, &tmp_list, mnt_hash) { |
1238 | list_del_init(&p->mnt_expire); | 1188 | list_del_init(&p->mnt_expire); |
1239 | list_del_init(&p->mnt_list); | 1189 | list_del_init(&p->mnt_list); |
1240 | __touch_mnt_namespace(p->mnt_ns); | 1190 | __touch_mnt_namespace(p->mnt_ns); |
1241 | p->mnt_ns = NULL; | 1191 | p->mnt_ns = NULL; |
1192 | atomic_dec(&p->mnt_longterm); | ||
1242 | list_del_init(&p->mnt_child); | 1193 | list_del_init(&p->mnt_child); |
1243 | if (p->mnt_parent != p) { | 1194 | if (p->mnt_parent != p) { |
1244 | p->mnt_parent->mnt_ghosts++; | 1195 | p->mnt_parent->mnt_ghosts++; |
@@ -1246,6 +1197,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | |||
1246 | } | 1197 | } |
1247 | change_mnt_propagation(p, MS_PRIVATE); | 1198 | change_mnt_propagation(p, MS_PRIVATE); |
1248 | } | 1199 | } |
1200 | list_splice(&tmp_list, kill); | ||
1249 | } | 1201 | } |
1250 | 1202 | ||
1251 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); | 1203 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); |
@@ -1844,9 +1796,10 @@ static int do_move_mount(struct path *path, char *old_name) | |||
1844 | return err; | 1796 | return err; |
1845 | 1797 | ||
1846 | down_write(&namespace_sem); | 1798 | down_write(&namespace_sem); |
1847 | while (d_mountpoint(path->dentry) && | 1799 | err = follow_down(path, true); |
1848 | follow_down(path)) | 1800 | if (err < 0) |
1849 | ; | 1801 | goto out; |
1802 | |||
1850 | err = -EINVAL; | 1803 | err = -EINVAL; |
1851 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) | 1804 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) |
1852 | goto out; | 1805 | goto out; |
@@ -1924,15 +1877,14 @@ static int do_new_mount(struct path *path, char *type, int flags, | |||
1924 | if (IS_ERR(mnt)) | 1877 | if (IS_ERR(mnt)) |
1925 | return PTR_ERR(mnt); | 1878 | return PTR_ERR(mnt); |
1926 | 1879 | ||
1927 | return do_add_mount(mnt, path, mnt_flags, NULL); | 1880 | return do_add_mount(mnt, path, mnt_flags); |
1928 | } | 1881 | } |
1929 | 1882 | ||
1930 | /* | 1883 | /* |
1931 | * add a mount into a namespace's mount tree | 1884 | * add a mount into a namespace's mount tree |
1932 | * - provide the option of adding the new mount to an expiration list | 1885 | * - this unconditionally eats one of the caller's references to newmnt. |
1933 | */ | 1886 | */ |
1934 | int do_add_mount(struct vfsmount *newmnt, struct path *path, | 1887 | int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) |
1935 | int mnt_flags, struct list_head *fslist) | ||
1936 | { | 1888 | { |
1937 | int err; | 1889 | int err; |
1938 | 1890 | ||
@@ -1940,9 +1892,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, | |||
1940 | 1892 | ||
1941 | down_write(&namespace_sem); | 1893 | down_write(&namespace_sem); |
1942 | /* Something was mounted here while we slept */ | 1894 | /* Something was mounted here while we slept */ |
1943 | while (d_mountpoint(path->dentry) && | 1895 | err = follow_down(path, true); |
1944 | follow_down(path)) | 1896 | if (err < 0) |
1945 | ; | 1897 | goto unlock; |
1898 | |||
1946 | err = -EINVAL; | 1899 | err = -EINVAL; |
1947 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) | 1900 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) |
1948 | goto unlock; | 1901 | goto unlock; |
@@ -1961,19 +1914,45 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, | |||
1961 | if ((err = graft_tree(newmnt, path))) | 1914 | if ((err = graft_tree(newmnt, path))) |
1962 | goto unlock; | 1915 | goto unlock; |
1963 | 1916 | ||
1964 | if (fslist) /* add to the specified expiration list */ | ||
1965 | list_add_tail(&newmnt->mnt_expire, fslist); | ||
1966 | |||
1967 | up_write(&namespace_sem); | 1917 | up_write(&namespace_sem); |
1968 | return 0; | 1918 | return 0; |
1969 | 1919 | ||
1970 | unlock: | 1920 | unlock: |
1971 | up_write(&namespace_sem); | 1921 | up_write(&namespace_sem); |
1972 | mntput_long(newmnt); | 1922 | mntput(newmnt); |
1973 | return err; | 1923 | return err; |
1974 | } | 1924 | } |
1975 | 1925 | ||
1976 | EXPORT_SYMBOL_GPL(do_add_mount); | 1926 | /** |
1927 | * mnt_set_expiry - Put a mount on an expiration list | ||
1928 | * @mnt: The mount to list. | ||
1929 | * @expiry_list: The list to add the mount to. | ||
1930 | */ | ||
1931 | void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list) | ||
1932 | { | ||
1933 | down_write(&namespace_sem); | ||
1934 | br_write_lock(vfsmount_lock); | ||
1935 | |||
1936 | list_add_tail(&mnt->mnt_expire, expiry_list); | ||
1937 | |||
1938 | br_write_unlock(vfsmount_lock); | ||
1939 | up_write(&namespace_sem); | ||
1940 | } | ||
1941 | EXPORT_SYMBOL(mnt_set_expiry); | ||
1942 | |||
1943 | /* | ||
1944 | * Remove a vfsmount from any expiration list it may be on | ||
1945 | */ | ||
1946 | void mnt_clear_expiry(struct vfsmount *mnt) | ||
1947 | { | ||
1948 | if (!list_empty(&mnt->mnt_expire)) { | ||
1949 | down_write(&namespace_sem); | ||
1950 | br_write_lock(vfsmount_lock); | ||
1951 | list_del_init(&mnt->mnt_expire); | ||
1952 | br_write_unlock(vfsmount_lock); | ||
1953 | up_write(&namespace_sem); | ||
1954 | } | ||
1955 | } | ||
1977 | 1956 | ||
1978 | /* | 1957 | /* |
1979 | * process a list of expirable mountpoints with the intent of discarding any | 1958 | * process a list of expirable mountpoints with the intent of discarding any |
@@ -2262,6 +2241,20 @@ static struct mnt_namespace *alloc_mnt_ns(void) | |||
2262 | return new_ns; | 2241 | return new_ns; |
2263 | } | 2242 | } |
2264 | 2243 | ||
2244 | void mnt_make_longterm(struct vfsmount *mnt) | ||
2245 | { | ||
2246 | atomic_inc(&mnt->mnt_longterm); | ||
2247 | } | ||
2248 | |||
2249 | void mnt_make_shortterm(struct vfsmount *mnt) | ||
2250 | { | ||
2251 | if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) | ||
2252 | return; | ||
2253 | br_write_lock(vfsmount_lock); | ||
2254 | atomic_dec(&mnt->mnt_longterm); | ||
2255 | br_write_unlock(vfsmount_lock); | ||
2256 | } | ||
2257 | |||
2265 | /* | 2258 | /* |
2266 | * Allocate a new namespace structure and populate it with contents | 2259 | * Allocate a new namespace structure and populate it with contents |
2267 | * copied from the namespace of the passed in task structure. | 2260 | * copied from the namespace of the passed in task structure. |
@@ -2299,14 +2292,19 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2299 | q = new_ns->root; | 2292 | q = new_ns->root; |
2300 | while (p) { | 2293 | while (p) { |
2301 | q->mnt_ns = new_ns; | 2294 | q->mnt_ns = new_ns; |
2295 | atomic_inc(&q->mnt_longterm); | ||
2302 | if (fs) { | 2296 | if (fs) { |
2303 | if (p == fs->root.mnt) { | 2297 | if (p == fs->root.mnt) { |
2298 | fs->root.mnt = mntget(q); | ||
2299 | atomic_inc(&q->mnt_longterm); | ||
2300 | mnt_make_shortterm(p); | ||
2304 | rootmnt = p; | 2301 | rootmnt = p; |
2305 | fs->root.mnt = mntget_long(q); | ||
2306 | } | 2302 | } |
2307 | if (p == fs->pwd.mnt) { | 2303 | if (p == fs->pwd.mnt) { |
2304 | fs->pwd.mnt = mntget(q); | ||
2305 | atomic_inc(&q->mnt_longterm); | ||
2306 | mnt_make_shortterm(p); | ||
2308 | pwdmnt = p; | 2307 | pwdmnt = p; |
2309 | fs->pwd.mnt = mntget_long(q); | ||
2310 | } | 2308 | } |
2311 | } | 2309 | } |
2312 | p = next_mnt(p, mnt_ns->root); | 2310 | p = next_mnt(p, mnt_ns->root); |
@@ -2315,9 +2313,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2315 | up_write(&namespace_sem); | 2313 | up_write(&namespace_sem); |
2316 | 2314 | ||
2317 | if (rootmnt) | 2315 | if (rootmnt) |
2318 | mntput_long(rootmnt); | 2316 | mntput(rootmnt); |
2319 | if (pwdmnt) | 2317 | if (pwdmnt) |
2320 | mntput_long(pwdmnt); | 2318 | mntput(pwdmnt); |
2321 | 2319 | ||
2322 | return new_ns; | 2320 | return new_ns; |
2323 | } | 2321 | } |
@@ -2350,6 +2348,7 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) | |||
2350 | new_ns = alloc_mnt_ns(); | 2348 | new_ns = alloc_mnt_ns(); |
2351 | if (!IS_ERR(new_ns)) { | 2349 | if (!IS_ERR(new_ns)) { |
2352 | mnt->mnt_ns = new_ns; | 2350 | mnt->mnt_ns = new_ns; |
2351 | atomic_inc(&mnt->mnt_longterm); | ||
2353 | new_ns->root = mnt; | 2352 | new_ns->root = mnt; |
2354 | list_add(&new_ns->list, &new_ns->root->mnt_list); | 2353 | list_add(&new_ns->list, &new_ns->root->mnt_list); |
2355 | } | 2354 | } |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index df8c03a02161..2c3eb33b904d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -970,7 +970,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) | |||
970 | { | 970 | { |
971 | struct nfs_server *server = NFS_SERVER(inode); | 971 | struct nfs_server *server = NFS_SERVER(inode); |
972 | 972 | ||
973 | if (test_bit(NFS_INO_MOUNTPOINT, &NFS_I(inode)->flags)) | 973 | if (IS_AUTOMOUNT(inode)) |
974 | return 0; | 974 | return 0; |
975 | if (nd != NULL) { | 975 | if (nd != NULL) { |
976 | /* VFS wants an on-the-wire revalidation */ | 976 | /* VFS wants an on-the-wire revalidation */ |
@@ -1173,6 +1173,7 @@ const struct dentry_operations nfs_dentry_operations = { | |||
1173 | .d_revalidate = nfs_lookup_revalidate, | 1173 | .d_revalidate = nfs_lookup_revalidate, |
1174 | .d_delete = nfs_dentry_delete, | 1174 | .d_delete = nfs_dentry_delete, |
1175 | .d_iput = nfs_dentry_iput, | 1175 | .d_iput = nfs_dentry_iput, |
1176 | .d_automount = nfs_d_automount, | ||
1176 | }; | 1177 | }; |
1177 | 1178 | ||
1178 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 1179 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
@@ -1246,6 +1247,7 @@ const struct dentry_operations nfs4_dentry_operations = { | |||
1246 | .d_revalidate = nfs_open_revalidate, | 1247 | .d_revalidate = nfs_open_revalidate, |
1247 | .d_delete = nfs_dentry_delete, | 1248 | .d_delete = nfs_dentry_delete, |
1248 | .d_iput = nfs_dentry_iput, | 1249 | .d_iput = nfs_dentry_iput, |
1250 | .d_automount = nfs_d_automount, | ||
1249 | }; | 1251 | }; |
1250 | 1252 | ||
1251 | /* | 1253 | /* |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index ce00b704452c..d8512423ba72 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -300,7 +300,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
300 | else | 300 | else |
301 | inode->i_op = &nfs_mountpoint_inode_operations; | 301 | inode->i_op = &nfs_mountpoint_inode_operations; |
302 | inode->i_fop = NULL; | 302 | inode->i_fop = NULL; |
303 | set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags); | 303 | inode->i_flags |= S_AUTOMOUNT; |
304 | } | 304 | } |
305 | } else if (S_ISLNK(inode->i_mode)) | 305 | } else if (S_ISLNK(inode->i_mode)) |
306 | inode->i_op = &nfs_symlink_inode_operations; | 306 | inode->i_op = &nfs_symlink_inode_operations; |
@@ -1208,7 +1208,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1208 | /* Update the fsid? */ | 1208 | /* Update the fsid? */ |
1209 | if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) && | 1209 | if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) && |
1210 | !nfs_fsid_equal(&server->fsid, &fattr->fsid) && | 1210 | !nfs_fsid_equal(&server->fsid, &fattr->fsid) && |
1211 | !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags)) | 1211 | !IS_AUTOMOUNT(inode)) |
1212 | server->fsid = fattr->fsid; | 1212 | server->fsid = fattr->fsid; |
1213 | 1213 | ||
1214 | /* | 1214 | /* |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index bfa3a34af801..4644f04b4b46 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -252,6 +252,7 @@ extern char *nfs_path(const char *base, | |||
252 | const struct dentry *droot, | 252 | const struct dentry *droot, |
253 | const struct dentry *dentry, | 253 | const struct dentry *dentry, |
254 | char *buffer, ssize_t buflen); | 254 | char *buffer, ssize_t buflen); |
255 | extern struct vfsmount *nfs_d_automount(struct path *path); | ||
255 | 256 | ||
256 | /* getroot.c */ | 257 | /* getroot.c */ |
257 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); | 258 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 74aaf3963c10..f32b8603dca8 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -97,9 +97,8 @@ Elong: | |||
97 | } | 97 | } |
98 | 98 | ||
99 | /* | 99 | /* |
100 | * nfs_follow_mountpoint - handle crossing a mountpoint on the server | 100 | * nfs_d_automount - Handle crossing a mountpoint on the server |
101 | * @dentry - dentry of mountpoint | 101 | * @path - The mountpoint |
102 | * @nd - nameidata info | ||
103 | * | 102 | * |
104 | * When we encounter a mountpoint on the server, we want to set up | 103 | * When we encounter a mountpoint on the server, we want to set up |
105 | * a mountpoint on the client too, to prevent inode numbers from | 104 | * a mountpoint on the client too, to prevent inode numbers from |
@@ -109,87 +108,65 @@ Elong: | |||
109 | * situation, and that different filesystems may want to use | 108 | * situation, and that different filesystems may want to use |
110 | * different security flavours. | 109 | * different security flavours. |
111 | */ | 110 | */ |
112 | static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | 111 | struct vfsmount *nfs_d_automount(struct path *path) |
113 | { | 112 | { |
114 | struct vfsmount *mnt; | 113 | struct vfsmount *mnt; |
115 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 114 | struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); |
116 | struct dentry *parent; | 115 | struct dentry *parent; |
117 | struct nfs_fh *fh = NULL; | 116 | struct nfs_fh *fh = NULL; |
118 | struct nfs_fattr *fattr = NULL; | 117 | struct nfs_fattr *fattr = NULL; |
119 | int err; | 118 | int err; |
120 | 119 | ||
121 | dprintk("--> nfs_follow_mountpoint()\n"); | 120 | dprintk("--> nfs_d_automount()\n"); |
122 | 121 | ||
123 | err = -ESTALE; | 122 | mnt = ERR_PTR(-ESTALE); |
124 | if (IS_ROOT(dentry)) | 123 | if (IS_ROOT(path->dentry)) |
125 | goto out_err; | 124 | goto out_nofree; |
126 | 125 | ||
127 | err = -ENOMEM; | 126 | mnt = ERR_PTR(-ENOMEM); |
128 | fh = nfs_alloc_fhandle(); | 127 | fh = nfs_alloc_fhandle(); |
129 | fattr = nfs_alloc_fattr(); | 128 | fattr = nfs_alloc_fattr(); |
130 | if (fh == NULL || fattr == NULL) | 129 | if (fh == NULL || fattr == NULL) |
131 | goto out_err; | 130 | goto out; |
132 | 131 | ||
133 | dprintk("%s: enter\n", __func__); | 132 | dprintk("%s: enter\n", __func__); |
134 | dput(nd->path.dentry); | ||
135 | nd->path.dentry = dget(dentry); | ||
136 | 133 | ||
137 | /* Look it up again */ | 134 | /* Look it up again to get its attributes */ |
138 | parent = dget_parent(nd->path.dentry); | 135 | parent = dget_parent(path->dentry); |
139 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, | 136 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, |
140 | &nd->path.dentry->d_name, | 137 | &path->dentry->d_name, |
141 | fh, fattr); | 138 | fh, fattr); |
142 | dput(parent); | 139 | dput(parent); |
143 | if (err != 0) | 140 | if (err != 0) { |
144 | goto out_err; | 141 | mnt = ERR_PTR(err); |
142 | goto out; | ||
143 | } | ||
145 | 144 | ||
146 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 145 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
147 | mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); | 146 | mnt = nfs_do_refmount(path->mnt, path->dentry); |
148 | else | 147 | else |
149 | mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh, | 148 | mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr); |
150 | fattr); | ||
151 | err = PTR_ERR(mnt); | ||
152 | if (IS_ERR(mnt)) | 149 | if (IS_ERR(mnt)) |
153 | goto out_err; | 150 | goto out; |
154 | 151 | ||
155 | mntget(mnt); | 152 | dprintk("%s: done, success\n", __func__); |
156 | err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, | 153 | mntget(mnt); /* prevent immediate expiration */ |
157 | &nfs_automount_list); | 154 | mnt_set_expiry(mnt, &nfs_automount_list); |
158 | if (err < 0) { | ||
159 | mntput(mnt); | ||
160 | if (err == -EBUSY) | ||
161 | goto out_follow; | ||
162 | goto out_err; | ||
163 | } | ||
164 | path_put(&nd->path); | ||
165 | nd->path.mnt = mnt; | ||
166 | nd->path.dentry = dget(mnt->mnt_root); | ||
167 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | 155 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
156 | |||
168 | out: | 157 | out: |
169 | nfs_free_fattr(fattr); | 158 | nfs_free_fattr(fattr); |
170 | nfs_free_fhandle(fh); | 159 | nfs_free_fhandle(fh); |
171 | dprintk("%s: done, returned %d\n", __func__, err); | 160 | out_nofree: |
172 | 161 | dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt); | |
173 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); | 162 | return mnt; |
174 | return ERR_PTR(err); | ||
175 | out_err: | ||
176 | path_put(&nd->path); | ||
177 | goto out; | ||
178 | out_follow: | ||
179 | while (d_mountpoint(nd->path.dentry) && | ||
180 | follow_down(&nd->path)) | ||
181 | ; | ||
182 | err = 0; | ||
183 | goto out; | ||
184 | } | 163 | } |
185 | 164 | ||
186 | const struct inode_operations nfs_mountpoint_inode_operations = { | 165 | const struct inode_operations nfs_mountpoint_inode_operations = { |
187 | .follow_link = nfs_follow_mountpoint, | ||
188 | .getattr = nfs_getattr, | 166 | .getattr = nfs_getattr, |
189 | }; | 167 | }; |
190 | 168 | ||
191 | const struct inode_operations nfs_referral_inode_operations = { | 169 | const struct inode_operations nfs_referral_inode_operations = { |
192 | .follow_link = nfs_follow_mountpoint, | ||
193 | }; | 170 | }; |
194 | 171 | ||
195 | static void nfs_expire_automounts(struct work_struct *work) | 172 | static void nfs_expire_automounts(struct work_struct *work) |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a3c7f701395a..641117f2188d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -87,8 +87,9 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
87 | .dentry = dget(dentry)}; | 87 | .dentry = dget(dentry)}; |
88 | int err = 0; | 88 | int err = 0; |
89 | 89 | ||
90 | while (d_mountpoint(path.dentry) && follow_down(&path)) | 90 | err = follow_down(&path, false); |
91 | ; | 91 | if (err < 0) |
92 | goto out; | ||
92 | 93 | ||
93 | exp2 = rqst_exp_get_by_name(rqstp, &path); | 94 | exp2 = rqst_exp_get_by_name(rqstp, &path); |
94 | if (IS_ERR(exp2)) { | 95 | if (IS_ERR(exp2)) { |
@@ -1292,7 +1292,7 @@ static int __init init_pipe_fs(void) | |||
1292 | static void __exit exit_pipe_fs(void) | 1292 | static void __exit exit_pipe_fs(void) |
1293 | { | 1293 | { |
1294 | unregister_filesystem(&pipe_fs_type); | 1294 | unregister_filesystem(&pipe_fs_type); |
1295 | mntput_long(pipe_mnt); | 1295 | mntput(pipe_mnt); |
1296 | } | 1296 | } |
1297 | 1297 | ||
1298 | fs_initcall(init_pipe_fs); | 1298 | fs_initcall(init_pipe_fs); |
@@ -75,11 +75,13 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, | |||
75 | int error = -EINVAL; | 75 | int error = -EINVAL; |
76 | int lookup_flags = 0; | 76 | int lookup_flags = 0; |
77 | 77 | ||
78 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | 78 | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0) |
79 | goto out; | 79 | goto out; |
80 | 80 | ||
81 | if (!(flag & AT_SYMLINK_NOFOLLOW)) | 81 | if (!(flag & AT_SYMLINK_NOFOLLOW)) |
82 | lookup_flags |= LOOKUP_FOLLOW; | 82 | lookup_flags |= LOOKUP_FOLLOW; |
83 | if (flag & AT_NO_AUTOMOUNT) | ||
84 | lookup_flags |= LOOKUP_NO_AUTOMOUNT; | ||
83 | 85 | ||
84 | error = user_path_at(dfd, filename, lookup_flags, &path); | 86 | error = user_path_at(dfd, filename, lookup_flags, &path); |
85 | if (error) | 87 | if (error) |
diff --git a/fs/super.c b/fs/super.c index 4f6a3571a634..74e149efed81 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -1141,7 +1141,7 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) | |||
1141 | return mnt; | 1141 | return mnt; |
1142 | 1142 | ||
1143 | err: | 1143 | err: |
1144 | mntput_long(mnt); | 1144 | mntput(mnt); |
1145 | return ERR_PTR(err); | 1145 | return ERR_PTR(err); |
1146 | } | 1146 | } |
1147 | 1147 | ||
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h index 8b49ac48a5b7..e02982fa2953 100644 --- a/include/linux/auto_fs4.h +++ b/include/linux/auto_fs4.h | |||
@@ -24,7 +24,7 @@ | |||
24 | #define AUTOFS_MIN_PROTO_VERSION 3 | 24 | #define AUTOFS_MIN_PROTO_VERSION 3 |
25 | #define AUTOFS_MAX_PROTO_VERSION 5 | 25 | #define AUTOFS_MAX_PROTO_VERSION 5 |
26 | 26 | ||
27 | #define AUTOFS_PROTO_SUBVERSION 1 | 27 | #define AUTOFS_PROTO_SUBVERSION 2 |
28 | 28 | ||
29 | /* Mask for expire behaviour */ | 29 | /* Mask for expire behaviour */ |
30 | #define AUTOFS_EXP_IMMEDIATE 1 | 30 | #define AUTOFS_EXP_IMMEDIATE 1 |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 59fcd24b1468..f958c19e3ca5 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -167,6 +167,8 @@ struct dentry_operations { | |||
167 | void (*d_release)(struct dentry *); | 167 | void (*d_release)(struct dentry *); |
168 | void (*d_iput)(struct dentry *, struct inode *); | 168 | void (*d_iput)(struct dentry *, struct inode *); |
169 | char *(*d_dname)(struct dentry *, char *, int); | 169 | char *(*d_dname)(struct dentry *, char *, int); |
170 | struct vfsmount *(*d_automount)(struct path *); | ||
171 | int (*d_manage)(struct dentry *, bool, bool); | ||
170 | } ____cacheline_aligned; | 172 | } ____cacheline_aligned; |
171 | 173 | ||
172 | /* | 174 | /* |
@@ -205,13 +207,18 @@ struct dentry_operations { | |||
205 | 207 | ||
206 | #define DCACHE_CANT_MOUNT 0x0100 | 208 | #define DCACHE_CANT_MOUNT 0x0100 |
207 | #define DCACHE_GENOCIDE 0x0200 | 209 | #define DCACHE_GENOCIDE 0x0200 |
208 | #define DCACHE_MOUNTED 0x0400 /* is a mountpoint */ | ||
209 | 210 | ||
210 | #define DCACHE_OP_HASH 0x1000 | 211 | #define DCACHE_OP_HASH 0x1000 |
211 | #define DCACHE_OP_COMPARE 0x2000 | 212 | #define DCACHE_OP_COMPARE 0x2000 |
212 | #define DCACHE_OP_REVALIDATE 0x4000 | 213 | #define DCACHE_OP_REVALIDATE 0x4000 |
213 | #define DCACHE_OP_DELETE 0x8000 | 214 | #define DCACHE_OP_DELETE 0x8000 |
214 | 215 | ||
216 | #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ | ||
217 | #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ | ||
218 | #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ | ||
219 | #define DCACHE_MANAGED_DENTRY \ | ||
220 | (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) | ||
221 | |||
215 | extern seqlock_t rename_lock; | 222 | extern seqlock_t rename_lock; |
216 | 223 | ||
217 | static inline int dname_external(struct dentry *dentry) | 224 | static inline int dname_external(struct dentry *dentry) |
@@ -399,7 +406,12 @@ static inline void dont_mount(struct dentry *dentry) | |||
399 | 406 | ||
400 | extern void dput(struct dentry *); | 407 | extern void dput(struct dentry *); |
401 | 408 | ||
402 | static inline int d_mountpoint(struct dentry *dentry) | 409 | static inline bool d_managed(struct dentry *dentry) |
410 | { | ||
411 | return dentry->d_flags & DCACHE_MANAGED_DENTRY; | ||
412 | } | ||
413 | |||
414 | static inline bool d_mountpoint(struct dentry *dentry) | ||
403 | { | 415 | { |
404 | return dentry->d_flags & DCACHE_MOUNTED; | 416 | return dentry->d_flags & DCACHE_MOUNTED; |
405 | } | 417 | } |
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index afc00af3229b..a562fa5fb4e3 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h | |||
@@ -45,6 +45,7 @@ | |||
45 | #define AT_REMOVEDIR 0x200 /* Remove directory instead of | 45 | #define AT_REMOVEDIR 0x200 /* Remove directory instead of |
46 | unlinking file. */ | 46 | unlinking file. */ |
47 | #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ | 47 | #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ |
48 | #define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ | ||
48 | 49 | ||
49 | #ifdef __KERNEL__ | 50 | #ifdef __KERNEL__ |
50 | 51 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 08824e0ef381..177b4ddea418 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -242,6 +242,7 @@ struct inodes_stat_t { | |||
242 | #define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */ | 242 | #define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */ |
243 | #define S_PRIVATE 512 /* Inode is fs-internal */ | 243 | #define S_PRIVATE 512 /* Inode is fs-internal */ |
244 | #define S_IMA 1024 /* Inode has an associated IMA struct */ | 244 | #define S_IMA 1024 /* Inode has an associated IMA struct */ |
245 | #define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */ | ||
245 | 246 | ||
246 | /* | 247 | /* |
247 | * Note that nosuid etc flags are inode-specific: setting some file-system | 248 | * Note that nosuid etc flags are inode-specific: setting some file-system |
@@ -277,6 +278,7 @@ struct inodes_stat_t { | |||
277 | #define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE) | 278 | #define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE) |
278 | #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) | 279 | #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) |
279 | #define IS_IMA(inode) ((inode)->i_flags & S_IMA) | 280 | #define IS_IMA(inode) ((inode)->i_flags & S_IMA) |
281 | #define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT) | ||
280 | 282 | ||
281 | /* the read-only stuff doesn't really belong here, but any other place is | 283 | /* the read-only stuff doesn't really belong here, but any other place is |
282 | probably as bad and I don't want to create yet another include file. */ | 284 | probably as bad and I don't want to create yet another include file. */ |
diff --git a/include/linux/mount.h b/include/linux/mount.h index 1869ea24a739..604f122a2326 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -60,7 +60,7 @@ struct vfsmount { | |||
60 | struct super_block *mnt_sb; /* pointer to superblock */ | 60 | struct super_block *mnt_sb; /* pointer to superblock */ |
61 | #ifdef CONFIG_SMP | 61 | #ifdef CONFIG_SMP |
62 | struct mnt_pcp __percpu *mnt_pcp; | 62 | struct mnt_pcp __percpu *mnt_pcp; |
63 | atomic_t mnt_longrefs; | 63 | atomic_t mnt_longterm; /* how many of the refs are longterm */ |
64 | #else | 64 | #else |
65 | int mnt_count; | 65 | int mnt_count; |
66 | int mnt_writers; | 66 | int mnt_writers; |
@@ -96,8 +96,6 @@ extern int mnt_clone_write(struct vfsmount *mnt); | |||
96 | extern void mnt_drop_write(struct vfsmount *mnt); | 96 | extern void mnt_drop_write(struct vfsmount *mnt); |
97 | extern void mntput(struct vfsmount *mnt); | 97 | extern void mntput(struct vfsmount *mnt); |
98 | extern struct vfsmount *mntget(struct vfsmount *mnt); | 98 | extern struct vfsmount *mntget(struct vfsmount *mnt); |
99 | extern void mntput_long(struct vfsmount *mnt); | ||
100 | extern struct vfsmount *mntget_long(struct vfsmount *mnt); | ||
101 | extern void mnt_pin(struct vfsmount *mnt); | 99 | extern void mnt_pin(struct vfsmount *mnt); |
102 | extern void mnt_unpin(struct vfsmount *mnt); | 100 | extern void mnt_unpin(struct vfsmount *mnt); |
103 | extern int __mnt_is_readonly(struct vfsmount *mnt); | 101 | extern int __mnt_is_readonly(struct vfsmount *mnt); |
@@ -110,12 +108,7 @@ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, | |||
110 | int flags, const char *name, | 108 | int flags, const char *name, |
111 | void *data); | 109 | void *data); |
112 | 110 | ||
113 | struct nameidata; | 111 | extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list); |
114 | |||
115 | struct path; | ||
116 | extern int do_add_mount(struct vfsmount *newmnt, struct path *path, | ||
117 | int mnt_flags, struct list_head *fslist); | ||
118 | |||
119 | extern void mark_mounts_for_expiry(struct list_head *mounts); | 112 | extern void mark_mounts_for_expiry(struct list_head *mounts); |
120 | 113 | ||
121 | extern dev_t name_to_dev_t(char *name); | 114 | extern dev_t name_to_dev_t(char *name); |
diff --git a/include/linux/namei.h b/include/linux/namei.h index 18d06add0a40..f276d4fa01fc 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
@@ -45,6 +45,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | |||
45 | * - ending slashes ok even for nonexistent files | 45 | * - ending slashes ok even for nonexistent files |
46 | * - internal "there are more path components" flag | 46 | * - internal "there are more path components" flag |
47 | * - dentry cache is untrusted; force a real lookup | 47 | * - dentry cache is untrusted; force a real lookup |
48 | * - suppress terminal automount | ||
48 | */ | 49 | */ |
49 | #define LOOKUP_FOLLOW 0x0001 | 50 | #define LOOKUP_FOLLOW 0x0001 |
50 | #define LOOKUP_DIRECTORY 0x0002 | 51 | #define LOOKUP_DIRECTORY 0x0002 |
@@ -53,6 +54,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | |||
53 | #define LOOKUP_PARENT 0x0010 | 54 | #define LOOKUP_PARENT 0x0010 |
54 | #define LOOKUP_REVAL 0x0020 | 55 | #define LOOKUP_REVAL 0x0020 |
55 | #define LOOKUP_RCU 0x0040 | 56 | #define LOOKUP_RCU 0x0040 |
57 | #define LOOKUP_NO_AUTOMOUNT 0x0080 | ||
56 | /* | 58 | /* |
57 | * Intent data | 59 | * Intent data |
58 | */ | 60 | */ |
@@ -79,7 +81,8 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry | |||
79 | 81 | ||
80 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); | 82 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); |
81 | 83 | ||
82 | extern int follow_down(struct path *); | 84 | extern int follow_down_one(struct path *); |
85 | extern int follow_down(struct path *, bool); | ||
83 | extern int follow_up(struct path *); | 86 | extern int follow_up(struct path *); |
84 | 87 | ||
85 | extern struct dentry *lock_rename(struct dentry *, struct dentry *); | 88 | extern struct dentry *lock_rename(struct dentry *, struct dentry *); |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0779bb8f95be..6023efa9f5d9 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -215,7 +215,6 @@ struct nfs_inode { | |||
215 | #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ | 215 | #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ |
216 | #define NFS_INO_STALE (1) /* possible stale inode */ | 216 | #define NFS_INO_STALE (1) /* possible stale inode */ |
217 | #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ | 217 | #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ |
218 | #define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */ | ||
219 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ | 218 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ |
220 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ | 219 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
221 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ | 220 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |
diff --git a/include/linux/path.h b/include/linux/path.h index a581e8c06533..edc98dec6266 100644 --- a/include/linux/path.h +++ b/include/linux/path.h | |||
@@ -10,9 +10,7 @@ struct path { | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | extern void path_get(struct path *); | 12 | extern void path_get(struct path *); |
13 | extern void path_get_long(struct path *); | ||
14 | extern void path_put(struct path *); | 13 | extern void path_put(struct path *); |
15 | extern void path_put_long(struct path *); | ||
16 | 14 | ||
17 | static inline int path_equal(const struct path *path1, const struct path *path2) | 15 | static inline int path_equal(const struct path *path1, const struct path *path2) |
18 | { | 16 | { |