Commit f05d147f7e3cf0d86b3a4bd5603029a7cb109633
Committed by
Trond Myklebust
1 parent
72de53ec4b
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
NFS: Fix following referral mount points with different security
I create a new proc_lookup_mountpoint() to use when submounting an NFS v4 share. This function returns an rpc_clnt to use for performing an fs_locations() call on a referral's mountpoint. Signed-off-by: Bryan Schumaker <bjschuma@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 5 changed files with 72 additions and 26 deletions Side-by-side Diff
fs/nfs/internal.h
... | ... | @@ -186,10 +186,10 @@ |
186 | 186 | |
187 | 187 | /* nfs4namespace.c */ |
188 | 188 | #ifdef CONFIG_NFS_V4 |
189 | -extern struct vfsmount *nfs_do_refmount(struct dentry *dentry); | |
189 | +extern struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry); | |
190 | 190 | #else |
191 | 191 | static inline |
192 | -struct vfsmount *nfs_do_refmount(struct dentry *dentry) | |
192 | +struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) | |
193 | 193 | { |
194 | 194 | return ERR_PTR(-ENOENT); |
195 | 195 | } |
fs/nfs/namespace.c
... | ... | @@ -200,6 +200,22 @@ |
200 | 200 | out: |
201 | 201 | return err; |
202 | 202 | } |
203 | + | |
204 | +static struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir, | |
205 | + struct qstr *name, | |
206 | + struct nfs_fh *fh, | |
207 | + struct nfs_fattr *fattr) | |
208 | +{ | |
209 | + int err; | |
210 | + | |
211 | + if (NFS_PROTO(dir)->version == 4) | |
212 | + return nfs4_proc_lookup_mountpoint(dir, name, fh, fattr); | |
213 | + | |
214 | + err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr); | |
215 | + if (err) | |
216 | + return ERR_PTR(err); | |
217 | + return rpc_clone_client(NFS_SERVER(dir)->client); | |
218 | +} | |
203 | 219 | #else /* CONFIG_NFS_V4 */ |
204 | 220 | static inline int nfs_lookup_with_sec(struct nfs_server *server, |
205 | 221 | struct dentry *parent, struct dentry *dentry, |
... | ... | @@ -209,6 +225,17 @@ |
209 | 225 | { |
210 | 226 | return -EPERM; |
211 | 227 | } |
228 | + | |
229 | +static inline struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir, | |
230 | + struct qstr *name, | |
231 | + struct nfs_fh *fh, | |
232 | + struct nfs_fattr *fattr) | |
233 | +{ | |
234 | + int err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr); | |
235 | + if (err) | |
236 | + return ERR_PTR(err); | |
237 | + return rpc_clone_client(NFS_SERVER(dir)->client); | |
238 | +} | |
212 | 239 | #endif /* CONFIG_NFS_V4 */ |
213 | 240 | |
214 | 241 | /* |
215 | 242 | |
... | ... | @@ -226,11 +253,10 @@ |
226 | 253 | struct vfsmount *nfs_d_automount(struct path *path) |
227 | 254 | { |
228 | 255 | struct vfsmount *mnt; |
229 | - struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); | |
230 | 256 | struct dentry *parent; |
231 | 257 | struct nfs_fh *fh = NULL; |
232 | 258 | struct nfs_fattr *fattr = NULL; |
233 | - int err; | |
259 | + struct rpc_clnt *client; | |
234 | 260 | rpc_authflavor_t flavor = RPC_AUTH_UNIX; |
235 | 261 | |
236 | 262 | dprintk("--> nfs_d_automount()\n"); |
237 | 263 | |
238 | 264 | |
239 | 265 | |
... | ... | @@ -249,21 +275,19 @@ |
249 | 275 | |
250 | 276 | /* Look it up again to get its attributes */ |
251 | 277 | parent = dget_parent(path->dentry); |
252 | - err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, | |
253 | - &path->dentry->d_name, | |
254 | - fh, fattr); | |
255 | - if (err == -EPERM && NFS_PROTO(parent->d_inode)->secinfo != NULL) | |
256 | - err = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr, &flavor); | |
278 | + client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr); | |
257 | 279 | dput(parent); |
258 | - if (err != 0) { | |
259 | - mnt = ERR_PTR(err); | |
280 | + if (IS_ERR(client)) { | |
281 | + mnt = ERR_CAST(client); | |
260 | 282 | goto out; |
261 | 283 | } |
262 | 284 | |
263 | 285 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
264 | - mnt = nfs_do_refmount(path->dentry); | |
286 | + mnt = nfs_do_refmount(client, path->dentry); | |
265 | 287 | else |
266 | 288 | mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); |
289 | + rpc_shutdown_client(client); | |
290 | + | |
267 | 291 | if (IS_ERR(mnt)) |
268 | 292 | goto out; |
269 | 293 |
fs/nfs/nfs4_fs.h
... | ... | @@ -216,8 +216,10 @@ |
216 | 216 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); |
217 | 217 | extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); |
218 | 218 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
219 | -extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |
220 | - struct nfs4_fs_locations *fs_locations, struct page *page); | |
219 | +extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, | |
220 | + struct nfs4_fs_locations *, struct page *); | |
221 | +extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, | |
222 | + struct nfs_fh *, struct nfs_fattr *); | |
221 | 223 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
222 | 224 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); |
223 | 225 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
fs/nfs/nfs4namespace.c
... | ... | @@ -300,7 +300,7 @@ |
300 | 300 | * @dentry - dentry of referral |
301 | 301 | * |
302 | 302 | */ |
303 | -struct vfsmount *nfs_do_refmount(struct dentry *dentry) | |
303 | +struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) | |
304 | 304 | { |
305 | 305 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
306 | 306 | struct dentry *parent; |
... | ... | @@ -326,7 +326,7 @@ |
326 | 326 | dprintk("%s: getting locations for %s/%s\n", |
327 | 327 | __func__, parent->d_name.name, dentry->d_name.name); |
328 | 328 | |
329 | - err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); | |
329 | + err = nfs4_proc_fs_locations(client, parent->d_inode, &dentry->d_name, fs_locations, page); | |
330 | 330 | dput(parent); |
331 | 331 | if (err != 0 || |
332 | 332 | fs_locations->nlocations <= 0 || |
fs/nfs/nfs4proc.c
... | ... | @@ -2377,8 +2377,9 @@ |
2377 | 2377 | * Note that we'll actually follow the referral later when |
2378 | 2378 | * we detect fsid mismatch in inode revalidation |
2379 | 2379 | */ |
2380 | -static int nfs4_get_referral(struct inode *dir, const struct qstr *name, | |
2381 | - struct nfs_fattr *fattr, struct nfs_fh *fhandle) | |
2380 | +static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir, | |
2381 | + const struct qstr *name, struct nfs_fattr *fattr, | |
2382 | + struct nfs_fh *fhandle) | |
2382 | 2383 | { |
2383 | 2384 | int status = -ENOMEM; |
2384 | 2385 | struct page *page = NULL; |
... | ... | @@ -2391,7 +2392,7 @@ |
2391 | 2392 | if (locations == NULL) |
2392 | 2393 | goto out; |
2393 | 2394 | |
2394 | - status = nfs4_proc_fs_locations(dir, name, locations, page); | |
2395 | + status = nfs4_proc_fs_locations(client, dir, name, locations, page); | |
2395 | 2396 | if (status != 0) |
2396 | 2397 | goto out; |
2397 | 2398 | /* Make sure server returned a different fsid for the referral */ |
... | ... | @@ -2550,7 +2551,7 @@ |
2550 | 2551 | err = -ENOENT; |
2551 | 2552 | goto out; |
2552 | 2553 | case -NFS4ERR_MOVED: |
2553 | - err = nfs4_get_referral(dir, name, fattr, fhandle); | |
2554 | + err = nfs4_get_referral(client, dir, name, fattr, fhandle); | |
2554 | 2555 | goto out; |
2555 | 2556 | case -NFS4ERR_WRONGSEC: |
2556 | 2557 | err = -EPERM; |
... | ... | @@ -2591,6 +2592,21 @@ |
2591 | 2592 | return status; |
2592 | 2593 | } |
2593 | 2594 | |
2595 | +struct rpc_clnt * | |
2596 | +nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, | |
2597 | + struct nfs_fh *fhandle, struct nfs_fattr *fattr) | |
2598 | +{ | |
2599 | + int status; | |
2600 | + struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir)); | |
2601 | + | |
2602 | + status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); | |
2603 | + if (status < 0) { | |
2604 | + rpc_shutdown_client(client); | |
2605 | + return ERR_PTR(status); | |
2606 | + } | |
2607 | + return client; | |
2608 | +} | |
2609 | + | |
2594 | 2610 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
2595 | 2611 | { |
2596 | 2612 | struct nfs_server *server = NFS_SERVER(inode); |
... | ... | @@ -4951,8 +4967,10 @@ |
4951 | 4967 | fattr->nlink = 2; |
4952 | 4968 | } |
4953 | 4969 | |
4954 | -static int _nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |
4955 | - struct nfs4_fs_locations *fs_locations, struct page *page) | |
4970 | +static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, | |
4971 | + const struct qstr *name, | |
4972 | + struct nfs4_fs_locations *fs_locations, | |
4973 | + struct page *page) | |
4956 | 4974 | { |
4957 | 4975 | struct nfs_server *server = NFS_SERVER(dir); |
4958 | 4976 | u32 bitmask[2] = { |
4959 | 4977 | |
4960 | 4978 | |
... | ... | @@ -4986,19 +5004,21 @@ |
4986 | 5004 | nfs_fattr_init(&fs_locations->fattr); |
4987 | 5005 | fs_locations->server = server; |
4988 | 5006 | fs_locations->nlocations = 0; |
4989 | - status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | |
5007 | + status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0); | |
4990 | 5008 | dprintk("%s: returned status = %d\n", __func__, status); |
4991 | 5009 | return status; |
4992 | 5010 | } |
4993 | 5011 | |
4994 | -int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |
4995 | - struct nfs4_fs_locations *fs_locations, struct page *page) | |
5012 | +int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, | |
5013 | + const struct qstr *name, | |
5014 | + struct nfs4_fs_locations *fs_locations, | |
5015 | + struct page *page) | |
4996 | 5016 | { |
4997 | 5017 | struct nfs4_exception exception = { }; |
4998 | 5018 | int err; |
4999 | 5019 | do { |
5000 | 5020 | err = nfs4_handle_exception(NFS_SERVER(dir), |
5001 | - _nfs4_proc_fs_locations(dir, name, fs_locations, page), | |
5021 | + _nfs4_proc_fs_locations(client, dir, name, fs_locations, page), | |
5002 | 5022 | &exception); |
5003 | 5023 | } while (exception.retry); |
5004 | 5024 | return err; |