aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2012-09-14 17:24:02 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-10-01 18:33:33 -0400
commitba9b584c1dc37851d9c6ca6d0d2ccba55d9aad04 (patch)
treed74fa5a04f928d5c508594f285381b41bfe4ac3c
parent1b63a75180c6c65c71655c250a4e6b578ba7d1c0 (diff)
SUNRPC: Introduce rpc_clone_client_set_auth()
An ULP is supposed to be able to replace a GSS rpc_auth object with another GSS rpc_auth object using rpcauth_create(). However, rpcauth_create() in 3.5 reliably fails with -EEXIST in this case. This is because when gss_create() attempts to create the upcall pipes, sometimes they are already there. For example if a pipe FS mount event occurs, or a previous GSS flavor was in use for this rpc_clnt. It turns out that's not the only problem here. While working on a fix for the above problem, we noticed that replacing an rpc_clnt's rpc_auth is not safe, since dereferencing the cl_auth field is not protected in any way. So we're deprecating the ability of rpcauth_create() to switch an rpc_clnt's security flavor during normal operation. Instead, let's add a fresh API that clones an rpc_clnt and gives the clone a new flavor before it's used. This makes immediate use of the new __rpc_clone_client() helper. This can be used in a similar fashion to rpcauth_create() when a client is hunting for the correct security flavor. Instead of replacing an rpc_clnt's security flavor in a loop, the ULP replaces the whole rpc_clnt. To fix the -EEXIST problem, any ULP logic that relies on replacing an rpc_clnt's rpc_auth with rpcauth_create() must be changed to use this API instead. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/client.c13
-rw-r--r--fs/nfs/nfs4namespace.c14
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--net/sunrpc/clnt.c22
4 files changed, 27 insertions, 24 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 99694442b93f..143149db3440 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -668,7 +668,8 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
668{ 668{
669 struct nfs_client *clp = server->nfs_client; 669 struct nfs_client *clp = server->nfs_client;
670 670
671 server->client = rpc_clone_client(clp->cl_rpcclient); 671 server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
672 pseudoflavour);
672 if (IS_ERR(server->client)) { 673 if (IS_ERR(server->client)) {
673 dprintk("%s: couldn't create rpc_client!\n", __func__); 674 dprintk("%s: couldn't create rpc_client!\n", __func__);
674 return PTR_ERR(server->client); 675 return PTR_ERR(server->client);
@@ -678,16 +679,6 @@ int nfs_init_server_rpcclient(struct nfs_server *server,
678 timeo, 679 timeo,
679 sizeof(server->client->cl_timeout_default)); 680 sizeof(server->client->cl_timeout_default));
680 server->client->cl_timeout = &server->client->cl_timeout_default; 681 server->client->cl_timeout = &server->client->cl_timeout_default;
681
682 if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
683 struct rpc_auth *auth;
684
685 auth = rpcauth_create(pseudoflavour, server->client);
686 if (IS_ERR(auth)) {
687 dprintk("%s: couldn't create credcache!\n", __func__);
688 return PTR_ERR(auth);
689 }
690 }
691 server->client->cl_softrtry = 0; 682 server->client->cl_softrtry = 0;
692 if (server->flags & NFS_MOUNT_SOFT) 683 if (server->flags & NFS_MOUNT_SOFT)
693 server->client->cl_softrtry = 1; 684 server->client->cl_softrtry = 1;
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 4fdeb1b7042e..79fbb61ce202 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -192,25 +192,13 @@ out:
192struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode, 192struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode,
193 struct qstr *name) 193 struct qstr *name)
194{ 194{
195 struct rpc_clnt *clone;
196 struct rpc_auth *auth;
197 rpc_authflavor_t flavor; 195 rpc_authflavor_t flavor;
198 196
199 flavor = nfs4_negotiate_security(inode, name); 197 flavor = nfs4_negotiate_security(inode, name);
200 if ((int)flavor < 0) 198 if ((int)flavor < 0)
201 return ERR_PTR((int)flavor); 199 return ERR_PTR((int)flavor);
202 200
203 clone = rpc_clone_client(clnt); 201 return rpc_clone_client_set_auth(clnt, flavor);
204 if (IS_ERR(clone))
205 return clone;
206
207 auth = rpcauth_create(flavor, clone);
208 if (IS_ERR(auth)) {
209 rpc_shutdown_client(clone);
210 clone = ERR_PTR(-EIO);
211 }
212
213 return clone;
214} 202}
215 203
216static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, 204static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 523547ecfee2..34206b84d8da 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -130,6 +130,8 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
130 const struct rpc_program *, u32); 130 const struct rpc_program *, u32);
131void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt); 131void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
132struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); 132struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
133struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *,
134 rpc_authflavor_t);
133void rpc_shutdown_client(struct rpc_clnt *); 135void rpc_shutdown_client(struct rpc_clnt *);
134void rpc_release_client(struct rpc_clnt *); 136void rpc_release_client(struct rpc_clnt *);
135void rpc_task_release_client(struct rpc_task *); 137void rpc_task_release_client(struct rpc_task *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index afbeefab6600..cdc7564b4512 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -548,6 +548,28 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
548} 548}
549EXPORT_SYMBOL_GPL(rpc_clone_client); 549EXPORT_SYMBOL_GPL(rpc_clone_client);
550 550
551/**
552 * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
553 *
554 * @clnt: RPC client whose parameters are copied
555 * @auth: security flavor for new client
556 *
557 * Returns a fresh RPC client or an ERR_PTR.
558 */
559struct rpc_clnt *
560rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
561{
562 struct rpc_create_args args = {
563 .program = clnt->cl_program,
564 .prognumber = clnt->cl_prog,
565 .version = clnt->cl_vers,
566 .authflavor = flavor,
567 .client_name = clnt->cl_principal,
568 };
569 return __rpc_clone_client(&args, clnt);
570}
571EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
572
551/* 573/*
552 * Kill all tasks for the given client. 574 * Kill all tasks for the given client.
553 * XXX: kill their descendants as well? 575 * XXX: kill their descendants as well?