NFSv4.1: Don't loop forever in nfs4_proc_create_session
If a server for some reason keeps sending NFS4ERR_DELAY errors, we can end up looping forever inside nfs4_proc_create_session, and so the usual mechanisms for detecting if the nfs_client is dead don't work. Fix this by ensuring that we loop inside the nfs4_state_manager thread instead. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
fb8a5ba811
commit
fd954ae124
|
@ -47,6 +47,7 @@ enum nfs4_client_state {
|
||||||
NFS4CLNT_LAYOUTRECALL,
|
NFS4CLNT_LAYOUTRECALL,
|
||||||
NFS4CLNT_SESSION_RESET,
|
NFS4CLNT_SESSION_RESET,
|
||||||
NFS4CLNT_RECALL_SLOT,
|
NFS4CLNT_RECALL_SLOT,
|
||||||
|
NFS4CLNT_LEASE_CONFIRM,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum nfs4_session_state {
|
enum nfs4_session_state {
|
||||||
|
|
|
@ -3754,18 +3754,17 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
|
||||||
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
|
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
|
||||||
if (status != -NFS4ERR_CLID_INUSE)
|
if (status != -NFS4ERR_CLID_INUSE)
|
||||||
break;
|
break;
|
||||||
if (signalled())
|
if (loop != 0) {
|
||||||
|
++clp->cl_id_uniquifier;
|
||||||
break;
|
break;
|
||||||
if (loop++ & 1)
|
}
|
||||||
|
++loop;
|
||||||
ssleep(clp->cl_lease_time / HZ + 1);
|
ssleep(clp->cl_lease_time / HZ + 1);
|
||||||
else
|
|
||||||
if (++clp->cl_id_uniquifier == 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
|
int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
|
||||||
struct nfs4_setclientid_res *arg,
|
struct nfs4_setclientid_res *arg,
|
||||||
struct rpc_cred *cred)
|
struct rpc_cred *cred)
|
||||||
{
|
{
|
||||||
|
@ -3790,26 +3789,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
|
|
||||||
struct nfs4_setclientid_res *arg,
|
|
||||||
struct rpc_cred *cred)
|
|
||||||
{
|
|
||||||
long timeout = 0;
|
|
||||||
int err;
|
|
||||||
do {
|
|
||||||
err = _nfs4_proc_setclientid_confirm(clp, arg, cred);
|
|
||||||
switch (err) {
|
|
||||||
case 0:
|
|
||||||
return err;
|
|
||||||
case -NFS4ERR_RESOURCE:
|
|
||||||
/* The IBM lawyers misread another document! */
|
|
||||||
case -NFS4ERR_DELAY:
|
|
||||||
err = nfs4_delay(clp->cl_rpcclient, &timeout);
|
|
||||||
}
|
|
||||||
} while (err == 0);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct nfs4_delegreturndata {
|
struct nfs4_delegreturndata {
|
||||||
struct nfs4_delegreturnargs args;
|
struct nfs4_delegreturnargs args;
|
||||||
struct nfs4_delegreturnres res;
|
struct nfs4_delegreturnres res;
|
||||||
|
@ -5222,20 +5201,10 @@ int nfs4_proc_create_session(struct nfs_client *clp)
|
||||||
int status;
|
int status;
|
||||||
unsigned *ptr;
|
unsigned *ptr;
|
||||||
struct nfs4_session *session = clp->cl_session;
|
struct nfs4_session *session = clp->cl_session;
|
||||||
long timeout = 0;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
|
dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
|
||||||
|
|
||||||
do {
|
|
||||||
status = _nfs4_proc_create_session(clp);
|
status = _nfs4_proc_create_session(clp);
|
||||||
if (status == -NFS4ERR_DELAY) {
|
|
||||||
err = nfs4_delay(clp->cl_rpcclient, &timeout);
|
|
||||||
if (err)
|
|
||||||
status = err;
|
|
||||||
}
|
|
||||||
} while (status == -NFS4ERR_DELAY);
|
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list);
|
||||||
|
|
||||||
int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
|
int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
|
||||||
{
|
{
|
||||||
struct nfs4_setclientid_res clid;
|
struct nfs4_setclientid_res clid = {
|
||||||
|
.clientid = clp->cl_clientid,
|
||||||
|
.confirm = clp->cl_confirm,
|
||||||
|
};
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
|
||||||
|
goto do_confirm;
|
||||||
port = nfs_callback_tcpport;
|
port = nfs_callback_tcpport;
|
||||||
if (clp->cl_addr.ss_family == AF_INET6)
|
if (clp->cl_addr.ss_family == AF_INET6)
|
||||||
port = nfs_callback_tcpport6;
|
port = nfs_callback_tcpport6;
|
||||||
|
@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
|
||||||
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
|
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
clp->cl_clientid = clid.clientid;
|
||||||
|
clp->cl_confirm = clid.confirm;
|
||||||
|
set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||||
|
do_confirm:
|
||||||
status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
|
status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
clp->cl_clientid = clid.clientid;
|
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||||
nfs4_schedule_state_renewal(clp);
|
nfs4_schedule_state_renewal(clp);
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
|
@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
|
||||||
|
goto do_confirm;
|
||||||
nfs4_begin_drain_session(clp);
|
nfs4_begin_drain_session(clp);
|
||||||
status = nfs4_proc_exchange_id(clp, cred);
|
status = nfs4_proc_exchange_id(clp, cred);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||||
|
do_confirm:
|
||||||
status = nfs4_proc_create_session(clp);
|
status = nfs4_proc_create_session(clp);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||||
nfs41_setup_state_renewal(clp);
|
nfs41_setup_state_renewal(clp);
|
||||||
nfs_mark_client_ready(clp, NFS_CS_READY);
|
nfs_mark_client_ready(clp, NFS_CS_READY);
|
||||||
out:
|
out:
|
||||||
|
@ -1584,11 +1598,14 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
|
||||||
*/
|
*/
|
||||||
static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
|
static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
|
||||||
{
|
{
|
||||||
if (nfs4_has_session(clp)) {
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case -NFS4ERR_DELAY:
|
|
||||||
case -NFS4ERR_CLID_INUSE:
|
case -NFS4ERR_CLID_INUSE:
|
||||||
|
case -NFS4ERR_STALE_CLIENTID:
|
||||||
|
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
|
||||||
|
break;
|
||||||
|
case -NFS4ERR_DELAY:
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
|
ssleep(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -EKEYEXPIRED:
|
case -EKEYEXPIRED:
|
||||||
|
@ -1598,7 +1615,6 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
|
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ struct nfs_client {
|
||||||
|
|
||||||
#ifdef CONFIG_NFS_V4
|
#ifdef CONFIG_NFS_V4
|
||||||
u64 cl_clientid; /* constant */
|
u64 cl_clientid; /* constant */
|
||||||
|
nfs4_verifier cl_confirm; /* Clientid verifier */
|
||||||
unsigned long cl_state;
|
unsigned long cl_state;
|
||||||
|
|
||||||
spinlock_t cl_lock;
|
spinlock_t cl_lock;
|
||||||
|
|
Loading…
Reference in New Issue