diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2012-09-14 17:24:02 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-10-01 18:33:33 -0400 |
commit | ba9b584c1dc37851d9c6ca6d0d2ccba55d9aad04 (patch) | |
tree | d74fa5a04f928d5c508594f285381b41bfe4ac3c | |
parent | 1b63a75180c6c65c71655c250a4e6b578ba7d1c0 (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.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 14 | ||||
-rw-r--r-- | include/linux/sunrpc/clnt.h | 2 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 22 |
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: | |||
192 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode, | 192 | struct 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 | ||
216 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | 204 | static 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); |
131 | void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt); | 131 | void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt); |
132 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | 132 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); |
133 | struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *, | ||
134 | rpc_authflavor_t); | ||
133 | void rpc_shutdown_client(struct rpc_clnt *); | 135 | void rpc_shutdown_client(struct rpc_clnt *); |
134 | void rpc_release_client(struct rpc_clnt *); | 136 | void rpc_release_client(struct rpc_clnt *); |
135 | void rpc_task_release_client(struct rpc_task *); | 137 | void 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 | } |
549 | EXPORT_SYMBOL_GPL(rpc_clone_client); | 549 | EXPORT_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 | */ | ||
559 | struct rpc_clnt * | ||
560 | rpc_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 | } | ||
571 | EXPORT_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? |