From patchwork Mon May 9 19:36:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever III X-Patchwork-Id: 770382 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p49JZt5v031503 for ; Mon, 9 May 2011 19:36:54 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754111Ab1EITgy (ORCPT ); Mon, 9 May 2011 15:36:54 -0400 Received: from mail-yi0-f46.google.com ([209.85.218.46]:50715 "EHLO mail-yi0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754072Ab1EITgx (ORCPT ); Mon, 9 May 2011 15:36:53 -0400 Received: by yia27 with SMTP id 27so1915432yia.19 for ; Mon, 09 May 2011 12:36:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:subject:to:cc:date:message-id :in-reply-to:references:user-agent:mime-version:content-type :content-transfer-encoding; bh=BCjhR983Kur5ft5po9clJbkP6zXwl9dw4dvyjPoHUH0=; b=Hv5cgN5MFBYNsSIV+7ISD3b1tD+5MwJ+KM8WMx6fwvWkiXH2tSKYPPMBLsKZExilQk PwGWyTOBCY0/j9XXhE5bBSr9+QXl4FSzm5BYeUrvrbzfdCWyTNb47eU2h67lHIW31w7S MYGMthX+nAQuqEUqXyFGzK4zLxSfsgZ0kroxQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:subject:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-type:content-transfer-encoding; b=M5aX8mQiaUJyLx91U+jpTHy5tI8ksRbodyhkmt3q8otbqGvmw69RF2gmXUdNXBdwCC xp4d9K6jrjckXmYQI1bEOUXgYJiyTQB41BJ1OzqdEzi23tnmJKymm0l7zJ22aX8LS95H nSuAhCuagndcFyqHaMo4f8Iu7IVdcitf6kApA= Received: by 10.236.112.199 with SMTP id y47mr2024809yhg.170.1304969812937; Mon, 09 May 2011 12:36:52 -0700 (PDT) Received: from matisse.1015granger.net (adsl-99-26-161-222.dsl.sfldmi.sbcglobal.net [99.26.161.222]) by mx.google.com with ESMTPS id p67sm1109515yhm.100.2011.05.09.12.36.51 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 09 May 2011 12:36:52 -0700 (PDT) From: Chuck Lever Subject: [PATCH 04/16] SUNRPC: Add a helper to switch the transport of the rpc_client To: trond.myklebust@netapp.com Cc: linux-nfs@vger.kernel.org Date: Mon, 09 May 2011 15:36:49 -0400 Message-ID: <20110509193649.16568.42738.stgit@matisse.1015granger.net> In-Reply-To: <20110509192522.16568.59082.stgit@matisse.1015granger.net> References: <20110509192522.16568.59082.stgit@matisse.1015granger.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Mon, 09 May 2011 19:36:54 +0000 (UTC) From: Trond Myklebust Signed-off-by: Trond Myklebust [ cel: fix whitespace ] Signed-off-by: Chuck Lever --- include/linux/sunrpc/clnt.h | 3 ++ net/sunrpc/clnt.c | 76 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 6 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 2eea0d7..d18d952 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -144,6 +144,9 @@ void rpc_task_release_client(struct rpc_task *); int rpc_lock_client(struct rpc_clnt *clnt, unsigned long timeout); void rpc_unlock_client(struct rpc_clnt *clnt); +int rpc_switch_client_transport(struct rpc_clnt *, + struct xprt_create *, + const struct rpc_timeout *); int rpcb_register(u32, u32, int, unsigned short); int rpcb_v4_register(const u32 program, const u32 version, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6479e1d..ac2d29e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -143,12 +144,35 @@ err: return error; } +static void rpc_set_client_transport(struct rpc_clnt *clnt, + struct rpc_xprt *xprt, + const struct rpc_timeout *timeout) +{ + struct rpc_xprt *old; + + spin_lock(&clnt->cl_lock); + old = clnt->cl_xprt; + + if (!xprt_bound(xprt)) + clnt->cl_autobind = 1; + + clnt->cl_timeout = timeout; + rcu_assign_pointer(clnt->cl_xprt, xprt); + spin_unlock(&clnt->cl_lock); + + if (old != NULL) { + synchronize_rcu(); + xprt_put(old); + } +} + static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) { struct rpc_program *program = args->program; struct rpc_version *version; struct rpc_clnt *clnt = NULL; struct rpc_auth *auth; + const struct rpc_timeout *timeout; int err; /* sanity check the name before trying to print it */ @@ -174,7 +198,6 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru goto out_err; clnt->cl_parent = clnt; - rcu_assign_pointer(clnt->cl_xprt, xprt); clnt->cl_procinfo = version->procs; clnt->cl_maxproc = version->nrprocs; clnt->cl_protname = program->name; @@ -189,16 +212,15 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru INIT_LIST_HEAD(&clnt->cl_tasks); spin_lock_init(&clnt->cl_lock); - if (!xprt_bound(xprt)) - clnt->cl_autobind = 1; - - clnt->cl_timeout = xprt->timeout; + timeout = xprt->timeout; if (args->timeout != NULL) { memcpy(&clnt->cl_timeout_default, args->timeout, sizeof(clnt->cl_timeout_default)); - clnt->cl_timeout = &clnt->cl_timeout_default; + timeout = &clnt->cl_timeout_default; } + rpc_set_client_transport(clnt, xprt, timeout); + clnt->cl_rtt = &clnt->cl_rtt_default; rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); clnt->cl_principal = NULL; @@ -412,6 +434,48 @@ out_no_clnt: } EXPORT_SYMBOL_GPL(rpc_clone_client); +/** + * rpc_switch_client_transport: switch the RPC transport on the fly + * @clnt: pointer to a struct rpc_clnt + * @args: pointer to the new transport arguments + * @timeout: pointer to the new timeout parameters + * + * This function allows the caller to switch the RPC transport for the + * rpc_clnt structure 'clnt' to allow it to connect to a mirrored NFS server, + * for instance. It assumes that the caller has ensured that there are no + * active tasks by using some form of locking. + */ +int rpc_switch_client_transport(struct rpc_clnt *clnt, + struct xprt_create *args, + const struct rpc_timeout *timeout) +{ + struct rpc_xprt *xprt; + struct rpc_auth *auth; + rpc_authflavor_t pseudoflavor; + + xprt = xprt_create_transport(args); + if (IS_ERR(xprt)) + return PTR_ERR(xprt); + + pseudoflavor = clnt->cl_auth->au_flavor; + + rpc_set_client_transport(clnt, xprt, timeout); + + /* + * Note: we must always create a new rpc_auth cache + * when switching to a different server! RPCSEC_GSS sessions + * in particular are between a single client and server, + * so we cannot reuse the sessions in the cache when we switch + * servers. + */ + auth = rpcauth_create(pseudoflavor, clnt); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + return 0; +} +EXPORT_SYMBOL_GPL(rpc_switch_client_transport); + /* * Kill all tasks for the given client. * XXX: kill their descendants as well?