Commit 39b4fa56 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Handle the NFS4ERR_CLID_INUSE error in SETCLIENTID

 Encode the AUTH flavour in the clientid, since AUTH_UNIX and AUTH_GSS
 credentials will always conflict.

 Then, strategy is to first retry after sleeping for a lease period. If
 the server then still refuses our clientid, assume we have a conflicting
 client, out there, and try bumping a "uniquifier" variable.

 Give up if we're signalled, or if we've gone through the entire range
 of uniquifiers...
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent e4bcc04c
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
...@@ -2163,9 +2164,7 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ ...@@ -2163,9 +2164,7 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port) int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port)
{ {
static nfs4_verifier sc_verifier; nfs4_verifier sc_verifier;
static int initialized;
struct nfs4_setclientid setclientid = { struct nfs4_setclientid setclientid = {
.sc_verifier = &sc_verifier, .sc_verifier = &sc_verifier,
.sc_prog = program, .sc_prog = program,
...@@ -2176,27 +2175,38 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p ...@@ -2176,27 +2175,38 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p
.rpc_resp = clp, .rpc_resp = clp,
.rpc_cred = clp->cl_cred, .rpc_cred = clp->cl_cred,
}; };
if (!initialized) {
struct timespec boot_time;
u32 *p; u32 *p;
int loop = 0;
int status;
initialized = 1;
boot_time = CURRENT_TIME;
p = (u32*)sc_verifier.data; p = (u32*)sc_verifier.data;
*p++ = htonl((u32)boot_time.tv_sec); *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
*p = htonl((u32)boot_time.tv_nsec); *p = htonl((u32)clp->cl_boot_time.tv_nsec);
}
for(;;) {
setclientid.sc_name_len = scnprintf(setclientid.sc_name, setclientid.sc_name_len = scnprintf(setclientid.sc_name,
sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u", sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u",
clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr)); clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr),
clp->cl_cred->cr_ops->cr_name,
clp->cl_id_uniquifier);
setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
sizeof(setclientid.sc_netid), "tcp"); sizeof(setclientid.sc_netid), "tcp");
setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
sizeof(setclientid.sc_uaddr), "%s.%d.%d", sizeof(setclientid.sc_uaddr), "%s.%d.%d",
clp->cl_ipaddr, port >> 8, port & 255); clp->cl_ipaddr, port >> 8, port & 255);
return rpc_call_sync(clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
if (status != -NFS4ERR_CLID_INUSE)
break;
if (signalled())
break;
if (loop++ & 1)
ssleep(clp->cl_lease_time + 1);
else
if (++clp->cl_id_uniquifier == 0)
break;
}
return status;
} }
int int
......
...@@ -116,6 +116,7 @@ nfs4_alloc_client(struct in_addr *addr) ...@@ -116,6 +116,7 @@ nfs4_alloc_client(struct in_addr *addr)
INIT_LIST_HEAD(&clp->cl_superblocks); INIT_LIST_HEAD(&clp->cl_superblocks);
init_waitqueue_head(&clp->cl_waitq); init_waitqueue_head(&clp->cl_waitq);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
clp->cl_boot_time = CURRENT_TIME;
clp->cl_state = 1 << NFS4CLNT_OK; clp->cl_state = 1 << NFS4CLNT_OK;
return clp; return clp;
} }
......
...@@ -3175,7 +3175,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) ...@@ -3175,7 +3175,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
READ_BUF(4); READ_BUF(4);
READ32(len); READ32(len);
READ_BUF(len); READ_BUF(len);
return -EEXIST; return -NFSERR_CLID_INUSE;
} else } else
return -nfs_stat_to_errno(nfserr); return -nfs_stat_to_errno(nfserr);
......
...@@ -583,6 +583,9 @@ struct nfs4_client { ...@@ -583,6 +583,9 @@ struct nfs4_client {
wait_queue_head_t cl_waitq; wait_queue_head_t cl_waitq;
struct rpc_wait_queue cl_rpcwaitq; struct rpc_wait_queue cl_rpcwaitq;
/* used for the setclientid verifier */
struct timespec cl_boot_time;
/* idmapper */ /* idmapper */
struct idmap * cl_idmap; struct idmap * cl_idmap;
...@@ -590,6 +593,7 @@ struct nfs4_client { ...@@ -590,6 +593,7 @@ struct nfs4_client {
* This is used to generate the clientid, and the callback address. * This is used to generate the clientid, and the callback address.
*/ */
char cl_ipaddr[16]; char cl_ipaddr[16];
unsigned char cl_id_uniquifier;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment