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 | { |
