From: Andy Adamson <andros@xxxxxxxxxx> NFSv4.1 session trunking wants to add multiple xprts to the same net. Signed-off-by: Andy Adamson <andros@xxxxxxxxxx> --- fs/nfs/client.c | 2 ++ fs/nfs/nfs4client.c | 4 +++- include/linux/nfs_fs_sb.h | 1 + include/linux/sunrpc/clnt.h | 1 + include/linux/sunrpc/xprtmultipath.h | 6 +++++- net/sunrpc/clnt.c | 7 +++++-- net/sunrpc/xprtmultipath.c | 33 +++++++++++++++++++++++++++++++-- 7 files changed, 48 insertions(+), 6 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d6d5d2a..f07d639 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -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; diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 10410e8..5f20acf 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -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); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 7fcc13c..8a63993 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -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 */ diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 9a7ddba..d8fa359 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -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, diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h index 5a9acff..05697cf 100644 --- a/include/linux/sunrpc/xprtmultipath.h +++ b/include/linux/sunrpc/xprtmultipath.h @@ -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); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index a56a44c8..38676a8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -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; diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c index 8b95ad1..7be5bd2 100644 --- a/net/sunrpc/xprtmultipath.c +++ b/net/sunrpc/xprtmultipath.c @@ -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); } -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html