[PATCH] SUNRPC: Fix autobind on cloned rpc clients

Andy Whitcroft apw at canonical.com
Tue Mar 24 16:13:59 GMT 2009


On Tue, Mar 24, 2009 at 02:55:20PM +0100, Stefan Bader wrote:
> From: Trond Myklebust <Trond.Myklebust at netapp.com>
> 
> Bug: #212485, #341783
> 
> commit 9a4bd29fe8f6d3f015fe1c8e5450eb62cfebfcc9 upstream
> 
> Despite the fact that cloned rpc clients won't have the cl_autobind flag
> set, they may still find themselves calling rpcb_getport_async(). For this
> to happen, it suffices for a _parent_ rpc_clnt to use autobinding, in which
> case any clone may find itself triggering the !xprt_bound() case in
> call_bind().
> 
> The correct fix for this is to walk back up the tree of cloned rpc clients,
> in order to find the parent that 'owns' the transport, either because it
> has clnt->cl_autobind set, or because it originally created the
> transport...
> 
> Signed-off-by: Trond Myklebust <Trond.Myklebust at netapp.com>
> Signed-off-by: Stefan Bader <stefan.bader at canonical.com>
> ---
>  net/sunrpc/rpcb_clnt.c |   36 +++++++++++++++++++++++++++++-------
>  1 files changed, 29 insertions(+), 7 deletions(-)
> 
> diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
> index f42433d..201a4ae 100644
> --- a/net/sunrpc/rpcb_clnt.c
> +++ b/net/sunrpc/rpcb_clnt.c
> @@ -295,6 +295,28 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
>  }
>  EXPORT_SYMBOL_GPL(rpcb_getport_sync);
>  
> +/*
> + * In the case where rpc clients have been cloned, we want to make
> + * sure that we use the program number/version etc of the actual
> + * owner of the xprt. To do so, we walk back up the tree of parents
> + * to find whoever created the transport and/or whoever has the
> + * autobind flag set.
> + */
> +static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
> +{
> +	struct rpc_clnt *parent = clnt->cl_parent;
> +
> +	while (parent != clnt) {
> +		if (parent->cl_xprt != clnt->cl_xprt)
> +			break;
> +		if (clnt->cl_autobind)
> +			break;
> +		clnt = parent;
> +		parent = parent->cl_parent;
> +	}
> +	return clnt;
> +}
> +
>  /**
>   * rpcb_getport_async - obtain the port for a given RPC service on a given host
>   * @task: task that is waiting for portmapper request
> @@ -304,9 +326,9 @@ EXPORT_SYMBOL_GPL(rpcb_getport_sync);
>   */
>  void rpcb_getport_async(struct rpc_task *task)
>  {
> -	struct rpc_clnt *clnt = task->tk_client;
> +	struct rpc_clnt *clnt;
>  	int bind_version;
> -	struct rpc_xprt *xprt = task->tk_xprt;
> +	struct rpc_xprt *xprt;
>  	struct rpc_clnt	*rpcb_clnt;
>  	static struct rpcbind_args *map;
>  	struct rpc_task	*child;
> @@ -314,13 +336,13 @@ void rpcb_getport_async(struct rpc_task *task)
>  	int status;
>  	struct rpcb_info *info;
>  
> +	clnt = rpcb_find_transport_owner(task->tk_client);
> +	xprt = clnt->cl_xprt;
> +
>  	dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
>  		task->tk_pid, __FUNCTION__,
>  		clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
>  
> -	/* Autobind on cloned rpc clients is discouraged */
> -	BUG_ON(clnt->cl_parent != clnt);
> -
>  	if (xprt_test_and_set_binding(xprt)) {
>  		status = -EAGAIN;	/* tell caller to check again */
>  		dprintk("RPC: %5u %s: waiting for another binder\n",
> @@ -401,9 +423,9 @@ void rpcb_getport_async(struct rpc_task *task)
>  			task->tk_pid, __FUNCTION__);
>  		goto bailout;
>  	}
> -	rpc_put_task(child);
>  
> -	task->tk_xprt->stat.bind_count++;
> +	xprt->stat.bind_count++;
> +	rpc_put_task(child);

This change of order seems odd, but benign to my reading.  I guess as
its this way upstream its ok.

>  	return;
>  
>  bailout:

Acked-by: Andy Whitcroft <apw at canonical.com>

-apw



More information about the kernel-team mailing list