aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorBryan Schumaker <bjschuma@netapp.com>2012-04-27 13:27:41 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-04-27 14:10:02 -0400
commitf05d147f7e3cf0d86b3a4bd5603029a7cb109633 (patch)
treee351ef7dd3d541626f5cccef86f50906bfb3a649 /fs/nfs
parent72de53ec4bca39c26709122a8f78bfefe7b6bca4 (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/nfs')
-rw-r--r--fs/nfs/internal.h4
-rw-r--r--fs/nfs/namespace.c44
-rw-r--r--fs/nfs/nfs4_fs.h6
-rw-r--r--fs/nfs/nfs4namespace.c4
-rw-r--r--fs/nfs/nfs4proc.c40
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
189extern struct vfsmount *nfs_do_refmount(struct dentry *dentry); 189extern struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry);
190#else 190#else
191static inline 191static inline
192struct vfsmount *nfs_do_refmount(struct dentry *dentry) 192struct 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:
200out: 200out:
201 return err; 201 return err;
202} 202}
203
204static 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 */
204static inline int nfs_lookup_with_sec(struct nfs_server *server, 220static 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
229static 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,
226struct vfsmount *nfs_d_automount(struct path *path) 253struct 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 *);
216extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); 216extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
217extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); 217extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc);
218extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); 218extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
219extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, 219extern 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 *);
221extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
222 struct nfs_fh *, struct nfs_fattr *);
221extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); 223extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
222extern int nfs4_release_lockowner(struct nfs4_lock_state *); 224extern int nfs4_release_lockowner(struct nfs4_lock_state *);
223extern const struct xattr_handler *nfs4_xattr_handlers[]; 225extern 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 */
303struct vfsmount *nfs_do_refmount(struct dentry *dentry) 303struct 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 */
2380static int nfs4_get_referral(struct inode *dir, const struct qstr *name, 2380static 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
2595struct rpc_clnt *
2596nfs4_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
2594static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) 2610static 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
4954static int _nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, 4970static 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
4994int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, 5012int 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;