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 e1c261ddd65..c4a69833dd0 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 628e35f7530..50c814828fc 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 4dfb34b43ff..4a810c8b075 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 | } |
