Message ID | 1303343405-5021-1-git-send-email-Trond.Myklebust@netapp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi- This will require some significant human intervention to merge with my code that caches the long-form client ID. On Apr 20, 2011, at 7:50 PM, Trond Myklebust wrote: > 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> > --- > fs/nfs/nfs4_fs.h | 1 + > fs/nfs/nfs4proc.c | 84 ++++++++++++--------------------------------- > fs/nfs/nfs4state.c | 47 +++++++++++++++++-------- > include/linux/nfs_fs_sb.h | 1 + > 4 files changed, 56 insertions(+), 77 deletions(-) > > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h > index e1c261d..c4a6983 100644 > --- a/fs/nfs/nfs4_fs.h > +++ b/fs/nfs/nfs4_fs.h > @@ -47,6 +47,7 @@ enum nfs4_client_state { > NFS4CLNT_LAYOUTRECALL, > NFS4CLNT_SESSION_RESET, > NFS4CLNT_RECALL_SLOT, > + NFS4CLNT_LEASE_CONFIRM, > }; > > enum nfs4_session_state { > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c > index 628e35f..2507f1f 100644 > --- a/fs/nfs/nfs4proc.c > +++ b/fs/nfs/nfs4proc.c > @@ -3726,46 +3726,36 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, > .rpc_cred = cred, > }; > __be32 *p; > - int loop = 0; > int status; > > p = (__be32*)sc_verifier.data; > *p++ = htonl((u32)clp->cl_boot_time.tv_sec); > *p = htonl((u32)clp->cl_boot_time.tv_nsec); > > - for(;;) { > - setclientid.sc_name_len = scnprintf(setclientid.sc_name, > - sizeof(setclientid.sc_name), "%s/%s %s %s %u", > - clp->cl_ipaddr, > - rpc_peeraddr2str(clp->cl_rpcclient, > - RPC_DISPLAY_ADDR), > - rpc_peeraddr2str(clp->cl_rpcclient, > - RPC_DISPLAY_PROTO), > - clp->cl_rpcclient->cl_auth->au_ops->au_name, > - clp->cl_id_uniquifier); > - setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, > - sizeof(setclientid.sc_netid), > - rpc_peeraddr2str(clp->cl_rpcclient, > - RPC_DISPLAY_NETID)); > - setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, > - sizeof(setclientid.sc_uaddr), "%s.%u.%u", > - clp->cl_ipaddr, port >> 8, port & 255); > - > - 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 / HZ + 1); > - else > - if (++clp->cl_id_uniquifier == 0) > - break; > - } > + setclientid.sc_name_len = scnprintf(setclientid.sc_name, > + sizeof(setclientid.sc_name), "%s/%s %s %s %u", > + clp->cl_ipaddr, > + rpc_peeraddr2str(clp->cl_rpcclient, > + RPC_DISPLAY_ADDR), > + rpc_peeraddr2str(clp->cl_rpcclient, > + RPC_DISPLAY_PROTO), > + clp->cl_rpcclient->cl_auth->au_ops->au_name, > + clp->cl_id_uniquifier); > + setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, > + sizeof(setclientid.sc_netid), > + rpc_peeraddr2str(clp->cl_rpcclient, > + RPC_DISPLAY_NETID)); > + setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, > + sizeof(setclientid.sc_uaddr), "%s.%u.%u", > + clp->cl_ipaddr, port >> 8, port & 255); > + > + status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); > + if (status == -NFS4ERR_CLID_INUSE) > + ssleep(clp->cl_lease_time / HZ + 1); > 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 rpc_cred *cred) > { > @@ -3790,26 +3780,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, > 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_delegreturnargs args; > struct nfs4_delegreturnres res; > @@ -5222,20 +5192,10 @@ int nfs4_proc_create_session(struct nfs_client *clp) > int status; > unsigned *ptr; > struct nfs4_session *session = clp->cl_session; > - long timeout = 0; > - int err; > > dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); > > - do { > - 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); > - > + status = _nfs4_proc_create_session(clp); > if (status) > goto out; > > diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c > index 4dfb34b..9a7f9df 100644 > --- a/fs/nfs/nfs4state.c > +++ b/fs/nfs/nfs4state.c > @@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); > > 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; > int status; > > + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) > + goto do_confirm; > port = nfs_callback_tcpport; > if (clp->cl_addr.ss_family == AF_INET6) > 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); > if (status != 0) > 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); > if (status != 0) > goto out; > - clp->cl_clientid = clid.clientid; > + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > nfs4_schedule_state_renewal(clp); > out: > return status; > @@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) > { > int status; > > + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) > + goto do_confirm; > nfs4_begin_drain_session(clp); > status = nfs4_proc_exchange_id(clp, cred); > if (status != 0) > goto out; > + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > +do_confirm: > status = nfs4_proc_create_session(clp); > if (status != 0) > goto out; > + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > nfs41_setup_state_renewal(clp); > nfs_mark_client_ready(clp, NFS_CS_READY); > out: > @@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } > */ > static void nfs4_set_lease_expired(struct nfs_client *clp, int status) > { > - if (nfs4_has_session(clp)) { > - switch (status) { > - case -NFS4ERR_DELAY: > - case -NFS4ERR_CLID_INUSE: > - case -EAGAIN: > - break; > + switch (status) { > + case -NFS4ERR_CLID_INUSE: > + clp->cl_id_uniquifier++; > + case -NFS4ERR_STALE_CLIENTID: > + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > + break; > + case -NFS4ERR_DELAY: > + case -EAGAIN: > + ssleep(1); > + break; > > - case -EKEYEXPIRED: > - nfs4_warn_keyexpired(clp->cl_hostname); > - case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery > - * in nfs4_exchange_id */ > - default: > - return; > - } > + case -EKEYEXPIRED: > + nfs4_warn_keyexpired(clp->cl_hostname); > + case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery > + * in nfs4_exchange_id */ > + default: > + return; > } > set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); > } > diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h > index 216cea5..87694ca 100644 > --- a/include/linux/nfs_fs_sb.h > +++ b/include/linux/nfs_fs_sb.h > @@ -47,6 +47,7 @@ struct nfs_client { > > #ifdef CONFIG_NFS_V4 > u64 cl_clientid; /* constant */ > + nfs4_verifier cl_confirm; /* Clientid verifier */ > unsigned long cl_state; > > spinlock_t cl_lock; > -- > 1.7.4.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, 2011-04-21 at 11:39 -0400, Chuck Lever wrote: > Hi- > > This will require some significant human intervention to merge with my code that caches the long-form client ID. How so? It really isn't doing much more than removing those 'for(;;)' loops. > On Apr 20, 2011, at 7:50 PM, Trond Myklebust wrote: > > > 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> > > --- > > fs/nfs/nfs4_fs.h | 1 + > > fs/nfs/nfs4proc.c | 84 ++++++++++++--------------------------------- > > fs/nfs/nfs4state.c | 47 +++++++++++++++++-------- > > include/linux/nfs_fs_sb.h | 1 + > > 4 files changed, 56 insertions(+), 77 deletions(-) > > > > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h > > index e1c261d..c4a6983 100644 > > --- a/fs/nfs/nfs4_fs.h > > +++ b/fs/nfs/nfs4_fs.h > > @@ -47,6 +47,7 @@ enum nfs4_client_state { > > NFS4CLNT_LAYOUTRECALL, > > NFS4CLNT_SESSION_RESET, > > NFS4CLNT_RECALL_SLOT, > > + NFS4CLNT_LEASE_CONFIRM, > > }; > > > > enum nfs4_session_state { > > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c > > index 628e35f..2507f1f 100644 > > --- a/fs/nfs/nfs4proc.c > > +++ b/fs/nfs/nfs4proc.c > > @@ -3726,46 +3726,36 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, > > .rpc_cred = cred, > > }; > > __be32 *p; > > - int loop = 0; > > int status; > > > > p = (__be32*)sc_verifier.data; > > *p++ = htonl((u32)clp->cl_boot_time.tv_sec); > > *p = htonl((u32)clp->cl_boot_time.tv_nsec); > > > > - for(;;) { > > - setclientid.sc_name_len = scnprintf(setclientid.sc_name, > > - sizeof(setclientid.sc_name), "%s/%s %s %s %u", > > - clp->cl_ipaddr, > > - rpc_peeraddr2str(clp->cl_rpcclient, > > - RPC_DISPLAY_ADDR), > > - rpc_peeraddr2str(clp->cl_rpcclient, > > - RPC_DISPLAY_PROTO), > > - clp->cl_rpcclient->cl_auth->au_ops->au_name, > > - clp->cl_id_uniquifier); > > - setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, > > - sizeof(setclientid.sc_netid), > > - rpc_peeraddr2str(clp->cl_rpcclient, > > - RPC_DISPLAY_NETID)); > > - setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, > > - sizeof(setclientid.sc_uaddr), "%s.%u.%u", > > - clp->cl_ipaddr, port >> 8, port & 255); > > - > > - 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 / HZ + 1); > > - else > > - if (++clp->cl_id_uniquifier == 0) > > - break; > > - } > > + setclientid.sc_name_len = scnprintf(setclientid.sc_name, > > + sizeof(setclientid.sc_name), "%s/%s %s %s %u", > > + clp->cl_ipaddr, > > + rpc_peeraddr2str(clp->cl_rpcclient, > > + RPC_DISPLAY_ADDR), > > + rpc_peeraddr2str(clp->cl_rpcclient, > > + RPC_DISPLAY_PROTO), > > + clp->cl_rpcclient->cl_auth->au_ops->au_name, > > + clp->cl_id_uniquifier); > > + setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, > > + sizeof(setclientid.sc_netid), > > + rpc_peeraddr2str(clp->cl_rpcclient, > > + RPC_DISPLAY_NETID)); > > + setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, > > + sizeof(setclientid.sc_uaddr), "%s.%u.%u", > > + clp->cl_ipaddr, port >> 8, port & 255); > > + > > + status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); > > + if (status == -NFS4ERR_CLID_INUSE) > > + ssleep(clp->cl_lease_time / HZ + 1); > > 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 rpc_cred *cred) > > { > > @@ -3790,26 +3780,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, > > 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_delegreturnargs args; > > struct nfs4_delegreturnres res; > > @@ -5222,20 +5192,10 @@ int nfs4_proc_create_session(struct nfs_client *clp) > > int status; > > unsigned *ptr; > > struct nfs4_session *session = clp->cl_session; > > - long timeout = 0; > > - int err; > > > > dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); > > > > - do { > > - 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); > > - > > + status = _nfs4_proc_create_session(clp); > > if (status) > > goto out; > > > > diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c > > index 4dfb34b..9a7f9df 100644 > > --- a/fs/nfs/nfs4state.c > > +++ b/fs/nfs/nfs4state.c > > @@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); > > > > 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; > > int status; > > > > + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) > > + goto do_confirm; > > port = nfs_callback_tcpport; > > if (clp->cl_addr.ss_family == AF_INET6) > > 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); > > if (status != 0) > > 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); > > if (status != 0) > > goto out; > > - clp->cl_clientid = clid.clientid; > > + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > > nfs4_schedule_state_renewal(clp); > > out: > > return status; > > @@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) > > { > > int status; > > > > + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) > > + goto do_confirm; > > nfs4_begin_drain_session(clp); > > status = nfs4_proc_exchange_id(clp, cred); > > if (status != 0) > > goto out; > > + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > > +do_confirm: > > status = nfs4_proc_create_session(clp); > > if (status != 0) > > goto out; > > + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > > nfs41_setup_state_renewal(clp); > > nfs_mark_client_ready(clp, NFS_CS_READY); > > out: > > @@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } > > */ > > static void nfs4_set_lease_expired(struct nfs_client *clp, int status) > > { > > - if (nfs4_has_session(clp)) { > > - switch (status) { > > - case -NFS4ERR_DELAY: > > - case -NFS4ERR_CLID_INUSE: > > - case -EAGAIN: > > - break; > > + switch (status) { > > + case -NFS4ERR_CLID_INUSE: > > + clp->cl_id_uniquifier++; > > + case -NFS4ERR_STALE_CLIENTID: > > + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); > > + break; > > + case -NFS4ERR_DELAY: > > + case -EAGAIN: > > + ssleep(1); > > + break; > > > > - case -EKEYEXPIRED: > > - nfs4_warn_keyexpired(clp->cl_hostname); > > - case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery > > - * in nfs4_exchange_id */ > > - default: > > - return; > > - } > > + case -EKEYEXPIRED: > > + nfs4_warn_keyexpired(clp->cl_hostname); > > + case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery > > + * in nfs4_exchange_id */ > > + default: > > + return; > > } > > set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); > > } > > diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h > > index 216cea5..87694ca 100644 > > --- a/include/linux/nfs_fs_sb.h > > +++ b/include/linux/nfs_fs_sb.h > > @@ -47,6 +47,7 @@ struct nfs_client { > > > > #ifdef CONFIG_NFS_V4 > > u64 cl_clientid; /* constant */ > > + nfs4_verifier cl_confirm; /* Clientid verifier */ > > unsigned long cl_state; > > > > spinlock_t cl_lock; > > -- > > 1.7.4.4 > > > > -- > > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > > the body of a message to majordomo@vger.kernel.org > > More majordomo info at http://vger.kernel.org/majordomo-info.html >
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index e1c261d..c4a6983 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -47,6 +47,7 @@ enum nfs4_client_state { NFS4CLNT_LAYOUTRECALL, NFS4CLNT_SESSION_RESET, NFS4CLNT_RECALL_SLOT, + NFS4CLNT_LEASE_CONFIRM, }; enum nfs4_session_state { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 628e35f..2507f1f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3726,46 +3726,36 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, .rpc_cred = cred, }; __be32 *p; - int loop = 0; int status; p = (__be32*)sc_verifier.data; *p++ = htonl((u32)clp->cl_boot_time.tv_sec); *p = htonl((u32)clp->cl_boot_time.tv_nsec); - for(;;) { - setclientid.sc_name_len = scnprintf(setclientid.sc_name, - sizeof(setclientid.sc_name), "%s/%s %s %s %u", - clp->cl_ipaddr, - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_ADDR), - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_PROTO), - clp->cl_rpcclient->cl_auth->au_ops->au_name, - clp->cl_id_uniquifier); - setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, - sizeof(setclientid.sc_netid), - rpc_peeraddr2str(clp->cl_rpcclient, - RPC_DISPLAY_NETID)); - setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, - sizeof(setclientid.sc_uaddr), "%s.%u.%u", - clp->cl_ipaddr, port >> 8, port & 255); - - 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 / HZ + 1); - else - if (++clp->cl_id_uniquifier == 0) - break; - } + setclientid.sc_name_len = scnprintf(setclientid.sc_name, + sizeof(setclientid.sc_name), "%s/%s %s %s %u", + clp->cl_ipaddr, + rpc_peeraddr2str(clp->cl_rpcclient, + RPC_DISPLAY_ADDR), + rpc_peeraddr2str(clp->cl_rpcclient, + RPC_DISPLAY_PROTO), + clp->cl_rpcclient->cl_auth->au_ops->au_name, + clp->cl_id_uniquifier); + setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, + sizeof(setclientid.sc_netid), + rpc_peeraddr2str(clp->cl_rpcclient, + RPC_DISPLAY_NETID)); + setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, + sizeof(setclientid.sc_uaddr), "%s.%u.%u", + clp->cl_ipaddr, port >> 8, port & 255); + + status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); + if (status == -NFS4ERR_CLID_INUSE) + ssleep(clp->cl_lease_time / HZ + 1); 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 rpc_cred *cred) { @@ -3790,26 +3780,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, 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_delegreturnargs args; struct nfs4_delegreturnres res; @@ -5222,20 +5192,10 @@ int nfs4_proc_create_session(struct nfs_client *clp) int status; unsigned *ptr; struct nfs4_session *session = clp->cl_session; - long timeout = 0; - int err; dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); - do { - 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); - + status = _nfs4_proc_create_session(clp); if (status) goto out; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4dfb34b..9a7f9df 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); 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; int status; + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) + goto do_confirm; port = nfs_callback_tcpport; if (clp->cl_addr.ss_family == AF_INET6) 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); if (status != 0) 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); if (status != 0) goto out; - clp->cl_clientid = clid.clientid; + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); nfs4_schedule_state_renewal(clp); out: return status; @@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) { int status; + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) + goto do_confirm; nfs4_begin_drain_session(clp); status = nfs4_proc_exchange_id(clp, cred); if (status != 0) goto out; + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +do_confirm: status = nfs4_proc_create_session(clp); if (status != 0) goto out; + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); nfs41_setup_state_renewal(clp); nfs_mark_client_ready(clp, NFS_CS_READY); out: @@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } */ static void nfs4_set_lease_expired(struct nfs_client *clp, int status) { - if (nfs4_has_session(clp)) { - switch (status) { - case -NFS4ERR_DELAY: - case -NFS4ERR_CLID_INUSE: - case -EAGAIN: - break; + switch (status) { + case -NFS4ERR_CLID_INUSE: + clp->cl_id_uniquifier++; + case -NFS4ERR_STALE_CLIENTID: + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); + break; + case -NFS4ERR_DELAY: + case -EAGAIN: + ssleep(1); + break; - case -EKEYEXPIRED: - nfs4_warn_keyexpired(clp->cl_hostname); - case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery - * in nfs4_exchange_id */ - default: - return; - } + case -EKEYEXPIRED: + nfs4_warn_keyexpired(clp->cl_hostname); + case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery + * in nfs4_exchange_id */ + default: + return; } set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); } diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 216cea5..87694ca 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -47,6 +47,7 @@ struct nfs_client { #ifdef CONFIG_NFS_V4 u64 cl_clientid; /* constant */ + nfs4_verifier cl_confirm; /* Clientid verifier */ unsigned long cl_state; spinlock_t cl_lock;
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> --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 84 ++++++++++++--------------------------------- fs/nfs/nfs4state.c | 47 +++++++++++++++++-------- include/linux/nfs_fs_sb.h | 1 + 4 files changed, 56 insertions(+), 77 deletions(-)