diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2012-04-27 13:27:41 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-27 14:10:02 -0400 |
commit | f05d147f7e3cf0d86b3a4bd5603029a7cb109633 (patch) | |
tree | e351ef7dd3d541626f5cccef86f50906bfb3a649 /fs | |
parent | 72de53ec4bca39c26709122a8f78bfefe7b6bca4 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/internal.h | 4 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 44 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 40 |
5 files changed, 72 insertions, 26 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 45966d953169..49c09b4a535a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -186,10 +186,10 @@ static inline void nfs_fs_proc_exit(void) | |||
186 | 186 | ||
187 | /* nfs4namespace.c */ | 187 | /* nfs4namespace.c */ |
188 | #ifdef CONFIG_NFS_V4 | 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 | #else | 190 | #else |
191 | static inline | 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 | return ERR_PTR(-ENOENT); | 194 | return ERR_PTR(-ENOENT); |
195 | } | 195 | } |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 1807866bb3ab..b9a593d056b3 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -200,6 +200,22 @@ out_shutdown: | |||
200 | out: | 200 | out: |
201 | return err; | 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 | #else /* CONFIG_NFS_V4 */ | 219 | #else /* CONFIG_NFS_V4 */ |
204 | static inline int nfs_lookup_with_sec(struct nfs_server *server, | 220 | static inline int nfs_lookup_with_sec(struct nfs_server *server, |
205 | struct dentry *parent, struct dentry *dentry, | 221 | struct dentry *parent, struct dentry *dentry, |
@@ -209,6 +225,17 @@ static inline int nfs_lookup_with_sec(struct nfs_server *server, | |||
209 | { | 225 | { |
210 | return -EPERM; | 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 | #endif /* CONFIG_NFS_V4 */ | 239 | #endif /* CONFIG_NFS_V4 */ |
213 | 240 | ||
214 | /* | 241 | /* |
@@ -226,11 +253,10 @@ static inline int nfs_lookup_with_sec(struct nfs_server *server, | |||
226 | struct vfsmount *nfs_d_automount(struct path *path) | 253 | struct vfsmount *nfs_d_automount(struct path *path) |
227 | { | 254 | { |
228 | struct vfsmount *mnt; | 255 | struct vfsmount *mnt; |
229 | struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); | ||
230 | struct dentry *parent; | 256 | struct dentry *parent; |
231 | struct nfs_fh *fh = NULL; | 257 | struct nfs_fh *fh = NULL; |
232 | struct nfs_fattr *fattr = NULL; | 258 | struct nfs_fattr *fattr = NULL; |
233 | int err; | 259 | struct rpc_clnt *client; |
234 | rpc_authflavor_t flavor = RPC_AUTH_UNIX; | 260 | rpc_authflavor_t flavor = RPC_AUTH_UNIX; |
235 | 261 | ||
236 | dprintk("--> nfs_d_automount()\n"); | 262 | dprintk("--> nfs_d_automount()\n"); |
@@ -249,21 +275,19 @@ struct vfsmount *nfs_d_automount(struct path *path) | |||
249 | 275 | ||
250 | /* Look it up again to get its attributes */ | 276 | /* Look it up again to get its attributes */ |
251 | parent = dget_parent(path->dentry); | 277 | parent = dget_parent(path->dentry); |
252 | err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, | 278 | client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr); |
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); | ||
257 | dput(parent); | 279 | dput(parent); |
258 | if (err != 0) { | 280 | if (IS_ERR(client)) { |
259 | mnt = ERR_PTR(err); | 281 | mnt = ERR_CAST(client); |
260 | goto out; | 282 | goto out; |
261 | } | 283 | } |
262 | 284 | ||
263 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 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 | else | 287 | else |
266 | mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); | 288 | mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); |
289 | rpc_shutdown_client(client); | ||
290 | |||
267 | if (IS_ERR(mnt)) | 291 | if (IS_ERR(mnt)) |
268 | goto out; | 292 | goto out; |
269 | 293 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c82c2cda3dfd..8d75021020b3 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -216,8 +216,10 @@ extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | |||
216 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); | 216 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); |
217 | extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); | 217 | extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); |
218 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 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, | 219 | extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, |
220 | struct nfs4_fs_locations *fs_locations, struct page *page); | 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 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 223 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
222 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); | 224 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); |
223 | extern const struct xattr_handler *nfs4_xattr_handlers[]; | 225 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 9f8681bf90de..a7f3dedc4ec7 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -300,7 +300,7 @@ out: | |||
300 | * @dentry - dentry of referral | 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 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); | 305 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
306 | struct dentry *parent; | 306 | struct dentry *parent; |
@@ -326,7 +326,7 @@ struct vfsmount *nfs_do_refmount(struct dentry *dentry) | |||
326 | dprintk("%s: getting locations for %s/%s\n", | 326 | dprintk("%s: getting locations for %s/%s\n", |
327 | __func__, parent->d_name.name, dentry->d_name.name); | 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 | dput(parent); | 330 | dput(parent); |
331 | if (err != 0 || | 331 | if (err != 0 || |
332 | fs_locations->nlocations <= 0 || | 332 | fs_locations->nlocations <= 0 || |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3d92fe6be780..75eb883ed4ce 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2377,8 +2377,9 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2377 | * Note that we'll actually follow the referral later when | 2377 | * Note that we'll actually follow the referral later when |
2378 | * we detect fsid mismatch in inode revalidation | 2378 | * we detect fsid mismatch in inode revalidation |
2379 | */ | 2379 | */ |
2380 | static int nfs4_get_referral(struct inode *dir, const struct qstr *name, | 2380 | static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir, |
2381 | struct nfs_fattr *fattr, struct nfs_fh *fhandle) | 2381 | const struct qstr *name, struct nfs_fattr *fattr, |
2382 | struct nfs_fh *fhandle) | ||
2382 | { | 2383 | { |
2383 | int status = -ENOMEM; | 2384 | int status = -ENOMEM; |
2384 | struct page *page = NULL; | 2385 | struct page *page = NULL; |
@@ -2391,7 +2392,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, | |||
2391 | if (locations == NULL) | 2392 | if (locations == NULL) |
2392 | goto out; | 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 | if (status != 0) | 2396 | if (status != 0) |
2396 | goto out; | 2397 | goto out; |
2397 | /* Make sure server returned a different fsid for the referral */ | 2398 | /* Make sure server returned a different fsid for the referral */ |
@@ -2550,7 +2551,7 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, | |||
2550 | err = -ENOENT; | 2551 | err = -ENOENT; |
2551 | goto out; | 2552 | goto out; |
2552 | case -NFS4ERR_MOVED: | 2553 | case -NFS4ERR_MOVED: |
2553 | err = nfs4_get_referral(dir, name, fattr, fhandle); | 2554 | err = nfs4_get_referral(client, dir, name, fattr, fhandle); |
2554 | goto out; | 2555 | goto out; |
2555 | case -NFS4ERR_WRONGSEC: | 2556 | case -NFS4ERR_WRONGSEC: |
2556 | err = -EPERM; | 2557 | err = -EPERM; |
@@ -2591,6 +2592,21 @@ static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qst | |||
2591 | return status; | 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 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 2610 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
2595 | { | 2611 | { |
2596 | struct nfs_server *server = NFS_SERVER(inode); | 2612 | struct nfs_server *server = NFS_SERVER(inode); |
@@ -4951,8 +4967,10 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr) | |||
4951 | fattr->nlink = 2; | 4967 | fattr->nlink = 2; |
4952 | } | 4968 | } |
4953 | 4969 | ||
4954 | static int _nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 4970 | static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, |
4955 | struct nfs4_fs_locations *fs_locations, struct page *page) | 4971 | const struct qstr *name, |
4972 | struct nfs4_fs_locations *fs_locations, | ||
4973 | struct page *page) | ||
4956 | { | 4974 | { |
4957 | struct nfs_server *server = NFS_SERVER(dir); | 4975 | struct nfs_server *server = NFS_SERVER(dir); |
4958 | u32 bitmask[2] = { | 4976 | u32 bitmask[2] = { |
@@ -4986,19 +5004,21 @@ static int _nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4986 | nfs_fattr_init(&fs_locations->fattr); | 5004 | nfs_fattr_init(&fs_locations->fattr); |
4987 | fs_locations->server = server; | 5005 | fs_locations->server = server; |
4988 | fs_locations->nlocations = 0; | 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 | dprintk("%s: returned status = %d\n", __func__, status); | 5008 | dprintk("%s: returned status = %d\n", __func__, status); |
4991 | return status; | 5009 | return status; |
4992 | } | 5010 | } |
4993 | 5011 | ||
4994 | int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 5012 | int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, |
4995 | struct nfs4_fs_locations *fs_locations, struct page *page) | 5013 | const struct qstr *name, |
5014 | struct nfs4_fs_locations *fs_locations, | ||
5015 | struct page *page) | ||
4996 | { | 5016 | { |
4997 | struct nfs4_exception exception = { }; | 5017 | struct nfs4_exception exception = { }; |
4998 | int err; | 5018 | int err; |
4999 | do { | 5019 | do { |
5000 | err = nfs4_handle_exception(NFS_SERVER(dir), | 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 | &exception); | 5022 | &exception); |
5003 | } while (exception.retry); | 5023 | } while (exception.retry); |
5004 | return err; | 5024 | return err; |