aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2012-09-14 17:24:21 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-10-01 18:33:33 -0400
commite984a55a7418f777407c7edbb2bdf5eb9559b5e2 (patch)
tree75374f581c61cde0910d37c089e9b871e121b4af /fs/nfs/nfs4proc.c
parent896526174ce2b6a773e187ebe5a047b68230e2c4 (diff)
NFS: Use the same nfs_client_id4 for every server
Currently, when identifying itself to NFS servers, the Linux NFS client uses a unique nfs_client_id4.id string for each server IP address it talks with. For example, when client A talks to server X, the client identifies itself using a string like "AX". The requirements for these strings are specified in detail by RFC 3530 (and bis). This form of client identification presents a problem for Transparent State Migration. When client A's state on server X is migrated to server Y, it continues to be associated with string "AX." But, according to the rules of client string construction above, client A will present string "AY" when communicating with server Y. Server Y thus has no way to know that client A should be associated with the state migrated from server X. "AX" is all but abandoned, interfering with establishing fresh state for client A on server Y. To support transparent state migration, then, NFSv4.0 clients must instead use the same nfs_client_id4.id string to identify themselves to every NFS server; something like "A". Now a client identifies itself as "A" to server X. When a file system on server X transitions to server Y, and client A identifies itself as "A" to server Y, Y will know immediately that the state associated with "A," whether it is native or migrated, is owned by the client, and can merge both into a single lease. As a pre-requisite to adding support for NFSv4 migration to the Linux NFS client, this patch changes the way Linux identifies itself to NFS servers via the SETCLIENTID (NFSv4 minor version 0) and EXCHANGE_ID (NFSv4 minor version 1) operations. In addition to removing the server's IP address from nfs_client_id4, the Linux NFS client will also no longer use its own source IP address as part of the nfs_client_id4 string. On multi-homed clients, the value of this address depends on the address family and network routing used to contact the server, thus it can be different for each server. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c51
1 files changed, 39 insertions, 12 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5b3207f557d9..461411171966 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4047,6 +4047,32 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
4047 memcpy(bootverf->data, verf, sizeof(bootverf->data)); 4047 memcpy(bootverf->data, verf, sizeof(bootverf->data));
4048} 4048}
4049 4049
4050static unsigned int
4051nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
4052 char *buf, size_t len)
4053{
4054 unsigned int result;
4055
4056 rcu_read_lock();
4057 result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
4058 clp->cl_ipaddr,
4059 rpc_peeraddr2str(clp->cl_rpcclient,
4060 RPC_DISPLAY_ADDR),
4061 rpc_peeraddr2str(clp->cl_rpcclient,
4062 RPC_DISPLAY_PROTO));
4063 rcu_read_unlock();
4064 return result;
4065}
4066
4067static unsigned int
4068nfs4_init_uniform_client_string(const struct nfs_client *clp,
4069 char *buf, size_t len)
4070{
4071 return scnprintf(buf, len, "Linux NFSv%u.%u %s",
4072 clp->rpc_ops->version, clp->cl_minorversion,
4073 clp->cl_rpcclient->cl_nodename);
4074}
4075
4050/** 4076/**
4051 * nfs4_proc_setclientid - Negotiate client ID 4077 * nfs4_proc_setclientid - Negotiate client ID
4052 * @clp: state data structure 4078 * @clp: state data structure
@@ -4077,15 +4103,18 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
4077 4103
4078 /* nfs_client_id4 */ 4104 /* nfs_client_id4 */
4079 nfs4_init_boot_verifier(clp, &sc_verifier); 4105 nfs4_init_boot_verifier(clp, &sc_verifier);
4080 rcu_read_lock(); 4106 if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
4081 setclientid.sc_name_len = scnprintf(setclientid.sc_name, 4107 setclientid.sc_name_len =
4082 sizeof(setclientid.sc_name), "%s/%s %s", 4108 nfs4_init_uniform_client_string(clp,
4083 clp->cl_ipaddr, 4109 setclientid.sc_name,
4084 rpc_peeraddr2str(clp->cl_rpcclient, 4110 sizeof(setclientid.sc_name));
4085 RPC_DISPLAY_ADDR), 4111 else
4086 rpc_peeraddr2str(clp->cl_rpcclient, 4112 setclientid.sc_name_len =
4087 RPC_DISPLAY_PROTO)); 4113 nfs4_init_nonuniform_client_string(clp,
4114 setclientid.sc_name,
4115 sizeof(setclientid.sc_name));
4088 /* cb_client4 */ 4116 /* cb_client4 */
4117 rcu_read_lock();
4089 setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, 4118 setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
4090 sizeof(setclientid.sc_netid), 4119 sizeof(setclientid.sc_netid),
4091 rpc_peeraddr2str(clp->cl_rpcclient, 4120 rpc_peeraddr2str(clp->cl_rpcclient,
@@ -5307,10 +5336,8 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
5307 }; 5336 };
5308 5337
5309 nfs4_init_boot_verifier(clp, &verifier); 5338 nfs4_init_boot_verifier(clp, &verifier);
5310 args.id_len = scnprintf(args.id, sizeof(args.id), 5339 args.id_len = nfs4_init_uniform_client_string(clp, args.id,
5311 "%s/%s", 5340 sizeof(args.id));
5312 clp->cl_ipaddr,
5313 clp->cl_rpcclient->cl_nodename);
5314 dprintk("NFS call exchange_id auth=%s, '%.*s'\n", 5341 dprintk("NFS call exchange_id auth=%s, '%.*s'\n",
5315 clp->cl_rpcclient->cl_auth->au_ops->au_name, 5342 clp->cl_rpcclient->cl_auth->au_ops->au_name,
5316 args.id_len, args.id); 5343 args.id_len, args.id);