diff options
Diffstat (limited to 'net/sunrpc/clnt.c')
| -rw-r--r-- | net/sunrpc/clnt.c | 1317 | 
1 files changed, 954 insertions, 363 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 9dab9573be4..2e6ab10734f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -13,15 +13,10 @@   *	and need to be refreshed, or when a packet was damaged in transit.   *	This may be have to be moved to the VFS layer.   * - *  NB: BSD uses a more intelligent approach to guessing when a request - *  or reply has been lost by keeping the RTO estimate for each procedure. - *  We currently make do with a constant timeout value. - *   *  Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>   *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>   */ -#include <asm/system.h>  #include <linux/module.h>  #include <linux/types.h> @@ -30,16 +25,22 @@  #include <linux/namei.h>  #include <linux/mount.h>  #include <linux/slab.h> +#include <linux/rcupdate.h>  #include <linux/utsname.h>  #include <linux/workqueue.h> +#include <linux/in.h>  #include <linux/in6.h> +#include <linux/un.h>  #include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/addr.h>  #include <linux/sunrpc/rpc_pipe_fs.h>  #include <linux/sunrpc/metrics.h>  #include <linux/sunrpc/bc_xprt.h> +#include <trace/events/sunrpc.h>  #include "sunrpc.h" +#include "netns.h"  #ifdef RPC_DEBUG  # define RPCDBG_FACILITY	RPCDBG_CALL @@ -52,8 +53,6 @@  /*   * All RPC clients are linked into this list   */ -static LIST_HEAD(all_clients); -static DEFINE_SPINLOCK(rpc_client_lock);  static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); @@ -66,9 +65,9 @@ static void	call_decode(struct rpc_task *task);  static void	call_bind(struct rpc_task *task);  static void	call_bind_status(struct rpc_task *task);  static void	call_transmit(struct rpc_task *task); -#if defined(CONFIG_NFS_V4_1) +#if defined(CONFIG_SUNRPC_BACKCHANNEL)  static void	call_bc_transmit(struct rpc_task *task); -#endif /* CONFIG_NFS_V4_1 */ +#endif /* CONFIG_SUNRPC_BACKCHANNEL */  static void	call_status(struct rpc_task *task);  static void	call_transmit_status(struct rpc_task *task);  static void	call_refresh(struct rpc_task *task); @@ -83,93 +82,295 @@ static int	rpc_ping(struct rpc_clnt *clnt);  static void rpc_register_client(struct rpc_clnt *clnt)  { -	spin_lock(&rpc_client_lock); -	list_add(&clnt->cl_clients, &all_clients); -	spin_unlock(&rpc_client_lock); +	struct net *net = rpc_net_ns(clnt); +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + +	spin_lock(&sn->rpc_client_lock); +	list_add(&clnt->cl_clients, &sn->all_clients); +	spin_unlock(&sn->rpc_client_lock);  }  static void rpc_unregister_client(struct rpc_clnt *clnt)  { -	spin_lock(&rpc_client_lock); +	struct net *net = rpc_net_ns(clnt); +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + +	spin_lock(&sn->rpc_client_lock);  	list_del(&clnt->cl_clients); -	spin_unlock(&rpc_client_lock); +	spin_unlock(&sn->rpc_client_lock);  } -static int -rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) +static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)  { -	static uint32_t clntid; -	struct nameidata nd; -	struct path path; -	char name[15]; -	struct qstr q = { -		.name = name, -	}; -	int error; +	rpc_remove_client_dir(clnt); +} -	clnt->cl_path.mnt = ERR_PTR(-ENOENT); -	clnt->cl_path.dentry = ERR_PTR(-ENOENT); -	if (dir_name == NULL) -		return 0; +static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) +{ +	struct net *net = rpc_net_ns(clnt); +	struct super_block *pipefs_sb; -	path.mnt = rpc_get_mount(); -	if (IS_ERR(path.mnt)) -		return PTR_ERR(path.mnt); -	error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd); -	if (error) -		goto err; +	pipefs_sb = rpc_get_sb_net(net); +	if (pipefs_sb) { +		__rpc_clnt_remove_pipedir(clnt); +		rpc_put_sb_net(net); +	} +} +static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, +				    struct rpc_clnt *clnt) +{ +	static uint32_t clntid; +	const char *dir_name = clnt->cl_program->pipe_dir_name; +	char name[15]; +	struct dentry *dir, *dentry; + +	dir = rpc_d_lookup_sb(sb, dir_name); +	if (dir == NULL) { +		pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name); +		return dir; +	}  	for (;;) { -		q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); +		snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);  		name[sizeof(name) - 1] = '\0'; -		q.hash = full_name_hash(q.name, q.len); -		path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt); -		if (!IS_ERR(path.dentry)) +		dentry = rpc_create_client_dir(dir, name, clnt); +		if (!IS_ERR(dentry))  			break; -		error = PTR_ERR(path.dentry); -		if (error != -EEXIST) { -			printk(KERN_INFO "RPC: Couldn't create pipefs entry" -					" %s/%s, error %d\n", -					dir_name, name, error); -			goto err_path_put; -		} +		if (dentry == ERR_PTR(-EEXIST)) +			continue; +		printk(KERN_INFO "RPC: Couldn't create pipefs entry" +				" %s/%s, error %ld\n", +				dir_name, name, PTR_ERR(dentry)); +		break; +	} +	dput(dir); +	return dentry; +} + +static int +rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt) +{ +	struct dentry *dentry; + +	if (clnt->cl_program->pipe_dir_name != NULL) { +		dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt); +		if (IS_ERR(dentry)) +			return PTR_ERR(dentry); +	} +	return 0; +} + +static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event) +{ +	if (clnt->cl_program->pipe_dir_name == NULL) +		return 1; + +	switch (event) { +	case RPC_PIPEFS_MOUNT: +		if (clnt->cl_pipedir_objects.pdh_dentry != NULL) +			return 1; +		if (atomic_read(&clnt->cl_count) == 0) +			return 1; +		break; +	case RPC_PIPEFS_UMOUNT: +		if (clnt->cl_pipedir_objects.pdh_dentry == NULL) +			return 1; +		break;  	} -	path_put(&nd.path); -	clnt->cl_path = path;  	return 0; -err_path_put: -	path_put(&nd.path); -err: -	rpc_put_mount(); +} + +static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event, +				   struct super_block *sb) +{ +	struct dentry *dentry; +	int err = 0; + +	switch (event) { +	case RPC_PIPEFS_MOUNT: +		dentry = rpc_setup_pipedir_sb(sb, clnt); +		if (!dentry) +			return -ENOENT; +		if (IS_ERR(dentry)) +			return PTR_ERR(dentry); +		break; +	case RPC_PIPEFS_UMOUNT: +		__rpc_clnt_remove_pipedir(clnt); +		break; +	default: +		printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event); +		return -ENOTSUPP; +	} +	return err; +} + +static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, +				struct super_block *sb) +{ +	int error = 0; + +	for (;; clnt = clnt->cl_parent) { +		if (!rpc_clnt_skip_event(clnt, event)) +			error = __rpc_clnt_handle_event(clnt, event, sb); +		if (error || clnt == clnt->cl_parent) +			break; +	}  	return error;  } -static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) +static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) +{ +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); +	struct rpc_clnt *clnt; + +	spin_lock(&sn->rpc_client_lock); +	list_for_each_entry(clnt, &sn->all_clients, cl_clients) { +		if (rpc_clnt_skip_event(clnt, event)) +			continue; +		spin_unlock(&sn->rpc_client_lock); +		return clnt; +	} +	spin_unlock(&sn->rpc_client_lock); +	return NULL; +} + +static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, +			    void *ptr)  { -	struct rpc_program	*program = args->program; -	struct rpc_version	*version; -	struct rpc_clnt		*clnt = NULL; -	struct rpc_auth		*auth; +	struct super_block *sb = ptr; +	struct rpc_clnt *clnt; +	int error = 0; + +	while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) { +		error = __rpc_pipefs_event(clnt, event, sb); +		if (error) +			break; +	} +	return error; +} + +static struct notifier_block rpc_clients_block = { +	.notifier_call	= rpc_pipefs_event, +	.priority	= SUNRPC_PIPEFS_RPC_PRIO, +}; + +int rpc_clients_notifier_register(void) +{ +	return rpc_pipefs_notifier_register(&rpc_clients_block); +} + +void rpc_clients_notifier_unregister(void) +{ +	return rpc_pipefs_notifier_unregister(&rpc_clients_block); +} + +static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt, +		struct rpc_xprt *xprt, +		const struct rpc_timeout *timeout) +{ +	struct rpc_xprt *old; + +	spin_lock(&clnt->cl_lock); +	old = rcu_dereference_protected(clnt->cl_xprt, +			lockdep_is_held(&clnt->cl_lock)); + +	if (!xprt_bound(xprt)) +		clnt->cl_autobind = 1; + +	clnt->cl_timeout = timeout; +	rcu_assign_pointer(clnt->cl_xprt, xprt); +	spin_unlock(&clnt->cl_lock); + +	return old; +} + +static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) +{ +	clnt->cl_nodelen = strlen(nodename); +	if (clnt->cl_nodelen > UNX_MAXNODENAME) +		clnt->cl_nodelen = UNX_MAXNODENAME; +	memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen); +} + +static int rpc_client_register(struct rpc_clnt *clnt, +			       rpc_authflavor_t pseudoflavor, +			       const char *client_name) +{ +	struct rpc_auth_create_args auth_args = { +		.pseudoflavor = pseudoflavor, +		.target_name = client_name, +	}; +	struct rpc_auth *auth; +	struct net *net = rpc_net_ns(clnt); +	struct super_block *pipefs_sb;  	int err; -	size_t len; -	/* sanity check the name before trying to print it */ -	err = -EINVAL; -	len = strlen(args->servername); -	if (len > RPC_MAXNETNAMELEN) -		goto out_no_rpciod; -	len++; +	pipefs_sb = rpc_get_sb_net(net); +	if (pipefs_sb) { +		err = rpc_setup_pipedir(pipefs_sb, clnt); +		if (err) +			goto out; +	} + +	rpc_register_client(clnt); +	if (pipefs_sb) +		rpc_put_sb_net(net); + +	auth = rpcauth_create(&auth_args, clnt); +	if (IS_ERR(auth)) { +		dprintk("RPC:       Couldn't create auth handle (flavor %u)\n", +				pseudoflavor); +		err = PTR_ERR(auth); +		goto err_auth; +	} +	return 0; +err_auth: +	pipefs_sb = rpc_get_sb_net(net); +	rpc_unregister_client(clnt); +	__rpc_clnt_remove_pipedir(clnt); +out: +	if (pipefs_sb) +		rpc_put_sb_net(net); +	return err; +} + +static DEFINE_IDA(rpc_clids); + +static int rpc_alloc_clid(struct rpc_clnt *clnt) +{ +	int clid; + +	clid = ida_simple_get(&rpc_clids, 0, 0, GFP_KERNEL); +	if (clid < 0) +		return clid; +	clnt->cl_clid = clid; +	return 0; +} +static void rpc_free_clid(struct rpc_clnt *clnt) +{ +	ida_simple_remove(&rpc_clids, clnt->cl_clid); +} + +static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, +		struct rpc_xprt *xprt, +		struct rpc_clnt *parent) +{ +	const struct rpc_program *program = args->program; +	const struct rpc_version *version; +	struct rpc_clnt *clnt = NULL; +	const struct rpc_timeout *timeout; +	int err; + +	/* sanity check the name before trying to print it */  	dprintk("RPC:       creating %s client for %s (xprt %p)\n",  			program->name, args->servername, xprt);  	err = rpciod_up();  	if (err)  		goto out_no_rpciod; -	err = -EINVAL; -	if (!xprt) -		goto out_no_xprt; +	err = -EINVAL;  	if (args->version >= program->nrvers)  		goto out_err;  	version = program->version[args->version]; @@ -180,26 +381,19 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru  	clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);  	if (!clnt)  		goto out_err; -	clnt->cl_parent = clnt; +	clnt->cl_parent = parent ? : clnt; -	clnt->cl_server = clnt->cl_inline_name; -	if (len > sizeof(clnt->cl_inline_name)) { -		char *buf = kmalloc(len, GFP_KERNEL); -		if (buf != NULL) -			clnt->cl_server = buf; -		else -			len = sizeof(clnt->cl_inline_name); -	} -	strlcpy(clnt->cl_server, args->servername, len); +	err = rpc_alloc_clid(clnt); +	if (err) +		goto out_no_clid; -	clnt->cl_xprt     = xprt;  	clnt->cl_procinfo = version->procs;  	clnt->cl_maxproc  = version->nrprocs; -	clnt->cl_protname = program->name;  	clnt->cl_prog     = args->prognumber ? : program->number;  	clnt->cl_vers     = version->number;  	clnt->cl_stats    = program->stats;  	clnt->cl_metrics  = rpc_alloc_iostats(clnt); +	rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);  	err = -ENOMEM;  	if (clnt->cl_metrics == NULL)  		goto out_no_stats; @@ -207,69 +401,76 @@ 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(clnt->cl_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_clnt_set_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; -	if (args->client_name) { -		clnt->cl_principal = kstrdup(args->client_name, GFP_KERNEL); -		if (!clnt->cl_principal) -			goto out_no_principal; -	}  	atomic_set(&clnt->cl_count, 1); -	err = rpc_setup_pipedir(clnt, program->pipe_dir_name); -	if (err < 0) -		goto out_no_path; - -	auth = rpcauth_create(args->authflavor, clnt); -	if (IS_ERR(auth)) { -		printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", -				args->authflavor); -		err = PTR_ERR(auth); -		goto out_no_auth; -	} -  	/* save the nodename */ -	clnt->cl_nodelen = strlen(init_utsname()->nodename); -	if (clnt->cl_nodelen > UNX_MAXNODENAME) -		clnt->cl_nodelen = UNX_MAXNODENAME; -	memcpy(clnt->cl_nodename, init_utsname()->nodename, clnt->cl_nodelen); -	rpc_register_client(clnt); +	rpc_clnt_set_nodename(clnt, utsname()->nodename); + +	err = rpc_client_register(clnt, args->authflavor, args->client_name); +	if (err) +		goto out_no_path; +	if (parent) +		atomic_inc(&parent->cl_count);  	return clnt; -out_no_auth: -	if (!IS_ERR(clnt->cl_path.dentry)) { -		rpc_remove_client_dir(clnt->cl_path.dentry); -		rpc_put_mount(); -	}  out_no_path: -	kfree(clnt->cl_principal); -out_no_principal:  	rpc_free_iostats(clnt->cl_metrics);  out_no_stats: -	if (clnt->cl_server != clnt->cl_inline_name) -		kfree(clnt->cl_server); +	rpc_free_clid(clnt); +out_no_clid:  	kfree(clnt);  out_err: -	xprt_put(xprt); -out_no_xprt:  	rpciod_down();  out_no_rpciod: +	xprt_put(xprt);  	return ERR_PTR(err);  } -/* +struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args, +					struct rpc_xprt *xprt) +{ +	struct rpc_clnt *clnt = NULL; + +	clnt = rpc_new_client(args, xprt, NULL); +	if (IS_ERR(clnt)) +		return clnt; + +	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) { +		int err = rpc_ping(clnt); +		if (err != 0) { +			rpc_shutdown_client(clnt); +			return ERR_PTR(err); +		} +	} + +	clnt->cl_softrtry = 1; +	if (args->flags & RPC_CLNT_CREATE_HARDRTRY) +		clnt->cl_softrtry = 0; + +	if (args->flags & RPC_CLNT_CREATE_AUTOBIND) +		clnt->cl_autobind = 1; +	if (args->flags & RPC_CLNT_CREATE_DISCRTRY) +		clnt->cl_discrtry = 1; +	if (!(args->flags & RPC_CLNT_CREATE_QUIET)) +		clnt->cl_chatty = 1; + +	return clnt; +} +EXPORT_SYMBOL_GPL(rpc_create_xprt); + +/**   * rpc_create - create an RPC client and transport with one call   * @args: rpc_clnt create argument structure   * @@ -282,44 +483,53 @@ out_no_rpciod:  struct rpc_clnt *rpc_create(struct rpc_create_args *args)  {  	struct rpc_xprt *xprt; -	struct rpc_clnt *clnt;  	struct xprt_create xprtargs = {  		.net = args->net,  		.ident = args->protocol,  		.srcaddr = args->saddress,  		.dstaddr = args->address,  		.addrlen = args->addrsize, +		.servername = args->servername,  		.bc_xprt = args->bc_xprt,  	};  	char servername[48]; +	if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS) +		xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS; +	if (args->flags & RPC_CLNT_CREATE_NO_IDLE_TIMEOUT) +		xprtargs.flags |= XPRT_CREATE_NO_IDLE_TIMEOUT;  	/*  	 * If the caller chooses not to specify a hostname, whip  	 * up a string representation of the passed-in address.  	 */ -	if (args->servername == NULL) { +	if (xprtargs.servername == NULL) { +		struct sockaddr_un *sun = +				(struct sockaddr_un *)args->address; +		struct sockaddr_in *sin = +				(struct sockaddr_in *)args->address; +		struct sockaddr_in6 *sin6 = +				(struct sockaddr_in6 *)args->address; +  		servername[0] = '\0';  		switch (args->address->sa_family) { -		case AF_INET: { -			struct sockaddr_in *sin = -					(struct sockaddr_in *)args->address; +		case AF_LOCAL: +			snprintf(servername, sizeof(servername), "%s", +				 sun->sun_path); +			break; +		case AF_INET:  			snprintf(servername, sizeof(servername), "%pI4",  				 &sin->sin_addr.s_addr);  			break; -		} -		case AF_INET6: { -			struct sockaddr_in6 *sin = -					(struct sockaddr_in6 *)args->address; +		case AF_INET6:  			snprintf(servername, sizeof(servername), "%pI6", -				 &sin->sin6_addr); +				 &sin6->sin6_addr);  			break; -		}  		default:  			/* caller wants default server name, but  			 * address family isn't recognized. */  			return ERR_PTR(-EINVAL);  		} -		args->servername = servername; +		xprtargs.servername = servername;  	}  	xprt = xprt_create_transport(&xprtargs); @@ -336,30 +546,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)  	if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)  		xprt->resvport = 0; -	clnt = rpc_new_client(args, xprt); -	if (IS_ERR(clnt)) -		return clnt; - -	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) { -		int err = rpc_ping(clnt); -		if (err != 0) { -			rpc_shutdown_client(clnt); -			return ERR_PTR(err); -		} -	} - -	clnt->cl_softrtry = 1; -	if (args->flags & RPC_CLNT_CREATE_HARDRTRY) -		clnt->cl_softrtry = 0; - -	if (args->flags & RPC_CLNT_CREATE_AUTOBIND) -		clnt->cl_autobind = 1; -	if (args->flags & RPC_CLNT_CREATE_DISCRTRY) -		clnt->cl_discrtry = 1; -	if (!(args->flags & RPC_CLNT_CREATE_QUIET)) -		clnt->cl_chatty = 1; - -	return clnt; +	return rpc_create_xprt(args, xprt);  }  EXPORT_SYMBOL_GPL(rpc_create); @@ -368,52 +555,153 @@ EXPORT_SYMBOL_GPL(rpc_create);   * same transport while varying parameters such as the authentication   * flavour.   */ -struct rpc_clnt * -rpc_clone_client(struct rpc_clnt *clnt) +static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args, +					   struct rpc_clnt *clnt)  { +	struct rpc_xprt *xprt;  	struct rpc_clnt *new; -	int err = -ENOMEM; +	int err; + +	err = -ENOMEM; +	rcu_read_lock(); +	xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); +	rcu_read_unlock(); +	if (xprt == NULL) +		goto out_err; +	args->servername = xprt->servername; + +	new = rpc_new_client(args, xprt, clnt); +	if (IS_ERR(new)) { +		err = PTR_ERR(new); +		goto out_err; +	} -	new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); -	if (!new) -		goto out_no_clnt; -	new->cl_parent = clnt;  	/* Turn off autobind on clones */  	new->cl_autobind = 0; -	INIT_LIST_HEAD(&new->cl_tasks); -	spin_lock_init(&new->cl_lock); -	rpc_init_rtt(&new->cl_rtt_default, clnt->cl_timeout->to_initval); -	new->cl_metrics = rpc_alloc_iostats(clnt); -	if (new->cl_metrics == NULL) -		goto out_no_stats; -	if (clnt->cl_principal) { -		new->cl_principal = kstrdup(clnt->cl_principal, GFP_KERNEL); -		if (new->cl_principal == NULL) -			goto out_no_principal; -	} -	atomic_set(&new->cl_count, 1); -	err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); -	if (err != 0) -		goto out_no_path; -	if (new->cl_auth) -		atomic_inc(&new->cl_auth->au_count); -	xprt_get(clnt->cl_xprt); -	atomic_inc(&clnt->cl_count); -	rpc_register_client(new); -	rpciod_up(); +	new->cl_softrtry = clnt->cl_softrtry; +	new->cl_discrtry = clnt->cl_discrtry; +	new->cl_chatty = clnt->cl_chatty;  	return new; -out_no_path: -	kfree(new->cl_principal); -out_no_principal: -	rpc_free_iostats(new->cl_metrics); -out_no_stats: -	kfree(new); -out_no_clnt: + +out_err:  	dprintk("RPC:       %s: returned error %d\n", __func__, err);  	return ERR_PTR(err);  } + +/** + * rpc_clone_client - Clone an RPC client structure + * + * @clnt: RPC client whose parameters are copied + * + * Returns a fresh RPC client or an ERR_PTR. + */ +struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt) +{ +	struct rpc_create_args args = { +		.program	= clnt->cl_program, +		.prognumber	= clnt->cl_prog, +		.version	= clnt->cl_vers, +		.authflavor	= clnt->cl_auth->au_flavor, +	}; +	return __rpc_clone_client(&args, clnt); +}  EXPORT_SYMBOL_GPL(rpc_clone_client); +/** + * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth + * + * @clnt: RPC client whose parameters are copied + * @flavor: security flavor for new client + * + * Returns a fresh RPC client or an ERR_PTR. + */ +struct rpc_clnt * +rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor) +{ +	struct rpc_create_args args = { +		.program	= clnt->cl_program, +		.prognumber	= clnt->cl_prog, +		.version	= clnt->cl_vers, +		.authflavor	= flavor, +	}; +	return __rpc_clone_client(&args, clnt); +} +EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth); + +/** + * 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 RPC tasks by using some form of locking. + * + * Returns zero if "clnt" is now using the new xprt.  Otherwise a + * negative errno is returned, and "clnt" continues to use the old + * xprt. + */ +int rpc_switch_client_transport(struct rpc_clnt *clnt, +		struct xprt_create *args, +		const struct rpc_timeout *timeout) +{ +	const struct rpc_timeout *old_timeo; +	rpc_authflavor_t pseudoflavor; +	struct rpc_xprt *xprt, *old; +	struct rpc_clnt *parent; +	int err; + +	xprt = xprt_create_transport(args); +	if (IS_ERR(xprt)) { +		dprintk("RPC:       failed to create new xprt for clnt %p\n", +			clnt); +		return PTR_ERR(xprt); +	} + +	pseudoflavor = clnt->cl_auth->au_flavor; + +	old_timeo = clnt->cl_timeout; +	old = rpc_clnt_set_transport(clnt, xprt, timeout); + +	rpc_unregister_client(clnt); +	__rpc_clnt_remove_pipedir(clnt); + +	/* +	 * A new transport was created.  "clnt" therefore +	 * becomes the root of a new cl_parent tree.  clnt's +	 * children, if it has any, still point to the old xprt. +	 */ +	parent = clnt->cl_parent; +	clnt->cl_parent = clnt; + +	/* +	 * The old rpc_auth cache cannot be re-used.  GSS +	 * contexts in particular are between a single +	 * client and server. +	 */ +	err = rpc_client_register(clnt, pseudoflavor, NULL); +	if (err) +		goto out_revert; + +	synchronize_rcu(); +	if (parent != clnt) +		rpc_release_client(parent); +	xprt_put(old); +	dprintk("RPC:       replaced xprt for clnt %p\n", clnt); +	return 0; + +out_revert: +	rpc_clnt_set_transport(clnt, old, old_timeo); +	clnt->cl_parent = parent; +	rpc_client_register(clnt, pseudoflavor, NULL); +	xprt_put(xprt); +	dprintk("RPC:       failed to switch xprt for clnt %p\n", clnt); +	return err; +} +EXPORT_SYMBOL_GPL(rpc_switch_client_transport); +  /*   * Kill all tasks for the given client.   * XXX: kill their descendants as well? @@ -436,7 +724,9 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)  		if (!(rovr->tk_flags & RPC_TASK_KILLED)) {  			rovr->tk_flags |= RPC_TASK_KILLED;  			rpc_exit(rovr, -EIO); -			rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr); +			if (RPC_IS_QUEUED(rovr)) +				rpc_wake_up_queued_task(rovr->tk_waitqueue, +							rovr);  		}  	}  	spin_unlock(&clnt->cl_lock); @@ -449,8 +739,11 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks);   */  void rpc_shutdown_client(struct rpc_clnt *clnt)  { -	dprintk("RPC:       shutting down %s client for %s\n", -			clnt->cl_protname, clnt->cl_server); +	might_sleep(); + +	dprintk_rcu("RPC:       shutting down %s client for %s\n", +			clnt->cl_program->name, +			rcu_dereference(clnt->cl_xprt)->servername);  	while (!list_empty(&clnt->cl_tasks)) {  		rpc_killall_tasks(clnt); @@ -465,41 +758,35 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client);  /*   * Free an RPC client   */ -static void +static struct rpc_clnt *  rpc_free_client(struct rpc_clnt *clnt)  { -	dprintk("RPC:       destroying %s client for %s\n", -			clnt->cl_protname, clnt->cl_server); -	if (!IS_ERR(clnt->cl_path.dentry)) { -		rpc_remove_client_dir(clnt->cl_path.dentry); -		rpc_put_mount(); -	} -	if (clnt->cl_parent != clnt) { -		rpc_release_client(clnt->cl_parent); -		goto out_free; -	} -	if (clnt->cl_server != clnt->cl_inline_name) -		kfree(clnt->cl_server); -out_free: +	struct rpc_clnt *parent = NULL; + +	dprintk_rcu("RPC:       destroying %s client for %s\n", +			clnt->cl_program->name, +			rcu_dereference(clnt->cl_xprt)->servername); +	if (clnt->cl_parent != clnt) +		parent = clnt->cl_parent; +	rpc_clnt_remove_pipedir(clnt);  	rpc_unregister_client(clnt);  	rpc_free_iostats(clnt->cl_metrics); -	kfree(clnt->cl_principal);  	clnt->cl_metrics = NULL; -	xprt_put(clnt->cl_xprt); +	xprt_put(rcu_dereference_raw(clnt->cl_xprt));  	rpciod_down(); +	rpc_free_clid(clnt);  	kfree(clnt); +	return parent;  }  /*   * Free an RPC client   */ -static void +static struct rpc_clnt *   rpc_free_auth(struct rpc_clnt *clnt)  { -	if (clnt->cl_auth == NULL) { -		rpc_free_client(clnt); -		return; -	} +	if (clnt->cl_auth == NULL) +		return rpc_free_client(clnt);  	/*  	 * Note: RPCSEC_GSS may need to send NULL RPC calls in order to @@ -510,7 +797,8 @@ rpc_free_auth(struct rpc_clnt *clnt)  	rpcauth_release(clnt->cl_auth);  	clnt->cl_auth = NULL;  	if (atomic_dec_and_test(&clnt->cl_count)) -		rpc_free_client(clnt); +		return rpc_free_client(clnt); +	return NULL;  }  /* @@ -521,11 +809,15 @@ rpc_release_client(struct rpc_clnt *clnt)  {  	dprintk("RPC:       rpc_release_client(%p)\n", clnt); -	if (list_empty(&clnt->cl_tasks)) -		wake_up(&destroy_wait); -	if (atomic_dec_and_test(&clnt->cl_count)) -		rpc_free_auth(clnt); +	do { +		if (list_empty(&clnt->cl_tasks)) +			wake_up(&destroy_wait); +		if (!atomic_dec_and_test(&clnt->cl_count)) +			break; +		clnt = rpc_free_auth(clnt); +	} while (clnt != NULL);  } +EXPORT_SYMBOL_GPL(rpc_release_client);  /**   * rpc_bind_new_program - bind a new RPC program to an existing client @@ -538,24 +830,21 @@ rpc_release_client(struct rpc_clnt *clnt)   * The Sun NFSv2/v3 ACL protocol can do this.   */  struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, -				      struct rpc_program *program, +				      const struct rpc_program *program,  				      u32 vers)  { +	struct rpc_create_args args = { +		.program	= program, +		.prognumber	= program->number, +		.version	= vers, +		.authflavor	= old->cl_auth->au_flavor, +	};  	struct rpc_clnt *clnt; -	struct rpc_version *version;  	int err; -	BUG_ON(vers >= program->nrvers || !program->version[vers]); -	version = program->version[vers]; -	clnt = rpc_clone_client(old); +	clnt = __rpc_clone_client(&args, old);  	if (IS_ERR(clnt))  		goto out; -	clnt->cl_procinfo = version->procs; -	clnt->cl_maxproc  = version->nrprocs; -	clnt->cl_protname = program->name; -	clnt->cl_prog     = program->number; -	clnt->cl_vers     = version->number; -	clnt->cl_stats    = program->stats;  	err = rpc_ping(clnt);  	if (err != 0) {  		rpc_shutdown_client(clnt); @@ -590,6 +879,17 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)  		atomic_inc(&clnt->cl_count);  		if (clnt->cl_softrtry)  			task->tk_flags |= RPC_TASK_SOFT; +		if (clnt->cl_noretranstimeo) +			task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; +		if (sk_memalloc_socks()) { +			struct rpc_xprt *xprt; + +			rcu_read_lock(); +			xprt = rcu_dereference(clnt->cl_xprt); +			if (xprt->swapper) +				task->tk_flags |= RPC_TASK_SWAPPER; +			rcu_read_unlock(); +		}  		/* Add to the client's list of all tasks */  		spin_lock(&clnt->cl_lock);  		list_add_tail(&task->tk_task, &clnt->cl_tasks); @@ -597,6 +897,14 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)  	}  } +void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt) +{ +	rpc_task_release_client(task); +	rpc_task_set_client(task, clnt); +} +EXPORT_SYMBOL_GPL(rpc_task_reset_client); + +  static void  rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)  { @@ -636,12 +944,6 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)  	rpc_task_set_client(task, task_setup_data->rpc_client);  	rpc_task_set_rpc_message(task, task_setup_data->rpc_message); -	if (task->tk_status != 0) { -		int ret = task->tk_status; -		rpc_put_task(task); -		return ERR_PTR(ret); -	} -  	if (task->tk_action == NULL)  		rpc_call_start(task); @@ -669,7 +971,12 @@ int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flag  	};  	int status; -	BUG_ON(flags & RPC_TASK_ASYNC); +	WARN_ON_ONCE(flags & RPC_TASK_ASYNC); +	if (flags & RPC_TASK_ASYNC) { +		rpc_release_calldata(task_setup_data.callback_ops, +			task_setup_data.callback_data); +		return -EINVAL; +	}  	task = rpc_run_task(&task_setup_data);  	if (IS_ERR(task)) @@ -709,7 +1016,7 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,  }  EXPORT_SYMBOL_GPL(rpc_call_async); -#if defined(CONFIG_NFS_V4_1) +#if defined(CONFIG_SUNRPC_BACKCHANNEL)  /**   * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run   * rpc_execute against it @@ -745,14 +1052,14 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,  	task->tk_action = call_bc_transmit;  	atomic_inc(&task->tk_count); -	BUG_ON(atomic_read(&task->tk_count) != 2); +	WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);  	rpc_execute(task);  out:  	dprintk("RPC: rpc_run_bc_task: task= %p\n", task);  	return task;  } -#endif /* CONFIG_NFS_V4_1 */ +#endif /* CONFIG_SUNRPC_BACKCHANNEL */  void  rpc_call_start(struct rpc_task *task) @@ -772,13 +1079,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start);  size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)  {  	size_t bytes; -	struct rpc_xprt *xprt = clnt->cl_xprt; +	struct rpc_xprt *xprt; -	bytes = sizeof(xprt->addr); +	rcu_read_lock(); +	xprt = rcu_dereference(clnt->cl_xprt); + +	bytes = xprt->addrlen;  	if (bytes > bufsize)  		bytes = bufsize; -	memcpy(buf, &clnt->cl_xprt->addr, bytes); -	return xprt->addrlen; +	memcpy(buf, &xprt->addr, bytes); +	rcu_read_unlock(); + +	return bytes;  }  EXPORT_SYMBOL_GPL(rpc_peeraddr); @@ -787,11 +1099,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr);   * @clnt: RPC client structure   * @format: address format   * + * NB: the lifetime of the memory referenced by the returned pointer is + * the same as the rpc_xprt itself.  As long as the caller uses this + * pointer, it must hold the RCU read lock.   */  const char *rpc_peeraddr2str(struct rpc_clnt *clnt,  			     enum rpc_display_format_t format)  { -	struct rpc_xprt *xprt = clnt->cl_xprt; +	struct rpc_xprt *xprt; + +	xprt = rcu_dereference(clnt->cl_xprt);  	if (xprt->address_strings[format] != NULL)  		return xprt->address_strings[format]; @@ -800,17 +1117,203 @@ const char *rpc_peeraddr2str(struct rpc_clnt *clnt,  }  EXPORT_SYMBOL_GPL(rpc_peeraddr2str); +static const struct sockaddr_in rpc_inaddr_loopback = { +	.sin_family		= AF_INET, +	.sin_addr.s_addr	= htonl(INADDR_ANY), +}; + +static const struct sockaddr_in6 rpc_in6addr_loopback = { +	.sin6_family		= AF_INET6, +	.sin6_addr		= IN6ADDR_ANY_INIT, +}; + +/* + * Try a getsockname() on a connected datagram socket.  Using a + * connected datagram socket prevents leaving a socket in TIME_WAIT. + * This conserves the ephemeral port number space. + * + * Returns zero and fills in "buf" if successful; otherwise, a + * negative errno is returned. + */ +static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen, +			struct sockaddr *buf, int buflen) +{ +	struct socket *sock; +	int err; + +	err = __sock_create(net, sap->sa_family, +				SOCK_DGRAM, IPPROTO_UDP, &sock, 1); +	if (err < 0) { +		dprintk("RPC:       can't create UDP socket (%d)\n", err); +		goto out; +	} + +	switch (sap->sa_family) { +	case AF_INET: +		err = kernel_bind(sock, +				(struct sockaddr *)&rpc_inaddr_loopback, +				sizeof(rpc_inaddr_loopback)); +		break; +	case AF_INET6: +		err = kernel_bind(sock, +				(struct sockaddr *)&rpc_in6addr_loopback, +				sizeof(rpc_in6addr_loopback)); +		break; +	default: +		err = -EAFNOSUPPORT; +		goto out; +	} +	if (err < 0) { +		dprintk("RPC:       can't bind UDP socket (%d)\n", err); +		goto out_release; +	} + +	err = kernel_connect(sock, sap, salen, 0); +	if (err < 0) { +		dprintk("RPC:       can't connect UDP socket (%d)\n", err); +		goto out_release; +	} + +	err = kernel_getsockname(sock, buf, &buflen); +	if (err < 0) { +		dprintk("RPC:       getsockname failed (%d)\n", err); +		goto out_release; +	} + +	err = 0; +	if (buf->sa_family == AF_INET6) { +		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf; +		sin6->sin6_scope_id = 0; +	} +	dprintk("RPC:       %s succeeded\n", __func__); + +out_release: +	sock_release(sock); +out: +	return err; +} + +/* + * Scraping a connected socket failed, so we don't have a useable + * local address.  Fallback: generate an address that will prevent + * the server from calling us back. + * + * Returns zero and fills in "buf" if successful; otherwise, a + * negative errno is returned. + */ +static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen) +{ +	switch (family) { +	case AF_INET: +		if (buflen < sizeof(rpc_inaddr_loopback)) +			return -EINVAL; +		memcpy(buf, &rpc_inaddr_loopback, +				sizeof(rpc_inaddr_loopback)); +		break; +	case AF_INET6: +		if (buflen < sizeof(rpc_in6addr_loopback)) +			return -EINVAL; +		memcpy(buf, &rpc_in6addr_loopback, +				sizeof(rpc_in6addr_loopback)); +	default: +		dprintk("RPC:       %s: address family not supported\n", +			__func__); +		return -EAFNOSUPPORT; +	} +	dprintk("RPC:       %s: succeeded\n", __func__); +	return 0; +} + +/** + * rpc_localaddr - discover local endpoint address for an RPC client + * @clnt: RPC client structure + * @buf: target buffer + * @buflen: size of target buffer, in bytes + * + * Returns zero and fills in "buf" and "buflen" if successful; + * otherwise, a negative errno is returned. + * + * This works even if the underlying transport is not currently connected, + * or if the upper layer never previously provided a source address. + * + * The result of this function call is transient: multiple calls in + * succession may give different results, depending on how local + * networking configuration changes over time. + */ +int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen) +{ +	struct sockaddr_storage address; +	struct sockaddr *sap = (struct sockaddr *)&address; +	struct rpc_xprt *xprt; +	struct net *net; +	size_t salen; +	int err; + +	rcu_read_lock(); +	xprt = rcu_dereference(clnt->cl_xprt); +	salen = xprt->addrlen; +	memcpy(sap, &xprt->addr, salen); +	net = get_net(xprt->xprt_net); +	rcu_read_unlock(); + +	rpc_set_port(sap, 0); +	err = rpc_sockname(net, sap, salen, buf, buflen); +	put_net(net); +	if (err != 0) +		/* Couldn't discover local address, return ANYADDR */ +		return rpc_anyaddr(sap->sa_family, buf, buflen); +	return 0; +} +EXPORT_SYMBOL_GPL(rpc_localaddr); +  void  rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)  { -	struct rpc_xprt *xprt = clnt->cl_xprt; +	struct rpc_xprt *xprt; + +	rcu_read_lock(); +	xprt = rcu_dereference(clnt->cl_xprt);  	if (xprt->ops->set_buffer_size)  		xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); +	rcu_read_unlock();  }  EXPORT_SYMBOL_GPL(rpc_setbufsize); -/* - * Return size of largest payload RPC client can support, in bytes +/** + * rpc_protocol - Get transport protocol number for an RPC client + * @clnt: RPC client to query + * + */ +int rpc_protocol(struct rpc_clnt *clnt) +{ +	int protocol; + +	rcu_read_lock(); +	protocol = rcu_dereference(clnt->cl_xprt)->prot; +	rcu_read_unlock(); +	return protocol; +} +EXPORT_SYMBOL_GPL(rpc_protocol); + +/** + * rpc_net_ns - Get the network namespace for this RPC client + * @clnt: RPC client to query + * + */ +struct net *rpc_net_ns(struct rpc_clnt *clnt) +{ +	struct net *ret; + +	rcu_read_lock(); +	ret = rcu_dereference(clnt->cl_xprt)->xprt_net; +	rcu_read_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(rpc_net_ns); + +/** + * rpc_max_payload - Get maximum payload size for a transport, in bytes + * @clnt: RPC client to query   *   * For stream transports, this is one RPC record fragment (see RFC   * 1831), as we don't support multi-record requests yet.  For datagram @@ -819,19 +1322,42 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize);   */  size_t rpc_max_payload(struct rpc_clnt *clnt)  { -	return clnt->cl_xprt->max_payload; +	size_t ret; + +	rcu_read_lock(); +	ret = rcu_dereference(clnt->cl_xprt)->max_payload; +	rcu_read_unlock(); +	return ret;  }  EXPORT_SYMBOL_GPL(rpc_max_payload);  /** + * rpc_get_timeout - Get timeout for transport in units of HZ + * @clnt: RPC client to query + */ +unsigned long rpc_get_timeout(struct rpc_clnt *clnt) +{ +	unsigned long ret; + +	rcu_read_lock(); +	ret = rcu_dereference(clnt->cl_xprt)->timeout->to_initval; +	rcu_read_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(rpc_get_timeout); + +/**   * rpc_force_rebind - force transport to check that remote port is unchanged   * @clnt: client to rebind   *   */  void rpc_force_rebind(struct rpc_clnt *clnt)  { -	if (clnt->cl_autobind) -		xprt_clear_bound(clnt->cl_xprt); +	if (clnt->cl_autobind) { +		rcu_read_lock(); +		xprt_clear_bound(rcu_dereference(clnt->cl_xprt)); +		rcu_read_unlock(); +	}  }  EXPORT_SYMBOL_GPL(rpc_force_rebind); @@ -844,7 +1370,10 @@ rpc_restart_call_prepare(struct rpc_task *task)  {  	if (RPC_ASSASSINATED(task))  		return 0; -	task->tk_action = rpc_prepare_task; +	task->tk_action = call_start; +	task->tk_status = 0; +	if (task->tk_ops->rpc_call_prepare != NULL) +		task->tk_action = rpc_prepare_task;  	return 1;  }  EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); @@ -859,6 +1388,7 @@ rpc_restart_call(struct rpc_task *task)  	if (RPC_ASSASSINATED(task))  		return 0;  	task->tk_action = call_start; +	task->tk_status = 0;  	return 1;  }  EXPORT_SYMBOL_GPL(rpc_restart_call); @@ -890,7 +1420,7 @@ call_start(struct rpc_task *task)  	struct rpc_clnt	*clnt = task->tk_client;  	dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid, -			clnt->cl_protname, clnt->cl_vers, +			clnt->cl_program->name, clnt->cl_vers,  			rpc_proc_name(task),  			(RPC_IS_ASYNC(task) ? "async" : "sync")); @@ -913,6 +1443,8 @@ call_reserve(struct rpc_task *task)  	xprt_reserve(task);  } +static void call_retry_reserve(struct rpc_task *task); +  /*   * 1b.	Grok the result of xprt_reserve()   */ @@ -951,8 +1483,10 @@ call_reserveresult(struct rpc_task *task)  	}  	switch (status) { +	case -ENOMEM: +		rpc_delay(task, HZ >> 2);  	case -EAGAIN:	/* woken up; retry */ -		task->tk_action = call_reserve; +		task->tk_action = call_retry_reserve;  		return;  	case -EIO:	/* probably a shutdown */  		break; @@ -965,6 +1499,19 @@ call_reserveresult(struct rpc_task *task)  }  /* + * 1c.	Retry reserving an RPC call slot + */ +static void +call_retry_reserve(struct rpc_task *task) +{ +	dprint_status(task); + +	task->tk_status  = 0; +	task->tk_action  = call_reserveresult; +	xprt_retry_reserve(task); +} + +/*   * 2.	Bind and/or refresh the credentials   */  static void @@ -989,20 +1536,31 @@ call_refreshresult(struct rpc_task *task)  	dprint_status(task);  	task->tk_status = 0; -	task->tk_action = call_allocate; -	if (status >= 0 && rpcauth_uptodatecred(task)) -		return; +	task->tk_action = call_refresh;  	switch (status) { -	case -EACCES: -		rpc_exit(task, -EACCES); -		return; -	case -ENOMEM: -		rpc_exit(task, -ENOMEM); -		return; +	case 0: +		if (rpcauth_uptodatecred(task)) { +			task->tk_action = call_allocate; +			return; +		} +		/* Use rate-limiting and a max number of retries if refresh +		 * had status 0 but failed to update the cred. +		 */  	case -ETIMEDOUT:  		rpc_delay(task, 3*HZ); +	case -EAGAIN: +		status = -EACCES; +	case -EKEYEXPIRED: +		if (!task->tk_cred_retry) +			break; +		task->tk_cred_retry--; +		dprintk("RPC: %5u %s: retry refresh creds\n", +				task->tk_pid, __func__); +		return;  	} -	task->tk_action = call_refresh; +	dprintk("RPC: %5u %s: refresh creds failed with error %d\n", +				task->tk_pid, __func__, status); +	rpc_exit(task, status);  }  /* @@ -1014,7 +1572,7 @@ call_allocate(struct rpc_task *task)  {  	unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack;  	struct rpc_rqst *req = task->tk_rqstp; -	struct rpc_xprt *xprt = task->tk_xprt; +	struct rpc_xprt *xprt = req->rq_xprt;  	struct rpc_procinfo *proc = task->tk_msg.rpc_proc;  	dprint_status(task); @@ -1048,7 +1606,7 @@ call_allocate(struct rpc_task *task)  	dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid); -	if (RPC_IS_ASYNC(task) || !signalled()) { +	if (RPC_IS_ASYNC(task) || !fatal_signal_pending(current)) {  		task->tk_action = call_allocate;  		rpc_delay(task, HZ>>4);  		return; @@ -1089,7 +1647,7 @@ static void  rpc_xdr_encode(struct rpc_task *task)  {  	struct rpc_rqst	*req = task->tk_rqstp; -	kxdrproc_t	encode; +	kxdreproc_t	encode;  	__be32		*p;  	dprint_status(task); @@ -1122,7 +1680,7 @@ rpc_xdr_encode(struct rpc_task *task)  static void  call_bind(struct rpc_task *task)  { -	struct rpc_xprt *xprt = task->tk_xprt; +	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;  	dprint_status(task); @@ -1149,6 +1707,7 @@ call_bind_status(struct rpc_task *task)  		return;  	} +	trace_rpc_bind_status(task);  	switch (task->tk_status) {  	case -ENOMEM:  		dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid); @@ -1162,6 +1721,9 @@ call_bind_status(struct rpc_task *task)  			status = -EOPNOTSUPP;  			break;  		} +		if (task->tk_rebind_retry == 0) +			break; +		task->tk_rebind_retry--;  		rpc_delay(task, 3*HZ);  		goto retry_timeout;  	case -ETIMEDOUT: @@ -1176,11 +1738,10 @@ call_bind_status(struct rpc_task *task)  	case -EPROTONOSUPPORT:  		dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",  				task->tk_pid); -		task->tk_status = 0; -		task->tk_action = call_bind; -		return; +		goto retry_timeout;  	case -ECONNREFUSED:		/* connection problems */  	case -ECONNRESET: +	case -ECONNABORTED:  	case -ENOTCONN:  	case -EHOSTDOWN:  	case -EHOSTUNREACH: @@ -1203,6 +1764,7 @@ call_bind_status(struct rpc_task *task)  	return;  retry_timeout: +	task->tk_status = 0;  	task->tk_action = call_timeout;  } @@ -1212,7 +1774,7 @@ retry_timeout:  static void  call_connect(struct rpc_task *task)  { -	struct rpc_xprt *xprt = task->tk_xprt; +	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;  	dprintk("RPC: %5u call_connect xprt %p %s connected\n",  			task->tk_pid, xprt, @@ -1223,6 +1785,10 @@ call_connect(struct rpc_task *task)  		task->tk_action = call_connect_status;  		if (task->tk_status < 0)  			return; +		if (task->tk_flags & RPC_TASK_NOCONNECT) { +			rpc_exit(task, -ENOTCONN); +			return; +		}  		xprt_connect(task);  	}  } @@ -1238,21 +1804,29 @@ call_connect_status(struct rpc_task *task)  	dprint_status(task); +	trace_rpc_connect_status(task, status);  	task->tk_status = 0; -	if (status >= 0 || status == -EAGAIN) { -		clnt->cl_stats->netreconn++; -		task->tk_action = call_transmit; -		return; -	} -  	switch (status) { -		/* if soft mounted, test if we've timed out */ +	case -ECONNREFUSED: +	case -ECONNRESET: +	case -ECONNABORTED: +	case -ENETUNREACH: +	case -EHOSTUNREACH: +		if (RPC_IS_SOFTCONN(task)) +			break; +		/* retry with existing socket, after a delay */ +		rpc_delay(task, 3*HZ); +	case -EAGAIN: +		/* Check for timeouts before looping back to call_bind */  	case -ETIMEDOUT:  		task->tk_action = call_timeout; -		break; -	default: -		rpc_exit(task, -EIO); +		return; +	case 0: +		clnt->cl_stats->netreconn++; +		task->tk_action = call_transmit; +		return;  	} +	rpc_exit(task, status);  }  /* @@ -1261,18 +1835,18 @@ call_connect_status(struct rpc_task *task)  static void  call_transmit(struct rpc_task *task)  { +	int is_retrans = RPC_WAS_SENT(task); +  	dprint_status(task);  	task->tk_action = call_status;  	if (task->tk_status < 0)  		return; -	task->tk_status = xprt_prepare_transmit(task); -	if (task->tk_status != 0) +	if (!xprt_prepare_transmit(task))  		return;  	task->tk_action = call_transmit_status;  	/* Encode here so that rpcsec_gss can use correct sequence number. */  	if (rpc_task_need_encode(task)) { -		BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);  		rpc_xdr_encode(task);  		/* Did the encode result in an error condition? */  		if (task->tk_status != 0) { @@ -1287,6 +1861,8 @@ call_transmit(struct rpc_task *task)  	xprt_transmit(task);  	if (task->tk_status < 0)  		return; +	if (is_retrans) +		task->tk_client->cl_stats->rpcretrans++;  	/*  	 * On success, ensure that we call xprt_end_transmit() before sleeping  	 * in order to allow access to the socket to other RPC requests. @@ -1295,7 +1871,7 @@ call_transmit(struct rpc_task *task)  	if (rpc_reply_expected(task))  		return;  	task->tk_action = rpc_exit_task; -	rpc_wake_up_queued_task(&task->tk_xprt->pending, task); +	rpc_wake_up_queued_task(&task->tk_rqstp->rq_xprt->pending, task);  }  /* @@ -1340,13 +1916,14 @@ call_transmit_status(struct rpc_task *task)  			break;  		}  	case -ECONNRESET: +	case -ECONNABORTED:  	case -ENOTCONN:  	case -EPIPE:  		rpc_task_force_reencode(task);  	}  } -#if defined(CONFIG_NFS_V4_1) +#if defined(CONFIG_SUNRPC_BACKCHANNEL)  /*   * 5b.	Send the backchannel RPC reply.  On error, drop the reply.  In   * addition, disconnect on connectivity errors. @@ -1356,9 +1933,7 @@ call_bc_transmit(struct rpc_task *task)  {  	struct rpc_rqst *req = task->tk_rqstp; -	BUG_ON(task->tk_status != 0); -	task->tk_status = xprt_prepare_transmit(task); -	if (task->tk_status == -EAGAIN) { +	if (!xprt_prepare_transmit(task)) {  		/*  		 * Could not reserve the transport. Try again after the  		 * transport is released. @@ -1395,7 +1970,7 @@ call_bc_transmit(struct rpc_task *task)  		 */  		printk(KERN_NOTICE "RPC: Could not send backchannel reply "  			"error: %d\n", task->tk_status); -		xprt_conditional_disconnect(task->tk_xprt, +		xprt_conditional_disconnect(req->rq_xprt,  			req->rq_connect_cookie);  		break;  	default: @@ -1403,14 +1978,14 @@ call_bc_transmit(struct rpc_task *task)  		 * We were unable to reply and will have to drop the  		 * request.  The server should reconnect and retransmit.  		 */ -		BUG_ON(task->tk_status == -EAGAIN); +		WARN_ON_ONCE(task->tk_status == -EAGAIN);  		printk(KERN_NOTICE "RPC: Could not send backchannel reply "  			"error: %d\n", task->tk_status);  		break;  	}  	rpc_wake_up_queued_task(&req->rq_xprt->pending, task);  } -#endif /* CONFIG_NFS_V4_1 */ +#endif /* CONFIG_SUNRPC_BACKCHANNEL */  /*   * 6.	Sort out the RPC call status @@ -1433,11 +2008,16 @@ call_status(struct rpc_task *task)  		return;  	} +	trace_rpc_call_status(task);  	task->tk_status = 0;  	switch(status) {  	case -EHOSTDOWN:  	case -EHOSTUNREACH:  	case -ENETUNREACH: +		if (RPC_IS_SOFTCONN(task)) { +			rpc_exit(task, status); +			break; +		}  		/*  		 * Delay any retries for 3 seconds, then handle as if it  		 * were a timeout. @@ -1445,12 +2025,14 @@ call_status(struct rpc_task *task)  		rpc_delay(task, 3*HZ);  	case -ETIMEDOUT:  		task->tk_action = call_timeout; -		if (task->tk_client->cl_discrtry) -			xprt_conditional_disconnect(task->tk_xprt, +		if (!(task->tk_flags & RPC_TASK_NO_RETRANS_TIMEOUT) +		    && task->tk_client->cl_discrtry) +			xprt_conditional_disconnect(req->rq_xprt,  					req->rq_connect_cookie);  		break; -	case -ECONNRESET:  	case -ECONNREFUSED: +	case -ECONNRESET: +	case -ECONNABORTED:  		rpc_force_rebind(clnt);  		rpc_delay(task, 3*HZ);  	case -EPIPE: @@ -1467,7 +2049,7 @@ call_status(struct rpc_task *task)  	default:  		if (clnt->cl_chatty)  			printk("%s: RPC call returned error %d\n", -			       clnt->cl_protname, -status); +			       clnt->cl_program->name, -status);  		rpc_exit(task, status);  	}  } @@ -1495,18 +2077,29 @@ call_timeout(struct rpc_task *task)  		return;  	}  	if (RPC_IS_SOFT(task)) { -		if (clnt->cl_chatty) +		if (clnt->cl_chatty) { +			rcu_read_lock();  			printk(KERN_NOTICE "%s: server %s not responding, timed out\n", -				clnt->cl_protname, clnt->cl_server); -		rpc_exit(task, -EIO); +				clnt->cl_program->name, +				rcu_dereference(clnt->cl_xprt)->servername); +			rcu_read_unlock(); +		} +		if (task->tk_flags & RPC_TASK_TIMEOUT) +			rpc_exit(task, -ETIMEDOUT); +		else +			rpc_exit(task, -EIO);  		return;  	}  	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {  		task->tk_flags |= RPC_CALL_MAJORSEEN; -		if (clnt->cl_chatty) +		if (clnt->cl_chatty) { +			rcu_read_lock();  			printk(KERN_NOTICE "%s: server %s not responding, still trying\n", -			clnt->cl_protname, clnt->cl_server); +			clnt->cl_program->name, +			rcu_dereference(clnt->cl_xprt)->servername); +			rcu_read_unlock(); +		}  	}  	rpc_force_rebind(clnt);  	/* @@ -1516,7 +2109,6 @@ call_timeout(struct rpc_task *task)  	rpcauth_invalcred(task);  retry: -	clnt->cl_stats->rpcretrans++;  	task->tk_action = call_bind;  	task->tk_status = 0;  } @@ -1529,16 +2121,19 @@ call_decode(struct rpc_task *task)  {  	struct rpc_clnt	*clnt = task->tk_client;  	struct rpc_rqst	*req = task->tk_rqstp; -	kxdrproc_t	decode = task->tk_msg.rpc_proc->p_decode; +	kxdrdproc_t	decode = task->tk_msg.rpc_proc->p_decode;  	__be32		*p; -	dprintk("RPC: %5u call_decode (status %d)\n", -			task->tk_pid, task->tk_status); +	dprint_status(task);  	if (task->tk_flags & RPC_CALL_MAJORSEEN) { -		if (clnt->cl_chatty) +		if (clnt->cl_chatty) { +			rcu_read_lock();  			printk(KERN_NOTICE "%s: server %s OK\n", -				clnt->cl_protname, clnt->cl_server); +				clnt->cl_program->name, +				rcu_dereference(clnt->cl_xprt)->servername); +			rcu_read_unlock(); +		}  		task->tk_flags &= ~RPC_CALL_MAJORSEEN;  	} @@ -1556,11 +2151,10 @@ call_decode(struct rpc_task *task)  	if (req->rq_rcv_buf.len < 12) {  		if (!RPC_IS_SOFT(task)) {  			task->tk_action = call_bind; -			clnt->cl_stats->rpcretrans++;  			goto out_retry;  		}  		dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n", -				clnt->cl_protname, task->tk_status); +				clnt->cl_program->name, task->tk_status);  		task->tk_action = call_timeout;  		goto out_retry;  	} @@ -1587,7 +2181,7 @@ out_retry:  	if (task->tk_rqstp == req) {  		req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;  		if (task->tk_client->cl_discrtry) -			xprt_conditional_disconnect(task->tk_xprt, +			xprt_conditional_disconnect(req->rq_xprt,  					req->rq_connect_cookie);  	}  } @@ -1601,7 +2195,7 @@ rpc_encode_header(struct rpc_task *task)  	/* FIXME: check buffer size? */ -	p = xprt_skip_transport_header(task->tk_xprt, p); +	p = xprt_skip_transport_header(req->rq_xprt, p);  	*p++ = req->rq_xid;		/* XID */  	*p++ = htonl(RPC_CALL);		/* CALL */  	*p++ = htonl(RPC_VERSION);	/* RPC version */ @@ -1616,6 +2210,7 @@ rpc_encode_header(struct rpc_task *task)  static __be32 *  rpc_verify_header(struct rpc_task *task)  { +	struct rpc_clnt *clnt = task->tk_client;  	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];  	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;  	__be32	*p = iov->iov_base; @@ -1631,7 +2226,8 @@ rpc_verify_header(struct rpc_task *task)  		dprintk("RPC: %5u %s: XDR representation not a multiple of"  		       " 4 bytes: 0x%x\n", task->tk_pid, __func__,  		       task->tk_rqstp->rq_rcv_buf.len); -		goto out_eio; +		error = -EIO; +		goto out_err;  	}  	if ((len -= 3) < 0)  		goto out_overflow; @@ -1640,6 +2236,7 @@ rpc_verify_header(struct rpc_task *task)  	if ((n = ntohl(*p++)) != RPC_REPLY) {  		dprintk("RPC: %5u %s: not an RPC reply: %x\n",  			task->tk_pid, __func__, n); +		error = -EIO;  		goto out_garbage;  	} @@ -1647,19 +2244,19 @@ rpc_verify_header(struct rpc_task *task)  		if (--len < 0)  			goto out_overflow;  		switch ((n = ntohl(*p++))) { -			case RPC_AUTH_ERROR: -				break; -			case RPC_MISMATCH: -				dprintk("RPC: %5u %s: RPC call version " -						"mismatch!\n", -						task->tk_pid, __func__); -				error = -EPROTONOSUPPORT; -				goto out_err; -			default: -				dprintk("RPC: %5u %s: RPC call rejected, " -						"unknown error: %x\n", -						task->tk_pid, __func__, n); -				goto out_eio; +		case RPC_AUTH_ERROR: +			break; +		case RPC_MISMATCH: +			dprintk("RPC: %5u %s: RPC call version mismatch!\n", +				task->tk_pid, __func__); +			error = -EPROTONOSUPPORT; +			goto out_err; +		default: +			dprintk("RPC: %5u %s: RPC call rejected, " +				"unknown error: %x\n", +				task->tk_pid, __func__, n); +			error = -EIO; +			goto out_err;  		}  		if (--len < 0)  			goto out_overflow; @@ -1689,8 +2286,11 @@ rpc_verify_header(struct rpc_task *task)  			task->tk_action = call_bind;  			goto out_retry;  		case RPC_AUTH_TOOWEAK: +			rcu_read_lock();  			printk(KERN_NOTICE "RPC: server %s requires stronger " -			       "authentication.\n", task->tk_client->cl_server); +			       "authentication.\n", +			       rcu_dereference(clnt->cl_xprt)->servername); +			rcu_read_unlock();  			break;  		default:  			dprintk("RPC: %5u %s: unknown auth error: %x\n", @@ -1701,9 +2301,11 @@ rpc_verify_header(struct rpc_task *task)  				task->tk_pid, __func__, n);  		goto out_err;  	} -	if (!(p = rpcauth_checkverf(task, p))) { -		dprintk("RPC: %5u %s: auth check failed\n", -				task->tk_pid, __func__); +	p = rpcauth_checkverf(task, p); +	if (IS_ERR(p)) { +		error = PTR_ERR(p); +		dprintk("RPC: %5u %s: auth check failed with %d\n", +				task->tk_pid, __func__, error);  		goto out_garbage;		/* bad verifier, retry */  	}  	len = p - (__be32 *)iov->iov_base - 1; @@ -1713,28 +2315,27 @@ rpc_verify_header(struct rpc_task *task)  	case RPC_SUCCESS:  		return p;  	case RPC_PROG_UNAVAIL: -		dprintk("RPC: %5u %s: program %u is unsupported by server %s\n", -				task->tk_pid, __func__, -				(unsigned int)task->tk_client->cl_prog, -				task->tk_client->cl_server); +		dprintk_rcu("RPC: %5u %s: program %u is unsupported " +				"by server %s\n", task->tk_pid, __func__, +				(unsigned int)clnt->cl_prog, +				rcu_dereference(clnt->cl_xprt)->servername);  		error = -EPFNOSUPPORT;  		goto out_err;  	case RPC_PROG_MISMATCH: -		dprintk("RPC: %5u %s: program %u, version %u unsupported by " -				"server %s\n", task->tk_pid, __func__, -				(unsigned int)task->tk_client->cl_prog, -				(unsigned int)task->tk_client->cl_vers, -				task->tk_client->cl_server); +		dprintk_rcu("RPC: %5u %s: program %u, version %u unsupported " +				"by server %s\n", task->tk_pid, __func__, +				(unsigned int)clnt->cl_prog, +				(unsigned int)clnt->cl_vers, +				rcu_dereference(clnt->cl_xprt)->servername);  		error = -EPROTONOSUPPORT;  		goto out_err;  	case RPC_PROC_UNAVAIL: -		dprintk("RPC: %5u %s: proc %s unsupported by program %u, " +		dprintk_rcu("RPC: %5u %s: proc %s unsupported by program %u, "  				"version %u on server %s\n",  				task->tk_pid, __func__,  				rpc_proc_name(task), -				task->tk_client->cl_prog, -				task->tk_client->cl_vers, -				task->tk_client->cl_server); +				clnt->cl_prog, clnt->cl_vers, +				rcu_dereference(clnt->cl_xprt)->servername);  		error = -EOPNOTSUPP;  		goto out_err;  	case RPC_GARBAGE_ARGS: @@ -1748,7 +2349,7 @@ rpc_verify_header(struct rpc_task *task)  	}  out_garbage: -	task->tk_client->cl_stats->rpcgarbage++; +	clnt->cl_stats->rpcgarbage++;  	if (task->tk_garb_retry) {  		task->tk_garb_retry--;  		dprintk("RPC: %5u %s: retrying\n", @@ -1757,8 +2358,6 @@ out_garbage:  out_retry:  		return ERR_PTR(-EAGAIN);  	} -out_eio: -	error = -EIO;  out_err:  	rpc_exit(task, error);  	dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid, @@ -1770,12 +2369,11 @@ out_overflow:  	goto out_garbage;  } -static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj) +static void rpcproc_encode_null(void *rqstp, struct xdr_stream *xdr, void *obj)  { -	return 0;  } -static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj) +static int rpcproc_decode_null(void *rqstp, struct xdr_stream *xdr, void *obj)  {  	return 0;  } @@ -1824,33 +2422,26 @@ static void rpc_show_task(const struct rpc_clnt *clnt,  			  const struct rpc_task *task)  {  	const char *rpc_waitq = "none"; -	char *p, action[KSYM_SYMBOL_LEN];  	if (RPC_IS_QUEUED(task))  		rpc_waitq = rpc_qname(task->tk_waitqueue); -	/* map tk_action pointer to a function name; then trim off -	 * the "+0x0 [sunrpc]" */ -	sprint_symbol(action, (unsigned long)task->tk_action); -	p = strchr(action, '+'); -	if (p) -		*p = '\0'; - -	printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%s q:%s\n", +	printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n",  		task->tk_pid, task->tk_flags, task->tk_status,  		clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops, -		clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task), -		action, rpc_waitq); +		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task), +		task->tk_action, rpc_waitq);  } -void rpc_show_tasks(void) +void rpc_show_tasks(struct net *net)  {  	struct rpc_clnt *clnt;  	struct rpc_task *task;  	int header = 0; +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); -	spin_lock(&rpc_client_lock); -	list_for_each_entry(clnt, &all_clients, cl_clients) { +	spin_lock(&sn->rpc_client_lock); +	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {  		spin_lock(&clnt->cl_lock);  		list_for_each_entry(task, &clnt->cl_tasks, tk_task) {  			if (!header) { @@ -1861,6 +2452,6 @@ void rpc_show_tasks(void)  		}  		spin_unlock(&clnt->cl_lock);  	} -	spin_unlock(&rpc_client_lock); +	spin_unlock(&sn->rpc_client_lock);  }  #endif  | 
