2016-04-27 15:36:39

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 0/9] NFSV4.1,2 session trunking

From: Andy Adamson <[email protected]>

RFC patchset.

Please review the code.

Main question: Do we want to use multiple hostnames on the mount command to
communicate the NFSv4.1 session trunking addresses, or only use (yet
to be coded) fs_locations_info?

This patch set uses multiple hostnames on the mount commnad and so requires
nfs-utils changes to mount.nfs from the Version 3 "Add multihostname support
for NFSv4.1,2" nfs-utils patchset.

Notes:

I did not call EXCHANGE_ID on the mulihostnames in the state
manager, as they are synchronous RPC calls that occur directly after
the nfs_client->cl_rpcclient has been established. I can change this
if needed.

I do not have code to call BIND_CONN_TO_SESSION if sp4_how is not SP4_NONE.

I added a "multiaddr=" option to the mtab for each multiaddr successfully
added to the xprt_switch.

If we want to keep the multiple hostnames on the mount command method of
expressing NFSv4.1 session trunking addresses, we should fix this:
- v3 mounts with multiple hostnames succeeds but adds an mtab dev entry that
omits the ":/<exported dir> and so prints a warning at umount.

Please review. I will start the fs_locations_info method of expressing the
session trunking addresses.

Thanks

--> Andy


NFS parse multiple hostnames
NFS default callback ops
NFS refactor nfs4_match_clientids
NFS refactor nfs4_check_serverowner_major_id
NFS detect session trunking
NFS refactor _nfs4_proc_exchange_id for session trunking
SUNRPC add flag to rpc_task_release_client
NFS test and add multi-addrs for session trunking
NFS add multiaddr to nfs_show_nfsv4_options

fs/nfs/internal.h | 19 ++++++
fs/nfs/nfs4_fs.h | 9 +++
fs/nfs/nfs4client.c | 141 ++++++++++++++++++++++++++++++++++++++++----
fs/nfs/nfs4proc.c | 79 +++++++++++++++++++++----
fs/nfs/super.c | 64 ++++++++++++++++++++
include/linux/sunrpc/clnt.h | 2 +-
net/sunrpc/clnt.c | 6 +-
net/sunrpc/sched.c | 2 +-
net/sunrpc/xprtmultipath.c | 4 ++
9 files changed, 300 insertions(+), 26 deletions(-)

--
1.8.3.1



2016-04-27 15:36:46

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 9/9] NFS add multiaddr to nfs_show_nfsv4_options

From: Andy Adamson <[email protected]>

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/super.c | 24 ++++++++++++++++++++++++
net/sunrpc/xprtmultipath.c | 1 +
2 files changed, 25 insertions(+)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 70a4fda..1dc1e18 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -605,8 +605,32 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
int showdefaults)
{
struct nfs_client *clp = nfss->nfs_client;
+ struct rpc_clnt *clnt = clp->cl_rpcclient;
+ struct rpc_xprt_switch *xps;
+ struct rpc_xprt *pos;
+ unsigned int nxprts;

seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+ rcu_read_lock();
+ xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
+ pos = xprt_iter_xprt(&clnt->cl_xpi);
+ if (xps == NULL || pos == NULL)
+ return;
+ nxprts = xps->xps_nxprts;
+ list_for_each_entry_rcu(pos, &xps->xps_xprt_list, xprt_switch) {
+ if (nxprts == 0)
+ break;
+ if (pos->address_strings[RPC_DISPLAY_ADDR] == NULL)
+ break;
+ /* Do not display mount xprt as a multiaddr */
+ if (pos == rcu_access_pointer(clp->cl_rpcclient->cl_xprt))
+ continue;
+ seq_printf(m, ",multiaddr=%s",
+ pos->address_strings[RPC_DISPLAY_ADDR]);
+ nxprts--;
+ }
+ rcu_read_unlock();
+ xprt_switch_put(xps);
}
#else
static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index 360f64c..708c22a 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -403,6 +403,7 @@ struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
WARN_ON_ONCE(!rcu_read_lock_held());
return xprt_iter_ops(xpi)->xpi_xprt(xpi);
}
+EXPORT_SYMBOL_GPL(xprt_iter_xprt);

static
struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
--
1.8.3.1


2016-04-27 15:36:47

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 3/9] NFS refactor nfs4_match_clientids

From: Andy Adamson <[email protected]>

For session trunking, to compare nfs41_exchange_id_res with
exiting nfs_client.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/nfs4client.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 10410e8..c9177a4 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -562,15 +562,15 @@ out:
/*
* Returns true if the client IDs match
*/
-static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
+static bool nfs4_match_clientids(u64 a, u64 b)
{
- if (a->cl_clientid != b->cl_clientid) {
+ if (a != b) {
dprintk("NFS: --> %s client ID %llx does not match %llx\n",
- __func__, a->cl_clientid, b->cl_clientid);
+ __func__, a, b);
return false;
}
dprintk("NFS: --> %s client ID %llx matches %llx\n",
- __func__, a->cl_clientid, b->cl_clientid);
+ __func__, a, b);
return true;
}

@@ -650,7 +650,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
if (pos->cl_cons_state != NFS_CS_READY)
continue;

- if (!nfs4_match_clientids(pos, new))
+ if (!nfs4_match_clientids(pos->cl_clientid, new->cl_clientid))
continue;

/*
--
1.8.3.1


2016-04-27 15:36:48

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 6/9] NFS refactor _nfs4_proc_exchange_id for session trunking

From: Andy Adamson <[email protected]>

Add an rpc_xprt parameter to test it's connection for session trunking

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/nfs4proc.c | 34 ++++++++++++++++++++++++++++------
1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index da2aa2e..70537f0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7024,7 +7024,7 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
* Wrapper for EXCHANGE_ID operation.
*/
static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
- u32 sp4_how)
+ u32 sp4_how, struct rpc_xprt *xprt)
{
nfs4_verifier verifier;
struct nfs41_exchange_id_args args = {
@@ -7049,6 +7049,18 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
.rpc_resp = &res,
.rpc_cred = cred,
};
+ struct rpc_task_setup task_setup_data = {
+ .rpc_client = clp->cl_rpcclient,
+ .rpc_xprt = xprt,
+ .callback_ops = &nfs4_proc_default_ops,
+ .rpc_message = &msg,
+ .flags = RPC_TASK_TIMEOUT,
+ };
+ struct rpc_task *task;
+
+ /* Do not run exchange_id against the established mount connection */
+ if (xprt && xprt == rcu_access_pointer(clp->cl_rpcclient->cl_xprt))
+ return 1;

nfs4_init_boot_verifier(clp, &verifier);

@@ -7096,11 +7108,17 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
goto out_impl_id;
}

- status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+ 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_exchange_id(clp, status);
if (status == 0)
status = nfs4_check_cl_exchange_flags(res.flags);
-
+ if (xprt)
+ goto session_trunk;
if (status == 0)
status = nfs4_sp4_select_mode(clp, &res.state_protect);

@@ -7138,7 +7156,6 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
res.server_scope = NULL;
}
}
-
out_impl_id:
kfree(res.impl_id);
out_server_scope:
@@ -7154,6 +7171,11 @@ out:
clp->cl_implid->date.nseconds);
dprintk("NFS reply exchange_id: %d\n", status);
return status;
+
+session_trunk:
+ if (status == 0)
+ status = nfs4_detect_session_trunking(clp, &res);
+ goto out_impl_id;
}

/*
@@ -7176,13 +7198,13 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
/* try SP4_MACH_CRED if krb5i/p */
if (authflavor == RPC_AUTH_GSS_KRB5I ||
authflavor == RPC_AUTH_GSS_KRB5P) {
- status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
+ status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED, NULL);
if (!status)
return 0;
}

/* try SP4_NONE */
- return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
+ return _nfs4_proc_exchange_id(clp, cred, SP4_NONE, NULL);
}

static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
--
1.8.3.1


2016-04-27 15:36:40

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 4/9] NFS refactor nfs4_check_serverowner_major_id

From: Andy Adamson <[email protected]>

For session trunking, to compare nfs41_exchange_id_res with
existing nfs_client

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/nfs4client.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index c9177a4..5a14fda 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -578,11 +578,9 @@ static bool nfs4_match_clientids(u64 a, u64 b)
* Returns true if the server major ids match
*/
static bool
-nfs4_check_clientid_trunking(struct nfs_client *a, struct nfs_client *b)
+nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
+ struct nfs41_server_owner *o2)
{
- struct nfs41_server_owner *o1 = a->cl_serverowner;
- struct nfs41_server_owner *o2 = b->cl_serverowner;
-
if (o1->major_id_sz != o2->major_id_sz)
goto out_major_mismatch;
if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
@@ -658,7 +656,8 @@ int nfs41_walk_client_list(struct nfs_client *new,
* client id trunking. In either case, we want to fall back
* to using the existing nfs_client.
*/
- if (!nfs4_check_clientid_trunking(pos, new))
+ if (!nfs4_check_serverowner_major_id(pos->cl_serverowner,
+ new->cl_serverowner))
continue;

/* Unlike NFSv4.0, we know that NFSv4.1 always uses the
--
1.8.3.1


2016-04-27 15:36:40

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 7/9] SUNRPC add flag to rpc_task_release_client

From: Andy Adamson <[email protected]>

Want to specify which rpc_xprt to use in rpc_run_task.

Don't pass in an rpc_xprt in rpc_init_task just to have it not used as it
is removed in rpc_task_release_client.

Signed-off-by: Andy Adamson <[email protected]>
---
include/linux/sunrpc/clnt.h | 2 +-
net/sunrpc/clnt.c | 6 +++---
net/sunrpc/sched.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 9a7ddba..b2c5b75 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -150,7 +150,7 @@ int rpc_switch_client_transport(struct rpc_clnt *,

void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
-void rpc_task_release_client(struct rpc_task *);
+void rpc_task_release_client(struct rpc_task *, int);

int rpcb_create_local(struct net *);
void rpcb_put_local(struct net *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 7e0c9bf..e157d09 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -942,7 +942,7 @@ out:
}
EXPORT_SYMBOL_GPL(rpc_bind_new_program);

-void rpc_task_release_client(struct rpc_task *task)
+void rpc_task_release_client(struct rpc_task *task, int rm_xprt)
{
struct rpc_clnt *clnt = task->tk_client;
struct rpc_xprt *xprt = task->tk_xprt;
@@ -957,7 +957,7 @@ void rpc_task_release_client(struct rpc_task *task)
rpc_release_client(clnt);
}

- if (xprt != NULL) {
+ if (rm_xprt && xprt) {
task->tk_xprt = NULL;

xprt_put(xprt);
@@ -969,7 +969,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
{

if (clnt != NULL) {
- rpc_task_release_client(task);
+ rpc_task_release_client(task, 0);
if (task->tk_xprt == NULL)
task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi);
task->tk_client = clnt;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index fcfd48d..0dacd9c 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -993,7 +993,7 @@ static void rpc_release_resources_task(struct rpc_task *task)
put_rpccred(task->tk_msg.rpc_cred);
task->tk_msg.rpc_cred = NULL;
}
- rpc_task_release_client(task);
+ rpc_task_release_client(task, 1);
}

static void rpc_final_put_task(struct rpc_task *task,
--
1.8.3.1


2016-04-27 15:36:40

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 5/9] NFS detect session trunking

From: Andy Adamson <[email protected]>

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/internal.h | 2 ++
fs/nfs/nfs4client.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 606b153..14d957c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -545,6 +545,8 @@ extern int nfs40_walk_client_list(struct nfs_client *clp,
extern int nfs41_walk_client_list(struct nfs_client *clp,
struct nfs_client **result,
struct rpc_cred *cred);
+extern int nfs4_detect_session_trunking(struct nfs_client *clp,
+ struct nfs41_exchange_id_res *res);

static inline struct inode *nfs_igrab_and_active(struct inode *inode)
{
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 5a14fda..2121c1f 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -586,7 +586,7 @@ nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
goto out_major_mismatch;

- dprintk("NFS: --> %s server owners match\n", __func__);
+ dprintk("NFS: --> %s server owner major IDs match\n", __func__);
return true;

out_major_mismatch:
@@ -595,6 +595,87 @@ out_major_mismatch:
return false;
}

+/*
+ * Returns true if server minor ids match
+ */
+static bool
+nfs4_check_serverowner_minor_id(struct nfs41_server_owner *o1,
+ struct nfs41_server_owner *o2)
+{
+ /* Check eir_server_owner so_minor_id */
+ if (o1->minor_id != o2->minor_id)
+ goto out_minor_mismatch;
+
+ dprintk("NFS: --> %s server owner minor IDs s match\n", __func__);
+ return true;
+
+out_minor_mismatch:
+ dprintk("NFS: --> %s server owner minor IDs do not match\n", __func__);
+ return false;
+}
+
+/*
+ * Returns true if the server scopes match
+ */
+static bool
+nfs4_check_server_scope(struct nfs41_server_scope *s1,
+ struct nfs41_server_scope *s2)
+{
+ if (s1->server_scope_sz != s2->server_scope_sz)
+ goto out_scope_mismatch;
+ if (memcmp(s1->server_scope, s2->server_scope,
+ s1->server_scope_sz) != 0)
+ goto out_scope_mismatch;
+
+ dprintk("NFS: --> %s server scopes match\n", __func__);
+ return true;
+
+out_scope_mismatch:
+ dprintk("NFS: --> %s server scopes do not match\n",
+ __func__);
+ return false;
+}
+
+/**
+ * nfs4_detect_session_trunking - Checks for ssession trunking called
+ * after a successuful EXCHANGE_ID testing a multi-addr connection to be
+ * potentially added as a session trunk
+ *
+ * @clp: original mount nfs_client
+ * @res: result structure from an exchange_id using the original mount
+ * nfs_client with a new multi_addr transport
+ *
+ * Returns zero on success, otherwise -EINVAL
+ *
+ * Note: since the exchange_id for the new multi_addr transport uses the
+ * same nfs_client from the original mount, the cl_owner_id is reused,
+ * so eir_clientowner is the same.
+ */
+int nfs4_detect_session_trunking(struct nfs_client *clp,
+ struct nfs41_exchange_id_res *res)
+{
+
+ /* Check eir_clientid */
+ if (!nfs4_match_clientids(clp->cl_clientid, res->clientid))
+ return -EINVAL;
+
+ /* Check eir_server_owner so_major_id */
+ if (!nfs4_check_serverowner_major_id(clp->cl_serverowner,
+ res->server_owner))
+ return -EINVAL;
+
+ /* Check eir_server_owner so_minor_id */
+ if (!nfs4_check_serverowner_minor_id(clp->cl_serverowner,
+ res->server_owner))
+ return -EINVAL;
+
+ /* Check eir_server_scope */
+ if (!nfs4_check_server_scope(clp->cl_serverscope, res->server_scope))
+ return -EINVAL;
+
+ return 0;
+}
+
/**
* nfs41_walk_client_list - Find nfs_client that matches a client/server owner
*
--
1.8.3.1


2016-04-27 15:36:36

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 1/9] NFS parse multiple hostnames

From: Andy Adamson <[email protected]>

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/internal.h | 17 +++++++++++++++++
fs/nfs/nfs4_fs.h | 4 ++++
fs/nfs/super.c | 40 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 61 insertions(+)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index f1d1d2c..606b153 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -75,6 +75,20 @@ struct nfs_client_initdata {
struct net *net;
};

+/**
+ * NFS_MAXHOSTNAME of 255 limits the number of multiple hostnames on the
+ * mount stanza. 16 is a reasonable maximum number
+ */
+#define NFS_MAX_MULTIADDR 16
+
+
+/* hold multiple hostname info */
+struct multi_addr {
+ struct sockaddr_storage addr;
+ size_t addrlen;
+ char *hostname;
+};
+
/*
* In-kernel mount arguments
*/
@@ -113,6 +127,9 @@ struct nfs_parsed_mount_data {
unsigned short protocol;
} nfs_server;

+ unsigned int num_multi;
+ struct multi_addr *multiaddrs;
+
struct security_mnt_opts lsm_opts;
struct net *net;
};
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 4afdee4..4c21022 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -214,6 +214,10 @@ struct nfs4_mig_recovery_ops {
int (*fsid_present)(struct inode *, struct rpc_cred *);
};

+struct nfs4_add_xprt_data {
+ struct nfs_client *clp;
+ struct rpc_cred *cred;
+};
extern const struct dentry_operations nfs4_dentry_operations;

/* dir.c */
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f126828..70a4fda 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -107,6 +107,7 @@ enum {
Opt_nfsvers,
Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
Opt_addr, Opt_mountaddr, Opt_clientaddr,
+ Opt_multiaddr,
Opt_lookupcache,
Opt_fscache_uniq,
Opt_local_lock,
@@ -178,6 +179,7 @@ static const match_table_t nfs_mount_option_tokens = {
{ Opt_clientaddr, "clientaddr=%s" },
{ Opt_mounthost, "mounthost=%s" },
{ Opt_mountaddr, "mountaddr=%s" },
+ { Opt_multiaddr, "multiaddr=%s" },

{ Opt_lookupcache, "lookupcache=%s" },
{ Opt_fscache_uniq, "fsc=%s" },
@@ -921,6 +923,12 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)

data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data) {
+ data->multiaddrs = kzalloc(sizeof(*data->multiaddrs) *
+ NFS_MAX_MULTIADDR, GFP_KERNEL);
+ if (!data->multiaddrs) {
+ kfree(data);
+ return NULL;
+ }
data->acregmin = NFS_DEF_ACREGMIN;
data->acregmax = NFS_DEF_ACREGMAX;
data->acdirmin = NFS_DEF_ACDIRMIN;
@@ -939,12 +947,20 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)

static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
{
+ struct multi_addr *multip = data->multiaddrs;
+ int i;
+
if (data) {
kfree(data->client_address);
kfree(data->mount_server.hostname);
kfree(data->nfs_server.export_path);
kfree(data->nfs_server.hostname);
kfree(data->fscache_uniq);
+ for (i = 0; i < data->num_multi; i++) {
+ kfree(multip->hostname);
+ multip++;
+ }
+ kfree(data->multiaddrs);
security_free_mnt_opts(&data->lsm_opts);
kfree(data);
}
@@ -1200,6 +1216,7 @@ static int nfs_parse_mount_options(char *raw,
int rc, sloppy = 0, invalid_option = 0;
unsigned short protofamily = AF_UNSPEC;
unsigned short mountfamily = AF_UNSPEC;
+ struct multi_addr *multip = mnt->multiaddrs;

if (!raw) {
dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@@ -1589,6 +1606,25 @@ static int nfs_parse_mount_options(char *raw,
return 0;
};
break;
+ case Opt_multiaddr:
+ if (mnt->num_multi == NFS_MAX_MULTIADDR)
+ goto out_too_many_multiaddrs;
+
+ if (nfs_get_option_str(args, &multip->hostname))
+ goto out_nomem;
+
+ multip->addrlen = rpc_pton(mnt->net, multip->hostname,
+ strlen(multip->hostname),
+ (struct sockaddr *)
+ &multip->addr,
+ sizeof(multip->addr));
+
+ dfprintk(MOUNT, "NFS: Added multiaddr %s\n",
+ multip->hostname);
+ mnt->num_multi++;
+ multip++;
+
+ break;

/*
* Special options
@@ -1640,6 +1676,10 @@ static int nfs_parse_mount_options(char *raw,

return 1;

+out_too_many_multiaddrs:
+ printk(KERN_INFO "NFS: %d is too many multiple hostnames.\n",
+ mnt->num_multi);
+ return 0;
out_mountproto_mismatch:
printk(KERN_INFO "NFS: mount server address does not match mountproto= "
"option\n");
--
1.8.3.1


2016-04-27 15:36:37

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 2/9] NFS default callback ops

From: Andy Adamson <[email protected]>

Also use with refactored exchange_id for session trunking

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/nfs4proc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 327b8c3..da2aa2e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6784,12 +6784,12 @@ nfs41_same_server_scope(struct nfs41_server_scope *a,
}

static void
-nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
+nfs4_proc_default_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,
+static const struct rpc_call_ops nfs4_proc_default_ops = {
+ .rpc_call_done = &nfs4_proc_default_done,
};

/*
@@ -6820,7 +6820,7 @@ int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
struct rpc_task_setup task_setup_data = {
.rpc_client = clnt,
.rpc_xprt = xprt,
- .callback_ops = &nfs4_bind_one_conn_to_session_ops,
+ .callback_ops = &nfs4_proc_default_ops,
.rpc_message = &msg,
.flags = RPC_TASK_TIMEOUT,
};
--
1.8.3.1


2016-04-27 15:46:16

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version 3 8/9] NFS test and add multi-addrs for session trunking

From: Andy Adamson <[email protected]>

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/nfs4_fs.h | 5 +++++
fs/nfs/nfs4client.c | 39 +++++++++++++++++++++++++++++++++++++++
fs/nfs/nfs4proc.c | 37 +++++++++++++++++++++++++++++++++++++
net/sunrpc/xprtmultipath.c | 3 +++
4 files changed, 84 insertions(+)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 4c21022..f496526 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -218,6 +218,11 @@ struct nfs4_add_xprt_data {
struct nfs_client *clp;
struct rpc_cred *cred;
};
+extern int nfs4_test_session_trunk_and_add_xprt(struct rpc_clnt *clnt,
+ struct rpc_xprt_switch *xps,
+ struct rpc_xprt *xprt,
+ void *data);
+
extern const struct dentry_operations nfs4_dentry_operations;

/* dir.c */
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 2121c1f..c5cbf89 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1041,6 +1041,43 @@ out:
return error;
}

+/**
+ * Add rpc_xprts to an existing RPC client
+ */
+void nfs4_try_multiaddr(struct nfs_parsed_mount_data *mnt,
+ struct nfs_client *clp)
+{
+ struct multi_addr *multip = mnt->multiaddrs;
+ struct nfs4_add_xprt_data xprtdata = {
+ .clp = clp,
+ };
+ int i;
+
+ dprintk("NFS: Try adding %u multi addrs\n", mnt->num_multi);
+
+ if (mnt->num_multi == 0)
+ return;
+
+ xprtdata.cred = nfs4_get_clid_cred(clp);
+
+ for (i = 0; i < mnt->num_multi; i++) {
+ struct xprt_create xprt_args = {
+ .ident = XPRT_TRANSPORT_TCP,
+ .net = mnt->net,
+ .dstaddr = (struct sockaddr *)&multip->addr,
+ .addrlen = multip->addrlen,
+ .servername = multip->hostname,
+ };
+ /* Add this address as an alias */
+ rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
+ nfs4_test_session_trunk_and_add_xprt,
+ &xprtdata);
+ multip++;
+ }
+ if (xprtdata.cred)
+ put_rpccred(xprtdata.cred);
+}
+
/*
* Create a version 4 volume record
*/
@@ -1097,6 +1134,8 @@ static int nfs4_init_server(struct nfs_server *server,
error = nfs_init_server_rpcclient(server, &timeparms,
data->selected_flavor);

+ if (!error)
+ nfs4_try_multiaddr(data, server->nfs_client);
error:
/* Done */
dprintk("<-- nfs4_init_server() = %d\n", error);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 70537f0..934c668 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7207,6 +7207,43 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
return _nfs4_proc_exchange_id(clp, cred, SP4_NONE, NULL);
}

+/**
+ * nfs4_test_session_trunk_and_add_xprt - Test for session trunking with a
+ * synchronous exchange_id call, and add a new transport to the rpc_clnt
+ *
+ * @clnt: struct rpc_clnt to get new transport
+ * @xps: the rpc_xprt_switch to hold the new transport
+ * @xprt: the rpc_xprt to test
+ * @data: call data for _nfs4_proc_exchange_id.
+ *
+ */
+int nfs4_test_session_trunk_and_add_xprt(struct rpc_clnt *clnt,
+ struct rpc_xprt_switch *xps,
+ struct rpc_xprt *xprt,
+ void *data)
+{
+ struct nfs4_add_xprt_data *xdata = (struct nfs4_add_xprt_data *)data;
+ u32 sp4_how;
+ int status;
+
+ sp4_how = (xdata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
+
+ /* Ensure these stick around for the rpc call */
+ xps = xprt_switch_get(xps);
+ xprt = xprt_get(xprt);
+
+ /* Sync call */
+ status = _nfs4_proc_exchange_id(xdata->clp, xdata->cred, sp4_how, xprt);
+
+ xprt_put(xprt);
+ xprt_switch_put(xps);
+
+ if (status)
+ pr_info("NFS: mulitaddr %s establishment failed. status %d\n",
+ xprt->address_strings[RPC_DISPLAY_ADDR], status);
+ return status;
+}
+
static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
struct rpc_cred *cred)
{
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index e7fd769..360f64c 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -53,6 +53,7 @@ void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
xprt_switch_add_xprt_locked(xps, xprt);
spin_unlock(&xps->xps_lock);
}
+EXPORT_SYMBOL_GPL(rpc_xprt_switch_add_xprt);

static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
struct rpc_xprt *xprt)
@@ -145,6 +146,7 @@ struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps)
return xps;
return NULL;
}
+EXPORT_SYMBOL_GPL(xprt_switch_get);

/**
* xprt_switch_put - Release a reference to a rpc_xprt_switch
@@ -157,6 +159,7 @@ void xprt_switch_put(struct rpc_xprt_switch *xps)
if (xps != NULL)
kref_put(&xps->xps_kref, xprt_switch_free);
}
+EXPORT_SYMBOL_GPL(xprt_switch_put);

/**
* rpc_xprt_switch_set_roundrobin - Set a round-robin policy on rpc_xprt_switch
--
1.8.3.1


2016-04-27 18:05:39

by Weston Andros Adamson

[permalink] [raw]
Subject: Re: [PATCH Version 3 9/9] NFS add multiaddr to nfs_show_nfsv4_options


> On Apr 27, 2016, at 11:36 AM, [email protected] wrote:
>
> From: Andy Adamson <[email protected]>
>
> Signed-off-by: Andy Adamson <[email protected]>
> ---
> fs/nfs/super.c | 24 ++++++++++++++++++++++++
> net/sunrpc/xprtmultipath.c | 1 +
> 2 files changed, 25 insertions(+)
>
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 70a4fda..1dc1e18 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -605,8 +605,32 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
> int showdefaults)
> {
> struct nfs_client *clp = nfss->nfs_client;
> + struct rpc_clnt *clnt = clp->cl_rpcclient;
> + struct rpc_xprt_switch *xps;
> + struct rpc_xprt *pos;
> + unsigned int nxprts;
>
> seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
> + rcu_read_lock();
> + xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
> + pos = xprt_iter_xprt(&clnt->cl_xpi);
> + if (xps == NULL || pos == NULL)
> + return;

^^ you need an rcu_read_unlock() before the return.

-dros

> + nxprts = xps->xps_nxprts;
> + list_for_each_entry_rcu(pos, &xps->xps_xprt_list, xprt_switch) {
> + if (nxprts == 0)
> + break;
> + if (pos->address_strings[RPC_DISPLAY_ADDR] == NULL)
> + break;
> + /* Do not display mount xprt as a multiaddr */
> + if (pos == rcu_access_pointer(clp->cl_rpcclient->cl_xprt))
> + continue;
> + seq_printf(m, ",multiaddr=%s",
> + pos->address_strings[RPC_DISPLAY_ADDR]);
> + nxprts--;
> + }
> + rcu_read_unlock();
> + xprt_switch_put(xps);
> }
> #else
> static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
> index 360f64c..708c22a 100644
> --- a/net/sunrpc/xprtmultipath.c
> +++ b/net/sunrpc/xprtmultipath.c
> @@ -403,6 +403,7 @@ struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
> WARN_ON_ONCE(!rcu_read_lock_held());
> return xprt_iter_ops(xpi)->xpi_xprt(xpi);
> }
> +EXPORT_SYMBOL_GPL(xprt_iter_xprt);
>
> static
> struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
> --
> 1.8.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


2016-04-27 18:32:07

by Adamson, Andy

[permalink] [raw]
Subject: Re: [PATCH Version 3 9/9] NFS add multiaddr to nfs_show_nfsv4_options

Thanks for catching that Dros

-->Andy
________________________________________
From: Weston Andros Adamson <[email protected]> on behalf of Weston Andros Adamson <[email protected]>
Sent: Wednesday, April 27, 2016 2:05 PM
To: Adamson, Andy
Cc: Trond Myklebust; Steve Dickson; linux-nfs list
Subject: Re: [PATCH Version 3 9/9] NFS add multiaddr to nfs_show_nfsv4_options

> On Apr 27, 2016, at 11:36 AM, [email protected] wrote:
>
> From: Andy Adamson <[email protected]>
>
> Signed-off-by: Andy Adamson <[email protected]>
> ---
> fs/nfs/super.c | 24 ++++++++++++++++++++++++
> net/sunrpc/xprtmultipath.c | 1 +
> 2 files changed, 25 insertions(+)
>
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 70a4fda..1dc1e18 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -605,8 +605,32 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
> int showdefaults)
> {
> struct nfs_client *clp = nfss->nfs_client;
> + struct rpc_clnt *clnt = clp->cl_rpcclient;
> + struct rpc_xprt_switch *xps;
> + struct rpc_xprt *pos;
> + unsigned int nxprts;
>
> seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
> + rcu_read_lock();
> + xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
> + pos = xprt_iter_xprt(&clnt->cl_xpi);
> + if (xps == NULL || pos == NULL)
> + return;

^^ you need an rcu_read_unlock() before the return.

-dros

> + nxprts = xps->xps_nxprts;
> + list_for_each_entry_rcu(pos, &xps->xps_xprt_list, xprt_switch) {
> + if (nxprts == 0)
> + break;
> + if (pos->address_strings[RPC_DISPLAY_ADDR] == NULL)
> + break;
> + /* Do not display mount xprt as a multiaddr */
> + if (pos == rcu_access_pointer(clp->cl_rpcclient->cl_xprt))
> + continue;
> + seq_printf(m, ",multiaddr=%s",
> + pos->address_strings[RPC_DISPLAY_ADDR]);
> + nxprts--;
> + }
> + rcu_read_unlock();
> + xprt_switch_put(xps);
> }
> #else
> static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
> index 360f64c..708c22a 100644
> --- a/net/sunrpc/xprtmultipath.c
> +++ b/net/sunrpc/xprtmultipath.c
> @@ -403,6 +403,7 @@ struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi)
> WARN_ON_ONCE(!rcu_read_lock_held());
> return xprt_iter_ops(xpi)->xpi_xprt(xpi);
> }
> +EXPORT_SYMBOL_GPL(xprt_iter_xprt);
>
> static
> struct rpc_xprt *xprt_iter_get_helper(struct rpc_xprt_iter *xpi,
> --
> 1.8.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html