diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 8aa865b..0425aaa 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -70,6 +70,10 @@ struct rpc_clnt {
 	struct dentry		*cl_debugfs;	/* debugfs directory */
 #endif
 	struct rpc_xprt_iter	cl_xpi;
+
+#if IS_ENABLED(CONFIG_ENFS)
+	bool cl_enfs;
+#endif
 };
 
 /*
@@ -124,6 +128,9 @@ struct rpc_create_args {
 	unsigned long		flags;
 	char			*client_name;
 	struct svc_xprt		*bc_xprt;	/* NFSv4.1 backchannel */
+#if IS_ENABLED(CONFIG_ENFS)
+	void *multipath_option;
+#endif
 };
 
 struct rpc_add_xprt_test {
@@ -221,6 +228,13 @@ bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
 			const struct sockaddr *sap);
 void rpc_cleanup_clids(void);
 
+#if IS_ENABLED(CONFIG_ENFS)
+int
+rpc_clnt_test_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
+		   const struct rpc_call_ops *ops, void *data, int flags);
+struct rpc_xprt *rpc_task_get_next_xprt(struct rpc_clnt *clnt);
+#endif /* CONFIG_ENFS */
+
 static inline int rpc_reply_expected(struct rpc_task *task)
 {
 	return (task->tk_msg.rpc_proc != NULL) &&
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index ad2e243..124f5a0 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -90,6 +90,9 @@ struct rpc_task {
 				tk_garb_retry : 2,
 				tk_cred_retry : 2,
 				tk_rebind_retry : 2;
+#if IS_ENABLED(CONFIG_ENFS)
+	unsigned long		tk_major_timeo;	/* major timeout ticks */
+#endif
 };
 
 typedef void			(*rpc_action)(struct rpc_task *);
@@ -118,6 +121,9 @@ struct rpc_task_setup {
  */
 #define RPC_TASK_ASYNC		0x0001		/* is an async task */
 #define RPC_TASK_SWAPPER	0x0002		/* is swapping in/out */
+#if IS_ENABLED(CONFIG_ENFS)
+#define RPC_TASK_FIXED	0x0004		/* detect xprt status task */
+#endif
 #define RPC_CALL_MAJORSEEN	0x0020		/* major timeout seen */
 #define RPC_TASK_ROOTCREDS	0x0040		/* force root creds */
 #define RPC_TASK_DYNAMIC	0x0080		/* task was kmalloc'ed */
@@ -257,6 +263,9 @@ void		rpc_destroy_mempool(void);
 extern struct workqueue_struct *rpciod_workqueue;
 extern struct workqueue_struct *xprtiod_workqueue;
 void		rpc_prepare_task(struct rpc_task *task);
+#if IS_ENABLED(CONFIG_ENFS)
+void rpc_init_task_retry_counters(struct rpc_task *task);
+#endif
 
 static inline int rpc_wait_for_completion_task(struct rpc_task *task)
 {
diff --git a/include/linux/sunrpc/sunrpc_enfs_adapter.h b/include/linux/sunrpc/sunrpc_enfs_adapter.h
new file mode 100644
index 0000000..cdd7fa6
--- /dev/null
+++ b/include/linux/sunrpc/sunrpc_enfs_adapter.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Client-side SUNRPC ENFS adapter header.
+ * Copyright (c) 2023. Huawei Technologies Co., Ltd. All rights reserved.
+ */
+#ifndef _SUNRPC_ENFS_ADAPTER_H_
+#define _SUNRPC_ENFS_ADAPTER_H_
+#include <linux/sunrpc/clnt.h>
+
+#if IS_ENABLED(CONFIG_ENFS)
+
+static inline void rpc_xps_nactive_add_one(struct rpc_xprt_switch *xps)
+{
+	xps->xps_nactive--;
+}
+
+static inline void rpc_xps_nactive_sub_one(struct rpc_xprt_switch *xps)
+{
+	xps->xps_nactive--;
+}
+
+struct rpc_xprt	*rpc_task_get_xprt
+(struct rpc_clnt *clnt, struct rpc_xprt *xprt);
+
+struct rpc_multipath_ops {
+	struct module *owner;
+	void (*create_clnt)(struct rpc_create_args *args,
+			    struct rpc_clnt *clnt);
+	void (*releas_clnt)(struct rpc_clnt *clnt);
+	void (*create_xprt)(struct rpc_xprt *xprt);
+	void (*destroy_xprt)(struct rpc_xprt *xprt);
+	void (*xprt_iostat)(struct rpc_task *task);
+	void (*failover_handle)(struct rpc_task *task);
+	bool (*task_need_call_start_again)(struct rpc_task *task);
+	void (*adjust_task_timeout)(struct rpc_task *task, void *condition);
+	void (*init_task_req)(struct rpc_task *task, struct rpc_rqst *req);
+	bool (*prepare_transmit)(struct rpc_task *task);
+	void (*set_transport)(struct rpc_task *task, struct rpc_clnt *clnt);
+};
+
+extern struct rpc_multipath_ops __rcu *multipath_ops;
+void rpc_init_task_retry_counters(struct rpc_task *task);
+int rpc_multipath_ops_register(struct rpc_multipath_ops *ops);
+int rpc_multipath_ops_unregister(struct rpc_multipath_ops *ops);
+struct rpc_multipath_ops *rpc_multipath_ops_get(void);
+void rpc_multipath_ops_put(struct rpc_multipath_ops *ops);
+void rpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt);
+void rpc_multipath_ops_create_clnt(struct rpc_create_args *args,
+				   struct rpc_clnt *clnt);
+void rpc_multipath_ops_releas_clnt(struct rpc_clnt *clnt);
+bool rpc_multipath_ops_create_xprt(struct rpc_xprt *xprt);
+void rpc_multipath_ops_destroy_xprt(struct rpc_xprt *xprt);
+void rpc_multipath_ops_xprt_iostat(struct rpc_task *task);
+void rpc_multipath_ops_failover_handle(struct rpc_task *task);
+bool rpc_multipath_ops_task_need_call_start_again(struct rpc_task *task);
+void rpc_multipath_ops_adjust_task_timeout(struct rpc_task *task,
+					   void *condition);
+void rpc_multipath_ops_init_task_req(struct rpc_task *task,
+				     struct rpc_rqst *req);
+bool rpc_multipath_ops_prepare_transmit(struct rpc_task *task);
+void rpc_multipath_ops_set_transport(struct rpc_task *task,
+				struct rpc_clnt *clnt);
+#else
+static inline struct rpc_xprt *rpc_task_get_xprt(struct rpc_clnt *clnt,
+						 struct rpc_xprt *xprt)
+{
+	return NULL;
+}
+
+static inline void rpc_task_release_xprt(struct rpc_clnt *clnt,
+					 struct rpc_xprt *xprt)
+{
+}
+
+static inline void rpc_xps_nactive_add_one(struct rpc_xprt_switch *xps)
+{
+}
+
+static inline void rpc_xps_nactive_sub_one(struct rpc_xprt_switch *xps)
+{
+}
+
+static inline void rpc_multipath_ops_create_clnt
+(struct rpc_create_args *args, struct rpc_clnt *clnt)
+{
+}
+
+static inline void rpc_multipath_ops_releas_clnt(struct rpc_clnt *clnt)
+{
+}
+
+static inline bool rpc_multipath_ops_create_xprt(struct rpc_xprt *xprt)
+{
+	return false;
+}
+
+static inline void rpc_multipath_ops_destroy_xprt(struct rpc_xprt *xprt)
+{
+}
+
+static inline void rpc_multipath_ops_xprt_iostat(struct rpc_task *task)
+{
+}
+
+static inline void rpc_multipath_ops_failover_handle(struct rpc_task *task)
+{
+}
+
+static inline
+bool rpc_multipath_ops_task_need_call_start_again(struct rpc_task *task)
+{
+	return false;
+}
+
+static inline void
+rpc_multipath_ops_adjust_task_timeout(struct rpc_task *task, void *condition)
+{
+}
+
+static inline void
+rpc_multipath_ops_init_task_req(struct rpc_task *task, struct rpc_rqst *req)
+{
+}
+
+static inline bool rpc_multipath_ops_prepare_transmit(struct rpc_task *task)
+{
+	return false;
+}
+
+static inline void
+rpc_multipath_ops_set_transport(struct rpc_task *task, struct rpc_clnt *clnt)
+{
+}
+
+#endif
+#endif // _SUNRPC_ENFS_ADAPTER_H_
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index ccfacca..2e47b35 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -279,6 +279,10 @@ struct rpc_xprt {
 	atomic_t		inject_disconnect;
 #endif
 	struct rcu_head		rcu;
+#if IS_ENABLED(CONFIG_ENFS)
+	atomic_long_t	queuelen;
+	void *multipath_context;
+#endif
 };
 
 #if defined(CONFIG_SUNRPC_BACKCHANNEL)
diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
index af1257c..5677a46 100644
--- a/include/linux/sunrpc/xprtmultipath.h
+++ b/include/linux/sunrpc/xprtmultipath.h
@@ -22,6 +22,11 @@ struct rpc_xprt_switch {
 	const struct rpc_xprt_iter_ops *xps_iter_ops;
 
 	struct rcu_head		xps_rcu;
+#if IS_ENABLED(CONFIG_ENFS)
+	unsigned int		xps_nactive;
+	atomic_long_t		xps_queuelen;
+	unsigned long		xps_tmp_time;
+#endif
 };
 
 struct rpc_xprt_iter {
@@ -69,4 +74,8 @@ extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi);
 
 extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
 		const struct sockaddr *sap);
+#if IS_ENABLED(CONFIG_ENFS)
+extern void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
+		struct rpc_xprt *xprt);
+#endif
 #endif
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 0fc540b..ebdcd02 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -37,6 +37,7 @@
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/metrics.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/sunrpc/sunrpc_enfs_adapter.h>
 #include <trace/events/sunrpc.h>
 
 #include "sunrpc.h"
@@ -490,6 +491,8 @@ static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
 		}
 	}
 
+	rpc_multipath_ops_create_clnt(args, clnt);
+
 	clnt->cl_softrtry = 1;
 	if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
 		clnt->cl_softrtry = 0;
@@ -869,6 +872,8 @@ void rpc_shutdown_client(struct rpc_clnt *clnt)
 			list_empty(&clnt->cl_tasks), 1*HZ);
 	}
 
+	rpc_multipath_ops_releas_clnt(clnt);
+
 	rpc_release_client(clnt);
 }
 EXPORT_SYMBOL_GPL(rpc_shutdown_client);
@@ -981,6 +986,12 @@ void rpc_task_release_transport(struct rpc_task *task)
 
 	if (xprt) {
 		task->tk_xprt = NULL;
+#if IS_ENABLED(CONFIG_ENFS)
+		if (task->tk_client) {
+			rpc_task_release_xprt(task->tk_client, xprt);
+			return;
+		}
+#endif
 		xprt_put(xprt);
 	}
 }
@@ -990,6 +1001,10 @@ void rpc_task_release_client(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
 
+#if IS_ENABLED(CONFIG_ENFS)
+	rpc_task_release_transport(task);
+#endif
+
 	if (clnt != NULL) {
 		/* Remove from client task list */
 		spin_lock(&clnt->cl_lock);
@@ -999,14 +1014,31 @@ void rpc_task_release_client(struct rpc_task *task)
 
 		rpc_release_client(clnt);
 	}
-	rpc_task_release_transport(task);
+
+	if (!IS_ENABLED(CONFIG_ENFS))
+		rpc_task_release_transport(task);
+
 }
 
+#if IS_ENABLED(CONFIG_ENFS)
+struct rpc_xprt *
+rpc_task_get_next_xprt(struct rpc_clnt *clnt)
+{
+	return rpc_task_get_xprt(clnt, xprt_iter_get_next(&clnt->cl_xpi));
+}
+EXPORT_SYMBOL_GPL(rpc_task_get_next_xprt);
+#endif
+
 static
 void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt)
 {
+	rpc_multipath_ops_set_transport(task, clnt);
 	if (!task->tk_xprt)
+#if IS_ENABLED(CONFIG_ENFS)
+		task->tk_xprt = rpc_task_get_next_xprt(clnt);
+#else
 		task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi);
+#endif
 }
 
 static
@@ -1597,6 +1629,14 @@ call_reserveresult(struct rpc_task *task)
 		return;
 	case -EIO:	/* probably a shutdown */
 		break;
+#if IS_ENABLED(CONFIG_ENFS)
+	case -ETIMEDOUT:	/* woken up; restart */
+		if (rpc_multipath_ops_task_need_call_start_again(task)) {
+			rpc_task_release_transport(task);
+			task->tk_action = call_start;
+			return;
+		}
+#endif
 	default:
 		printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
 				__func__, status);
@@ -1962,6 +2002,10 @@ call_transmit(struct rpc_task *task)
 		return;
 	if (!xprt_prepare_transmit(task))
 		return;
+
+	if (rpc_multipath_ops_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)) {
@@ -2277,6 +2321,7 @@ call_timeout(struct rpc_task *task)
 
 retry:
 	task->tk_action = call_bind;
+	rpc_multipath_ops_failover_handle(task);
 	task->tk_status = 0;
 }
 
@@ -2798,8 +2843,12 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
 		xprt->ops->set_connect_timeout(xprt,
 				connect_timeout,
 				reconnect_timeout);
-
+#if IS_ENABLED(CONFIG_ENFS)
+	if (!clnt->cl_enfs)
+		rpc_xprt_switch_set_roundrobin(xps);
+#else
 	rpc_xprt_switch_set_roundrobin(xps);
+#endif
 	if (setup) {
 		ret = setup(clnt, xps, xprt, data);
 		if (ret != 0)
@@ -2961,3 +3010,30 @@ rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
 #endif /* CONFIG_SUNRPC_SWAP */
+
+#if IS_ENABLED(CONFIG_ENFS)
+/* rpc_clnt_test_xprt - Test and add a new transport to a rpc_clnt
+ * @clnt: pointer to struct rpc_clnt
+ * @xprt: pointer struct rpc_xprt
+ * @ops: async operation
+ */
+int
+rpc_clnt_test_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
+		   const struct rpc_call_ops *ops, void *data, int flags)
+{
+	struct rpc_cred *cred;
+	struct rpc_task *task;
+
+	cred = authnull_ops.lookup_cred(NULL, NULL, 0);
+	task = rpc_call_null_helper(clnt, xprt, cred,
+				    RPC_TASK_SOFT | RPC_TASK_SOFTCONN | flags,
+				    ops, data);
+	put_rpccred(cred);
+	if (IS_ERR(task))
+		return PTR_ERR(task);
+
+	rpc_put_task(task);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(rpc_clnt_test_xprt);
+#endif
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index a873c92..2254fea 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -20,7 +20,7 @@
 #include <linux/mutex.h>
 #include <linux/freezer.h>
 
-#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sunrpc_enfs_adapter.h>
 
 #include "sunrpc.h"
 
@@ -962,7 +962,12 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
 	/* Initialize workqueue for async tasks */
 	task->tk_workqueue = task_setup_data->workqueue;
 
+#if IS_ENABLED(CONFIG_ENFS)
+	task->tk_xprt = rpc_task_get_xprt(task_setup_data->rpc_client,
+					  xprt_get(task_setup_data->rpc_xprt));
+#else
 	task->tk_xprt = xprt_get(task_setup_data->rpc_xprt);
+#endif
 
 	if (task->tk_ops->rpc_call_prepare != NULL)
 		task->tk_action = rpc_prepare_task;
diff --git a/net/sunrpc/sunrpc_enfs_adapter.c b/net/sunrpc/sunrpc_enfs_adapter.c
new file mode 100644
index 0000000..106ad73
--- /dev/null
+++ b/net/sunrpc/sunrpc_enfs_adapter.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Client-side SUNRPC ENFS adapter header.
+ * Copyright (c) 2023. Huawei Technologies Co., Ltd. All rights reserved.
+ */
+#include <linux/sunrpc/sunrpc_enfs_adapter.h>
+
+struct rpc_multipath_ops __rcu *multipath_ops;
+
+void rpc_init_task_retry_counters(struct rpc_task *task)
+{
+	/* Initialize retry counters */
+	task->tk_garb_retry = 2;
+	task->tk_cred_retry = 2;
+	task->tk_rebind_retry = 2;
+}
+EXPORT_SYMBOL_GPL(rpc_init_task_retry_counters);
+
+struct rpc_xprt *
+rpc_task_get_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
+{
+	struct rpc_xprt_switch *xps;
+
+	if (!xprt)
+		return NULL;
+	rcu_read_lock();
+	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
+	atomic_long_inc(&xps->xps_queuelen);
+	rcu_read_unlock();
+	atomic_long_inc(&xprt->queuelen);
+
+	return xprt;
+}
+
+int rpc_multipath_ops_register(struct rpc_multipath_ops *ops)
+{
+	struct rpc_multipath_ops *old;
+
+	old = cmpxchg((struct rpc_multipath_ops **)&multipath_ops, NULL, ops);
+	if (!old || old == ops)
+		return 0;
+	pr_err("regist rpc_multipath ops %p fail. old %p\n", ops, old);
+	return -EPERM;
+}
+EXPORT_SYMBOL_GPL(rpc_multipath_ops_register);
+
+int rpc_multipath_ops_unregister(struct rpc_multipath_ops *ops)
+{
+	struct rpc_multipath_ops *old;
+
+	old = cmpxchg((struct rpc_multipath_ops **)&multipath_ops, ops, NULL);
+	if (!old || old == ops)
+		return 0;
+	pr_err("regist rpc_multipath ops %p fail. old %p\n", ops, old);
+	return -EPERM;
+}
+EXPORT_SYMBOL_GPL(rpc_multipath_ops_unregister);
+
+struct rpc_multipath_ops *rpc_multipath_ops_get(void)
+{
+	struct rpc_multipath_ops *ops;
+
+	rcu_read_lock();
+	ops = rcu_dereference(multipath_ops);
+	if (!ops) {
+		rcu_read_unlock();
+		return NULL;
+	}
+	if (!try_module_get(ops->owner))
+		ops = NULL;
+	rcu_read_unlock();
+	return ops;
+}
+EXPORT_SYMBOL_GPL(rpc_multipath_ops_get);
+
+void rpc_multipath_ops_put(struct rpc_multipath_ops *ops)
+{
+	if (ops)
+		module_put(ops->owner);
+}
+EXPORT_SYMBOL_GPL(rpc_multipath_ops_put);
+
+void rpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
+{
+	struct rpc_xprt_switch *xps;
+
+	atomic_long_dec(&xprt->queuelen);
+	rcu_read_lock();
+	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
+	atomic_long_dec(&xps->xps_queuelen);
+	rcu_read_unlock();
+
+	xprt_put(xprt);
+}
+
+void rpc_multipath_ops_create_clnt(struct rpc_create_args *args,
+				   struct rpc_clnt *clnt)
+{
+	struct rpc_multipath_ops *mops;
+
+	if (args->multipath_option) {
+		mops = rpc_multipath_ops_get();
+		if (mops && mops->create_clnt)
+			mops->create_clnt(args, clnt);
+		rpc_multipath_ops_put(mops);
+	}
+}
+
+void rpc_multipath_ops_releas_clnt(struct rpc_clnt *clnt)
+{
+	struct rpc_multipath_ops *mops;
+
+	mops = rpc_multipath_ops_get();
+	if (mops && mops->releas_clnt)
+		mops->releas_clnt(clnt);
+
+	rpc_multipath_ops_put(mops);
+}
+
+bool rpc_multipath_ops_create_xprt(struct rpc_xprt *xprt)
+{
+	struct rpc_multipath_ops *mops = NULL;
+
+	mops = rpc_multipath_ops_get();
+	if (mops && mops->create_xprt) {
+		mops->create_xprt(xprt);
+		if (!xprt->multipath_context) {
+			rpc_multipath_ops_put(mops);
+			return true;
+		}
+	}
+	rpc_multipath_ops_put(mops);
+	return false;
+}
+
+void rpc_multipath_ops_destroy_xprt(struct rpc_xprt *xprt)
+{
+	struct rpc_multipath_ops *mops;
+
+	if (xprt->multipath_context) {
+		mops = rpc_multipath_ops_get();
+		if (mops && mops->destroy_xprt)
+			mops->destroy_xprt(xprt);
+		rpc_multipath_ops_put(mops);
+	}
+}
+
+void rpc_multipath_ops_xprt_iostat(struct rpc_task *task)
+{
+	struct rpc_multipath_ops *mops;
+
+	mops = rpc_multipath_ops_get();
+	if (task->tk_client && mops && mops->xprt_iostat)
+		mops->xprt_iostat(task);
+	rpc_multipath_ops_put(mops);
+}
+
+void rpc_multipath_ops_failover_handle(struct rpc_task *task)
+{
+	struct rpc_multipath_ops *mpath_ops = NULL;
+
+	mpath_ops = rpc_multipath_ops_get();
+	if (mpath_ops && mpath_ops->failover_handle)
+		mpath_ops->failover_handle(task);
+	rpc_multipath_ops_put(mpath_ops);
+}
+
+bool rpc_multipath_ops_task_need_call_start_again(struct rpc_task *task)
+{
+	struct rpc_multipath_ops *mpath_ops = NULL;
+	bool ret = false;
+
+	mpath_ops = rpc_multipath_ops_get();
+	if (mpath_ops && mpath_ops->task_need_call_start_again)
+		ret = mpath_ops->task_need_call_start_again(task);
+	rpc_multipath_ops_put(mpath_ops);
+	return ret;
+}
+
+void rpc_multipath_ops_adjust_task_timeout(struct rpc_task *task,
+					   void *condition)
+{
+	struct rpc_multipath_ops *mops = NULL;
+
+	mops = rpc_multipath_ops_get();
+	if (mops && mops->adjust_task_timeout)
+		mops->adjust_task_timeout(task, NULL);
+	rpc_multipath_ops_put(mops);
+}
+
+void rpc_multipath_ops_init_task_req(struct rpc_task *task,
+				     struct rpc_rqst *req)
+{
+	struct rpc_multipath_ops *mops = NULL;
+
+	mops = rpc_multipath_ops_get();
+	if (mops && mops->init_task_req)
+		mops->init_task_req(task, req);
+	rpc_multipath_ops_put(mops);
+}
+
+bool rpc_multipath_ops_prepare_transmit(struct rpc_task *task)
+{
+	struct rpc_multipath_ops *mops = NULL;
+
+	mops = rpc_multipath_ops_get();
+	if (mops && mops->prepare_transmit) {
+		if (!(mops->prepare_transmit(task))) {
+			rpc_multipath_ops_put(mops);
+			return true;
+		}
+	}
+	rpc_multipath_ops_put(mops);
+	return false;
+}
+
+void rpc_multipath_ops_set_transport(struct rpc_task *task,
+				     struct rpc_clnt *clnt)
+{
+	struct rpc_multipath_ops *mops = NULL;
+
+	mops = rpc_multipath_ops_get();
+	if (mops && mops->set_transport)
+		mops->set_transport(task, clnt);
+	rpc_multipath_ops_put(mops);
+}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index c912bf2..c2b63b3 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -48,6 +48,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/metrics.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/sunrpc/sunrpc_enfs_adapter.h>
 #include <linux/rcupdate.h>
 
 #include <trace/events/sunrpc.h>
@@ -259,6 +260,9 @@ out_sleep:
 	dprintk("RPC: %5u failed to lock transport %p\n",
 			task->tk_pid, xprt);
 	task->tk_timeout = 0;
+
+	rpc_multipath_ops_adjust_task_timeout(task, NULL);
+
 	task->tk_status = -EAGAIN;
 	if (req == NULL)
 		priority = RPC_PRIORITY_LOW;
@@ -560,6 +564,9 @@ void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
 	struct rpc_xprt *xprt = req->rq_xprt;
 
 	task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0;
+
+	rpc_multipath_ops_adjust_task_timeout(task, NULL);
+
 	rpc_sleep_on(&xprt->pending, task, action);
 }
 EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
@@ -1347,6 +1354,9 @@ xprt_request_init(struct rpc_task *task)
 	req->rq_rcv_buf.buflen = 0;
 	req->rq_release_snd_buf = NULL;
 	xprt_reset_majortimeo(req);
+
+	rpc_multipath_ops_init_task_req(task, req);
+
 	dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid,
 			req, ntohl(req->rq_xid));
 }
@@ -1427,6 +1437,9 @@ void xprt_release(struct rpc_task *task)
 		task->tk_ops->rpc_count_stats(task, task->tk_calldata);
 	else if (task->tk_client)
 		rpc_count_iostats(task, task->tk_client->cl_metrics);
+
+	rpc_multipath_ops_xprt_iostat(task);
+
 	spin_lock(&xprt->recv_lock);
 	if (!list_empty(&req->rq_list)) {
 		list_del_init(&req->rq_list);
@@ -1455,6 +1468,7 @@ void xprt_release(struct rpc_task *task)
 	else
 		xprt_free_bc_request(req);
 }
+EXPORT_SYMBOL_GPL(xprt_release);
 
 static void xprt_init(struct rpc_xprt *xprt, struct net *net)
 {
@@ -1528,6 +1542,10 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 		return ERR_PTR(-ENOMEM);
 	}
 
+if (rpc_multipath_ops_create_xprt(xprt)) {
+	xprt_destroy(xprt);
+	return ERR_PTR(-ENOMEM);
+}
 	rpc_xprt_debugfs_register(xprt);
 
 	dprintk("RPC:       created transport %p with %u slots\n", xprt,
@@ -1547,6 +1565,9 @@ static void xprt_destroy_cb(struct work_struct *work)
 	rpc_destroy_wait_queue(&xprt->sending);
 	rpc_destroy_wait_queue(&xprt->backlog);
 	kfree(xprt->servername);
+
+	rpc_multipath_ops_destroy_xprt(xprt);
+
 	/*
 	 * Tear down transport state and free the rpc_xprt
 	 */
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index 6ebaa58..f6a004e 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -18,6 +18,7 @@
 #include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/addr.h>
 #include <linux/sunrpc/xprtmultipath.h>
+#include <linux/sunrpc/sunrpc_enfs_adapter.h>
 
 typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct list_head *head,
 		const struct rpc_xprt *cur);
@@ -26,8 +27,8 @@ static const struct rpc_xprt_iter_ops rpc_xprt_iter_singular;
 static const struct rpc_xprt_iter_ops rpc_xprt_iter_roundrobin;
 static const struct rpc_xprt_iter_ops rpc_xprt_iter_listall;
 
-static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
-		struct rpc_xprt *xprt)
+void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
+				 struct rpc_xprt *xprt)
 {
 	if (unlikely(xprt_get(xprt) == NULL))
 		return;
@@ -36,7 +37,9 @@ static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
 	if (xps->xps_nxprts == 0)
 		xps->xps_net = xprt->xprt_net;
 	xps->xps_nxprts++;
+	rpc_xps_nactive_add_one(xps);
 }
+EXPORT_SYMBOL(xprt_switch_add_xprt_locked);
 
 /**
  * rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch
@@ -63,6 +66,7 @@ static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
 	if (unlikely(xprt == NULL))
 		return;
 	xps->xps_nxprts--;
+	rpc_xps_nactive_sub_one(xps);
 	if (xps->xps_nxprts == 0)
 		xps->xps_net = NULL;
 	smp_wmb();
@@ -84,7 +88,7 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
 	spin_unlock(&xps->xps_lock);
 	xprt_put(xprt);
 }
-
+EXPORT_SYMBOL(rpc_xprt_switch_remove_xprt);
 /**
  * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
  * @xprt: pointer to struct rpc_xprt
@@ -103,6 +107,10 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
 		spin_lock_init(&xps->xps_lock);
 		kref_init(&xps->xps_kref);
 		xps->xps_nxprts = 0;
+#if IS_ENABLED(CONFIG_ENFS)
+		xps->xps_nactive = 0;
+		atomic_long_set(&xps->xps_queuelen, 0);
+#endif
 		INIT_LIST_HEAD(&xps->xps_xprt_list);
 		xps->xps_iter_ops = &rpc_xprt_iter_singular;
 		xprt_switch_add_xprt_locked(xps, xprt);
@@ -148,6 +156,7 @@ struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps)
 		return xps;
 	return NULL;
 }
+EXPORT_SYMBOL(xprt_switch_get);
 
 /**
  * xprt_switch_put - Release a reference to a rpc_xprt_switch
@@ -160,6 +169,7 @@ void xprt_switch_put(struct rpc_xprt_switch *xps)
 	if (xps != NULL)
 		kref_put(&xps->xps_kref, xprt_switch_free);
 }
+EXPORT_SYMBOL(xprt_switch_put);
 
 /**
  * rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch
