Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ecf78286 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

Merge branch 'multipath'

* multipath:
  NFS add callback_ops to nfs4_proc_bind_conn_to_session_callback
  pnfs/NFSv4.1: Add multipath capabilities to pNFS flexfiles servers over NFSv3
  SUNRPC: Allow addition of new transports to a struct rpc_clnt
  NFSv4.1: nfs4_proc_bind_conn_to_session must iterate over all connections
  SUNRPC: Make NFS swap work with multipath
  SUNRPC: Add a helper to apply a function to all the rpc_clnt's transports
  SUNRPC: Allow caller to specify the transport to use
  SUNRPC: Use the multipath iterator to assign a transport to each task
  SUNRPC: Make rpc_clnt store the multipath iterators
  SUNRPC: Add a structure to track multiple transports
  SUNRPC: Make freeing of struct xprt rcu-safe
  SUNRPC: Uninline xprt_get(); It isn't performance critical.
  SUNRPC: Reorder rpc_task to put waitqueue related info in same cachelines
  SUNRPC: Remove unused function rpc_task_reset_client
parents cc1f9000 02a95dee
Loading
Loading
Loading
Loading
+58 −3
Original line number Diff line number Diff line
@@ -6782,13 +6782,26 @@ nfs41_same_server_scope(struct nfs41_server_scope *a,
	return false;
}

static void
nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
{
}

static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = {
	.rpc_call_done =  &nfs4_bind_one_conn_to_session_done,
};

/*
 * nfs4_proc_bind_conn_to_session()
 * nfs4_proc_bind_one_conn_to_session()
 *
 * The 4.1 client currently uses the same TCP connection for the
 * fore and backchannel.
 */
int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred)
static
int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
		struct rpc_xprt *xprt,
		struct nfs_client *clp,
		struct rpc_cred *cred)
{
	int status;
	struct nfs41_bind_conn_to_session_args args = {
@@ -6803,6 +6816,14 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
		.rpc_resp = &res,
		.rpc_cred = cred,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = clnt,
		.rpc_xprt = xprt,
		.callback_ops = &nfs4_bind_one_conn_to_session_ops,
		.rpc_message = &msg,
		.flags = RPC_TASK_TIMEOUT,
	};
	struct rpc_task *task;

	dprintk("--> %s\n", __func__);

@@ -6810,7 +6831,16 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
	if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
		args.dir = NFS4_CDFC4_FORE;

	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
	/* Do not set the backchannel flag unless this is clnt->cl_xprt */
	if (xprt != rcu_access_pointer(clnt->cl_xprt))
		args.dir = NFS4_CDFC4_FORE;

	task = rpc_run_task(&task_setup_data);
	if (!IS_ERR(task)) {
		status = task->tk_status;
		rpc_put_task(task);
	} else
		status = PTR_ERR(task);
	trace_nfs4_bind_conn_to_session(clp, status);
	if (status == 0) {
		if (memcmp(res.sessionid.data,
@@ -6837,6 +6867,31 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
	return status;
}

struct rpc_bind_conn_calldata {
	struct nfs_client *clp;
	struct rpc_cred *cred;
};

static int
nfs4_proc_bind_conn_to_session_callback(struct rpc_clnt *clnt,
		struct rpc_xprt *xprt,
		void *calldata)
{
	struct rpc_bind_conn_calldata *p = calldata;

	return nfs4_proc_bind_one_conn_to_session(clnt, xprt, p->clp, p->cred);
}

int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred)
{
	struct rpc_bind_conn_calldata data = {
		.clp = clp,
		.cred = cred,
	};
	return rpc_clnt_iterate_for_each_xprt(clp->cl_rpcclient,
			nfs4_proc_bind_conn_to_session_callback, &data);
}

/*
 * Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map
 * and operations we'd like to see to enable certain features in the allow map
+13 −3
Original line number Diff line number Diff line
@@ -606,12 +606,22 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
		dprintk("%s: DS %s: trying address %s\n",
			__func__, ds->ds_remotestr, da->da_remotestr);

		if (!IS_ERR(clp)) {
			struct xprt_create xprt_args = {
				.ident = XPRT_TRANSPORT_TCP,
				.net = clp->cl_net,
				.dstaddr = (struct sockaddr *)&da->da_addr,
				.addrlen = da->da_addrlen,
				.servername = clp->cl_hostname,
			};
			/* Add this address as an alias */
			rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
					rpc_clnt_test_and_add_xprt, NULL);
		} else
			clp = get_v3_ds_connect(mds_srv->nfs_client,
					(struct sockaddr *)&da->da_addr,
					da->da_addrlen, IPPROTO_TCP,
					timeo, retrans, au_flavor);
		if (!IS_ERR(clp))
			break;
	}

	if (IS_ERR(clp)) {
+17 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <asm/signal.h>
#include <linux/path.h>
#include <net/ipv6.h>
#include <linux/sunrpc/xprtmultipath.h>

struct rpc_inode;

@@ -67,6 +68,7 @@ struct rpc_clnt {
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
	struct dentry		*cl_debugfs;	/* debugfs directory */
#endif
	struct rpc_xprt_iter	cl_xpi;
};

/*
@@ -139,7 +141,6 @@ struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
					struct rpc_xprt *xprt);
struct rpc_clnt	*rpc_bind_new_program(struct rpc_clnt *,
				const struct rpc_program *, u32);
void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *,
				rpc_authflavor_t);
@@ -181,6 +182,21 @@ size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
const char	*rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
int		rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);

int 		rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
			int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *),
			void *data);

int 		rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
			struct rpc_xprt_switch *xps,
			struct rpc_xprt *xprt,
			void *dummy);
int		rpc_clnt_add_xprt(struct rpc_clnt *, struct xprt_create *,
			int (*setup)(struct rpc_clnt *,
				struct rpc_xprt_switch *,
				struct rpc_xprt *,
				void *),
			void *data);

const char *rpc_proc_name(const struct rpc_task *task);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_CLNT_H */
+18 −14
Original line number Diff line number Diff line
@@ -42,40 +42,43 @@ struct rpc_wait {
 */
struct rpc_task {
	atomic_t		tk_count;	/* Reference count */
	int			tk_status;	/* result of last operation */
	struct list_head	tk_task;	/* global list of tasks */
	struct rpc_clnt *	tk_client;	/* RPC client */
	struct rpc_rqst *	tk_rqstp;	/* RPC request */

	/*
	 * RPC call state
	 */
	struct rpc_message	tk_msg;		/* RPC call info */

	/*
	 * callback	to be executed after waking up
	 * action	next procedure for async tasks
	 * tk_ops	caller callbacks
	 */
	void			(*tk_callback)(struct rpc_task *);
	void			(*tk_action)(struct rpc_task *);
	const struct rpc_call_ops *tk_ops;
	void *			tk_calldata;

	unsigned long		tk_timeout;	/* timeout for rpc_sleep() */
	unsigned long		tk_runstate;	/* Task run status */
	struct workqueue_struct	*tk_workqueue;	/* Normally rpciod, but could
						 * be any workqueue
						 */

	struct rpc_wait_queue 	*tk_waitqueue;	/* RPC wait queue we're on */
	union {
		struct work_struct	tk_work;	/* Async task work queue */
		struct rpc_wait		tk_wait;	/* RPC wait */
	} u;

	/*
	 * RPC call state
	 */
	struct rpc_message	tk_msg;		/* RPC call info */
	void *			tk_calldata;	/* Caller private data */
	const struct rpc_call_ops *tk_ops;	/* Caller callbacks */

	struct rpc_clnt *	tk_client;	/* RPC client */
	struct rpc_xprt *	tk_xprt;	/* Transport */

	struct rpc_rqst *	tk_rqstp;	/* RPC request */

	struct workqueue_struct	*tk_workqueue;	/* Normally rpciod, but could
						 * be any workqueue
						 */
	ktime_t			tk_start;	/* RPC task init timestamp */

	pid_t			tk_owner;	/* Process id for batching tasks */
	int			tk_status;	/* result of last operation */
	unsigned short		tk_flags;	/* misc flags */
	unsigned short		tk_timeouts;	/* maj timeouts */

@@ -100,6 +103,7 @@ struct rpc_call_ops {
struct rpc_task_setup {
	struct rpc_task *task;
	struct rpc_clnt *rpc_client;
	struct rpc_xprt *rpc_xprt;
	const struct rpc_message *rpc_message;
	const struct rpc_call_ops *callback_ops;
	void *callback_data;
+9 −13
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/ktime.h>
#include <linux/kref.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h>
@@ -166,7 +167,7 @@ enum xprt_transports {
};

struct rpc_xprt {
	atomic_t		count;		/* Reference count */
	struct kref		kref;		/* Reference count */
	struct rpc_xprt_ops *	ops;		/* transport methods */

	const struct rpc_timeout *timeout;	/* timeout parms */
@@ -196,6 +197,11 @@ struct rpc_xprt {
						   transport */
	unsigned int		bind_index;	/* bind function index */

	/*
	 * Multipath
	 */
	struct list_head	xprt_switch;

	/*
	 * Connection of transports
	 */
@@ -256,6 +262,7 @@ struct rpc_xprt {
	struct dentry		*debugfs;		/* debugfs directory */
	atomic_t		inject_disconnect;
#endif
	struct rcu_head		rcu;
};

#if defined(CONFIG_SUNRPC_BACKCHANNEL)
@@ -318,24 +325,13 @@ int xprt_adjust_timeout(struct rpc_rqst *req);
void			xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
void			xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
void			xprt_release(struct rpc_task *task);
struct rpc_xprt *	xprt_get(struct rpc_xprt *xprt);
void			xprt_put(struct rpc_xprt *xprt);
struct rpc_xprt *	xprt_alloc(struct net *net, size_t size,
				unsigned int num_prealloc,
				unsigned int max_req);
void			xprt_free(struct rpc_xprt *);

/**
 * xprt_get - return a reference to an RPC transport.
 * @xprt: pointer to the transport
 *
 */
static inline struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
{
	if (atomic_inc_not_zero(&xprt->count))
		return xprt;
	return NULL;
}

static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
{
	return p + xprt->tsh_size;
Loading