Commit 36d43a43761b004ad1879ac21471d8fc5f3157ec
Committed by
Al Viro
1 parent
d18610b0ce
Exists in
master
and in
4 other branches
NFS: Use d_automount() rather than abusing follow_link()
Make NFS use the new d_automount() dentry operation rather than abusing follow_link() on directories. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Trond Myklebust <Trond.Myklebust@netapp.com> Acked-by: Ian Kent <raven@themaw.net> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 5 changed files with 46 additions and 48 deletions Side-by-side Diff
fs/nfs/dir.c
... | ... | @@ -970,7 +970,7 @@ |
970 | 970 | { |
971 | 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 | 974 | return 0; |
975 | 975 | if (nd != NULL) { |
976 | 976 | /* VFS wants an on-the-wire revalidation */ |
... | ... | @@ -1173,6 +1173,7 @@ |
1173 | 1173 | .d_revalidate = nfs_lookup_revalidate, |
1174 | 1174 | .d_delete = nfs_dentry_delete, |
1175 | 1175 | .d_iput = nfs_dentry_iput, |
1176 | + .d_automount = nfs_d_automount, | |
1176 | 1177 | }; |
1177 | 1178 | |
1178 | 1179 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
... | ... | @@ -1246,6 +1247,7 @@ |
1246 | 1247 | .d_revalidate = nfs_open_revalidate, |
1247 | 1248 | .d_delete = nfs_dentry_delete, |
1248 | 1249 | .d_iput = nfs_dentry_iput, |
1250 | + .d_automount = nfs_d_automount, | |
1249 | 1251 | }; |
1250 | 1252 | |
1251 | 1253 | /* |
fs/nfs/inode.c
... | ... | @@ -300,7 +300,7 @@ |
300 | 300 | else |
301 | 301 | inode->i_op = &nfs_mountpoint_inode_operations; |
302 | 302 | inode->i_fop = NULL; |
303 | - set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags); | |
303 | + inode->i_flags |= S_AUTOMOUNT; | |
304 | 304 | } |
305 | 305 | } else if (S_ISLNK(inode->i_mode)) |
306 | 306 | inode->i_op = &nfs_symlink_inode_operations; |
... | ... | @@ -1208,7 +1208,7 @@ |
1208 | 1208 | /* Update the fsid? */ |
1209 | 1209 | if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) && |
1210 | 1210 | !nfs_fsid_equal(&server->fsid, &fattr->fsid) && |
1211 | - !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags)) | |
1211 | + !IS_AUTOMOUNT(inode)) | |
1212 | 1212 | server->fsid = fattr->fsid; |
1213 | 1213 | |
1214 | 1214 | /* |
fs/nfs/internal.h
... | ... | @@ -252,6 +252,7 @@ |
252 | 252 | const struct dentry *droot, |
253 | 253 | const struct dentry *dentry, |
254 | 254 | char *buffer, ssize_t buflen); |
255 | +extern struct vfsmount *nfs_d_automount(struct path *path); | |
255 | 256 | |
256 | 257 | /* getroot.c */ |
257 | 258 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); |
fs/nfs/namespace.c
... | ... | @@ -97,9 +97,8 @@ |
97 | 97 | } |
98 | 98 | |
99 | 99 | /* |
100 | - * nfs_follow_mountpoint - handle crossing a mountpoint on the server | |
101 | - * @dentry - dentry of mountpoint | |
102 | - * @nd - nameidata info | |
100 | + * nfs_d_automount - Handle crossing a mountpoint on the server | |
101 | + * @path - The mountpoint | |
103 | 102 | * |
104 | 103 | * When we encounter a mountpoint on the server, we want to set up |
105 | 104 | * a mountpoint on the client too, to prevent inode numbers from |
106 | 105 | |
107 | 106 | |
108 | 107 | |
109 | 108 | |
110 | 109 | |
111 | 110 | |
112 | 111 | |
113 | 112 | |
114 | 113 | |
115 | 114 | |
116 | 115 | |
117 | 116 | |
118 | 117 | |
119 | 118 | |
120 | 119 | |
121 | 120 | |
122 | 121 | |
123 | 122 | |
124 | 123 | |
... | ... | @@ -109,84 +108,81 @@ |
109 | 108 | * situation, and that different filesystems may want to use |
110 | 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 | 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 | 115 | struct dentry *parent; |
117 | 116 | struct nfs_fh *fh = NULL; |
118 | 117 | struct nfs_fattr *fattr = NULL; |
119 | 118 | int err; |
120 | 119 | |
121 | - dprintk("--> nfs_follow_mountpoint()\n"); | |
120 | + dprintk("--> nfs_d_automount()\n"); | |
122 | 121 | |
123 | - err = -ESTALE; | |
124 | - if (IS_ROOT(dentry)) | |
125 | - goto out_err; | |
122 | + mnt = ERR_PTR(-ESTALE); | |
123 | + if (IS_ROOT(path->dentry)) | |
124 | + goto out_nofree; | |
126 | 125 | |
127 | - err = -ENOMEM; | |
126 | + mnt = ERR_PTR(-ENOMEM); | |
128 | 127 | fh = nfs_alloc_fhandle(); |
129 | 128 | fattr = nfs_alloc_fattr(); |
130 | 129 | if (fh == NULL || fattr == NULL) |
131 | - goto out_err; | |
130 | + goto out; | |
132 | 131 | |
133 | 132 | dprintk("%s: enter\n", __func__); |
134 | - dput(nd->path.dentry); | |
135 | - nd->path.dentry = dget(dentry); | |
136 | 133 | |
137 | - /* Look it up again */ | |
138 | - parent = dget_parent(nd->path.dentry); | |
134 | + /* Look it up again to get its attributes */ | |
135 | + parent = dget_parent(path->dentry); | |
139 | 136 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, |
140 | - &nd->path.dentry->d_name, | |
137 | + &path->dentry->d_name, | |
141 | 138 | fh, fattr); |
142 | 139 | dput(parent); |
143 | - if (err != 0) | |
144 | - goto out_err; | |
140 | + if (err != 0) { | |
141 | + mnt = ERR_PTR(err); | |
142 | + goto out; | |
143 | + } | |
145 | 144 | |
146 | 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 | 147 | else |
149 | - mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh, | |
150 | - fattr); | |
151 | - err = PTR_ERR(mnt); | |
148 | + mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr); | |
152 | 149 | if (IS_ERR(mnt)) |
153 | - goto out_err; | |
150 | + goto out; | |
154 | 151 | |
155 | 152 | mntget(mnt); |
156 | - err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, | |
153 | + err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE, | |
157 | 154 | &nfs_automount_list); |
158 | - if (err < 0) { | |
155 | + switch (err) { | |
156 | + case 0: | |
157 | + dprintk("%s: done, success\n", __func__); | |
158 | + schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | |
159 | + break; | |
160 | + case -EBUSY: | |
161 | + /* someone else made a mount here whilst we were busy */ | |
159 | 162 | mntput(mnt); |
160 | - if (err == -EBUSY) | |
161 | - goto out_follow; | |
162 | - goto out_err; | |
163 | + dprintk("%s: done, collision\n", __func__); | |
164 | + mnt = NULL; | |
165 | + break; | |
166 | + default: | |
167 | + mntput(mnt); | |
168 | + dprintk("%s: done, error %d\n", __func__, err); | |
169 | + mnt = ERR_PTR(err); | |
170 | + break; | |
163 | 171 | } |
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); | |
172 | + | |
168 | 173 | out: |
169 | 174 | nfs_free_fattr(fattr); |
170 | 175 | nfs_free_fhandle(fh); |
171 | - dprintk("%s: done, returned %d\n", __func__, err); | |
172 | - | |
173 | - dprintk("<-- nfs_follow_mountpoint() = %d\n", err); | |
174 | - return ERR_PTR(err); | |
175 | -out_err: | |
176 | - path_put(&nd->path); | |
177 | - goto out; | |
178 | -out_follow: | |
179 | - err = follow_down(&nd->path, false); | |
180 | - goto out; | |
176 | +out_nofree: | |
177 | + dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt); | |
178 | + return mnt; | |
181 | 179 | } |
182 | 180 | |
183 | 181 | const struct inode_operations nfs_mountpoint_inode_operations = { |
184 | - .follow_link = nfs_follow_mountpoint, | |
185 | 182 | .getattr = nfs_getattr, |
186 | 183 | }; |
187 | 184 | |
188 | 185 | const struct inode_operations nfs_referral_inode_operations = { |
189 | - .follow_link = nfs_follow_mountpoint, | |
190 | 186 | }; |
191 | 187 | |
192 | 188 | static void nfs_expire_automounts(struct work_struct *work) |
include/linux/nfs_fs.h
... | ... | @@ -215,7 +215,6 @@ |
215 | 215 | #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ |
216 | 216 | #define NFS_INO_STALE (1) /* possible stale inode */ |
217 | 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 | 218 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ |
220 | 219 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
221 | 220 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |