@@ -494,6 +494,8 @@ int nfs_create_rpc_client(struct nfs_client *clp,
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags))
args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS;
+ if (test_bit(NFS_CS_SAME_NET_OK, &clp->cl_flags))
+ args.flags |= RPC_CLNT_CREATE_SAME_NET_OK;
if (!IS_ERR(clp->cl_rpcclient))
return 0;
@@ -365,8 +365,10 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
/* Check NFS protocol revision and initialize RPC op vector */
clp->rpc_ops = &nfs_v4_clientops;
- if (clp->cl_minorversion != 0)
+ if (clp->cl_minorversion != 0) {
+ __set_bit(NFS_CS_SAME_NET_OK, &clp->cl_flags);
__set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
+ }
__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
__set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
@@ -42,6 +42,7 @@ struct nfs_client {
#define NFS_CS_MIGRATION 2 /* - transparent state migr */
#define NFS_CS_INFINITE_SLOTS 3 /* - don't limit TCP slots */
#define NFS_CS_NO_RETRANS_TIMEOUT 4 /* - Disable retransmit timeouts */
+#define NFS_CS_SAME_NET_OK 5 /* same net multiple xprts ok */
struct sockaddr_storage cl_addr; /* server identifier */
size_t cl_addrlen;
char * cl_hostname; /* hostname of server */
@@ -135,6 +135,7 @@ struct rpc_create_args {
#define RPC_CLNT_CREATE_INFINITE_SLOTS (1UL << 7)
#define RPC_CLNT_CREATE_NO_IDLE_TIMEOUT (1UL << 8)
#define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT (1UL << 9)
+#define RPC_CLNT_CREATE_SAME_NET_OK (1UL << 10)
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
@@ -18,6 +18,10 @@ struct rpc_xprt_switch {
struct net * xps_net;
+#define XPRT_SWITCH_SAME_NET_OK (1UL << 0)
+
+ int xps_flags;
+
const struct rpc_xprt_iter_ops *xps_iter_ops;
struct rcu_head xps_rcu;
@@ -38,7 +42,7 @@ struct rpc_xprt_iter_ops {
};
extern struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
- gfp_t gfp_flags);
+ gfp_t gfp_flags, int flags);
extern struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps);
extern void xprt_switch_put(struct rpc_xprt_switch *xps);
@@ -451,8 +451,11 @@ struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
{
struct rpc_clnt *clnt = NULL;
struct rpc_xprt_switch *xps;
+ int flags = 0;
- xps = xprt_switch_alloc(xprt, GFP_KERNEL);
+ if (args->flags & RPC_CLNT_CREATE_SAME_NET_OK)
+ flags |= XPRT_SWITCH_SAME_NET_OK;
+ xps = xprt_switch_alloc(xprt, GFP_KERNEL, flags);
if (xps == NULL)
return ERR_PTR(-ENOMEM);
@@ -683,7 +686,7 @@ int rpc_switch_client_transport(struct rpc_clnt *clnt,
return PTR_ERR(xprt);
}
- xps = xprt_switch_alloc(xprt, GFP_KERNEL);
+ xps = xprt_switch_alloc(xprt, GFP_KERNEL, 0);
if (xps == NULL) {
xprt_put(xprt);
return -ENOMEM;
@@ -16,6 +16,7 @@
#include <linux/spinlock.h>
#include <linux/sunrpc/xprt.h>
#include <linux/sunrpc/xprtmultipath.h>
+#include <linux/sunrpc/addr.h>
typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct list_head *head,
const struct rpc_xprt *cur);
@@ -37,6 +38,22 @@ static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps,
}
/**
+ * See if xprt->addr is already in switch
+ */
+static int
+rpc_xprt_switch_find_addr(struct list_head *head, struct rpc_xprt *xprt)
+{
+ struct rpc_xprt *local;
+
+ list_for_each_entry_rcu(local, head, xprt_switch) {
+ if (rpc_cmp_addr_port((struct sockaddr *)&local->addr,
+ (struct sockaddr *)&xprt->addr))
+ return 1;
+ }
+ return 0;
+}
+
+/**
* rpc_xprt_switch_add_xprt - Add a new rpc_xprt to an rpc_xprt_switch
* @xps: pointer to struct rpc_xprt_switch
* @xprt: pointer to struct rpc_xprt
@@ -49,8 +66,19 @@ void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
if (xprt == NULL)
return;
spin_lock(&xps->xps_lock);
- if (xps->xps_net != xprt->xprt_net || xps->xps_net == NULL)
+ if (xps->xps_net != xprt->xprt_net || xps->xps_net == NULL) {
+ pr_info("RPC: ADD NEW NET xprt %p servername %s\n", xprt,
+ xprt->servername);
xprt_switch_add_xprt_locked(xps, xprt);
+ }
+ if (xps->xps_flags & XPRT_SWITCH_SAME_NET_OK &&
+ xps->xps_net == xprt->xprt_net) {
+ if (!rpc_xprt_switch_find_addr(&xps->xps_xprt_list, xprt)) {
+ pr_info("RPC: ADD SAME NET xprt %p servername %s\n",
+ __func__, xprt, xprt->servername);
+ xprt_switch_add_xprt_locked(xps, xprt);
+ }
+ }
spin_unlock(&xps->xps_lock);
}
@@ -91,7 +119,7 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
* the entry xprt. Returns NULL on failure.
*/
struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
- gfp_t gfp_flags)
+ gfp_t gfp_flags, int flags)
{
struct rpc_xprt_switch *xps;
@@ -102,6 +130,7 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
xps->xps_nxprts = 0;
INIT_LIST_HEAD(&xps->xps_xprt_list);
xps->xps_iter_ops = &rpc_xprt_iter_singular;
+ xps->xps_flags = flags;
xprt_switch_add_xprt_locked(xps, xprt);
}