diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-04-24 14:28:18 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-04-24 14:28:18 -0400 |
commit | fd954ae124e8a866e9cc1bc3de9a07be5492f608 (patch) | |
tree | b45b1a58287e2e77afb1da4ed8ead0c3a8688c2d /fs | |
parent | fb8a5ba8114491467c4067ec0330e1c3dcc81d10 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 45 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 46 |
3 files changed, 39 insertions, 53 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index e1c261ddd65d..c4a69833dd0d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -47,6 +47,7 @@ enum nfs4_client_state { | |||
47 | NFS4CLNT_LAYOUTRECALL, | 47 | NFS4CLNT_LAYOUTRECALL, |
48 | NFS4CLNT_SESSION_RESET, | 48 | NFS4CLNT_SESSION_RESET, |
49 | NFS4CLNT_RECALL_SLOT, | 49 | NFS4CLNT_RECALL_SLOT, |
50 | NFS4CLNT_LEASE_CONFIRM, | ||
50 | }; | 51 | }; |
51 | 52 | ||
52 | enum nfs4_session_state { | 53 | enum nfs4_session_state { |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 628e35f75307..50c814828fcb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3754,18 +3754,17 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3754 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3754 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
3755 | if (status != -NFS4ERR_CLID_INUSE) | 3755 | if (status != -NFS4ERR_CLID_INUSE) |
3756 | break; | 3756 | break; |
3757 | if (signalled()) | 3757 | if (loop != 0) { |
3758 | ++clp->cl_id_uniquifier; | ||
3758 | break; | 3759 | break; |
3759 | if (loop++ & 1) | 3760 | } |
3760 | ssleep(clp->cl_lease_time / HZ + 1); | 3761 | ++loop; |
3761 | else | 3762 | ssleep(clp->cl_lease_time / HZ + 1); |
3762 | if (++clp->cl_id_uniquifier == 0) | ||
3763 | break; | ||
3764 | } | 3763 | } |
3765 | return status; | 3764 | return status; |
3766 | } | 3765 | } |
3767 | 3766 | ||
3768 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | 3767 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
3769 | struct nfs4_setclientid_res *arg, | 3768 | struct nfs4_setclientid_res *arg, |
3770 | struct rpc_cred *cred) | 3769 | struct rpc_cred *cred) |
3771 | { | 3770 | { |
@@ -3790,26 +3789,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
3790 | return status; | 3789 | return status; |
3791 | } | 3790 | } |
3792 | 3791 | ||
3793 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | ||
3794 | struct nfs4_setclientid_res *arg, | ||
3795 | struct rpc_cred *cred) | ||
3796 | { | ||
3797 | long timeout = 0; | ||
3798 | int err; | ||
3799 | do { | ||
3800 | err = _nfs4_proc_setclientid_confirm(clp, arg, cred); | ||
3801 | switch (err) { | ||
3802 | case 0: | ||
3803 | return err; | ||
3804 | case -NFS4ERR_RESOURCE: | ||
3805 | /* The IBM lawyers misread another document! */ | ||
3806 | case -NFS4ERR_DELAY: | ||
3807 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | ||
3808 | } | ||
3809 | } while (err == 0); | ||
3810 | return err; | ||
3811 | } | ||
3812 | |||
3813 | struct nfs4_delegreturndata { | 3792 | struct nfs4_delegreturndata { |
3814 | struct nfs4_delegreturnargs args; | 3793 | struct nfs4_delegreturnargs args; |
3815 | struct nfs4_delegreturnres res; | 3794 | struct nfs4_delegreturnres res; |
@@ -5222,20 +5201,10 @@ int nfs4_proc_create_session(struct nfs_client *clp) | |||
5222 | int status; | 5201 | int status; |
5223 | unsigned *ptr; | 5202 | unsigned *ptr; |
5224 | struct nfs4_session *session = clp->cl_session; | 5203 | struct nfs4_session *session = clp->cl_session; |
5225 | long timeout = 0; | ||
5226 | int err; | ||
5227 | 5204 | ||
5228 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | 5205 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); |
5229 | 5206 | ||
5230 | do { | 5207 | status = _nfs4_proc_create_session(clp); |
5231 | status = _nfs4_proc_create_session(clp); | ||
5232 | if (status == -NFS4ERR_DELAY) { | ||
5233 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | ||
5234 | if (err) | ||
5235 | status = err; | ||
5236 | } | ||
5237 | } while (status == -NFS4ERR_DELAY); | ||
5238 | |||
5239 | if (status) | 5208 | if (status) |
5240 | goto out; | 5209 | goto out; |
5241 | 5210 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4dfb34b43ffb..4a810c8b0753 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); | |||
64 | 64 | ||
65 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 65 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
66 | { | 66 | { |
67 | struct nfs4_setclientid_res clid; | 67 | struct nfs4_setclientid_res clid = { |
68 | .clientid = clp->cl_clientid, | ||
69 | .confirm = clp->cl_confirm, | ||
70 | }; | ||
68 | unsigned short port; | 71 | unsigned short port; |
69 | int status; | 72 | int status; |
70 | 73 | ||
74 | if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) | ||
75 | goto do_confirm; | ||
71 | port = nfs_callback_tcpport; | 76 | port = nfs_callback_tcpport; |
72 | if (clp->cl_addr.ss_family == AF_INET6) | 77 | if (clp->cl_addr.ss_family == AF_INET6) |
73 | port = nfs_callback_tcpport6; | 78 | port = nfs_callback_tcpport6; |
@@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
75 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); | 80 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); |
76 | if (status != 0) | 81 | if (status != 0) |
77 | goto out; | 82 | goto out; |
83 | clp->cl_clientid = clid.clientid; | ||
84 | clp->cl_confirm = clid.confirm; | ||
85 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
86 | do_confirm: | ||
78 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); | 87 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); |
79 | if (status != 0) | 88 | if (status != 0) |
80 | goto out; | 89 | goto out; |
81 | clp->cl_clientid = clid.clientid; | 90 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
82 | nfs4_schedule_state_renewal(clp); | 91 | nfs4_schedule_state_renewal(clp); |
83 | out: | 92 | out: |
84 | return status; | 93 | return status; |
@@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
230 | { | 239 | { |
231 | int status; | 240 | int status; |
232 | 241 | ||
242 | if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) | ||
243 | goto do_confirm; | ||
233 | nfs4_begin_drain_session(clp); | 244 | nfs4_begin_drain_session(clp); |
234 | status = nfs4_proc_exchange_id(clp, cred); | 245 | status = nfs4_proc_exchange_id(clp, cred); |
235 | if (status != 0) | 246 | if (status != 0) |
236 | goto out; | 247 | goto out; |
248 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
249 | do_confirm: | ||
237 | status = nfs4_proc_create_session(clp); | 250 | status = nfs4_proc_create_session(clp); |
238 | if (status != 0) | 251 | if (status != 0) |
239 | goto out; | 252 | goto out; |
253 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
240 | nfs41_setup_state_renewal(clp); | 254 | nfs41_setup_state_renewal(clp); |
241 | nfs_mark_client_ready(clp, NFS_CS_READY); | 255 | nfs_mark_client_ready(clp, NFS_CS_READY); |
242 | out: | 256 | out: |
@@ -1584,20 +1598,22 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } | |||
1584 | */ | 1598 | */ |
1585 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | 1599 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) |
1586 | { | 1600 | { |
1587 | if (nfs4_has_session(clp)) { | 1601 | switch (status) { |
1588 | switch (status) { | 1602 | case -NFS4ERR_CLID_INUSE: |
1589 | case -NFS4ERR_DELAY: | 1603 | case -NFS4ERR_STALE_CLIENTID: |
1590 | case -NFS4ERR_CLID_INUSE: | 1604 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
1591 | case -EAGAIN: | 1605 | break; |
1592 | break; | 1606 | case -NFS4ERR_DELAY: |
1607 | case -EAGAIN: | ||
1608 | ssleep(1); | ||
1609 | break; | ||
1593 | 1610 | ||
1594 | case -EKEYEXPIRED: | 1611 | case -EKEYEXPIRED: |
1595 | nfs4_warn_keyexpired(clp->cl_hostname); | 1612 | nfs4_warn_keyexpired(clp->cl_hostname); |
1596 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | 1613 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery |
1597 | * in nfs4_exchange_id */ | 1614 | * in nfs4_exchange_id */ |
1598 | default: | 1615 | default: |
1599 | return; | 1616 | return; |
1600 | } | ||
1601 | } | 1617 | } |
1602 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1618 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1603 | } | 1619 | } |