On Mon, 2012-04-23 at 16:54 -0400, Chuck Lever wrote: > A SETCLIENTID boot verifier is nothing more than a boot timestamp. > An NFSv4 server is obligated to wipe all NFSv4 state for an NFS client > when the client presents an updated SETCLIENTID boot verifier. This > is how servers detect client reboots. > > nfs4_reset_all_state() forces a boot verifier refresh to cause a > server to wipe state as part of recovering from a server reporting > that it has revoked some or all of a client's NFSv4 state. This wipes > the slate for full state recovery. > > Soon we want to get rid of the per-nfs_client cl_boot_time field, > however. Without cl_boot_time, the NFS client will need to find a > different way to force the server to purge the client's NFSv4 state. > > Because these verifiers are opaque (ie, the server doesn't know or > care that they are timestamps), we can do this by using the same > trick we use now, but then afterwards establish a fresh client ID > using the old boot verifier again. > > Hopefully there are no extra paranoid server implementations that keep > track of the client's boot verifiers and prevent clients from reusing > a previous one. > > Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> > --- > > fs/nfs/nfs4_fs.h | 1 + > fs/nfs/nfs4proc.c | 9 +++++++-- > fs/nfs/nfs4state.c | 7 ++++++- > 3 files changed, 14 insertions(+), 3 deletions(-) > > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h > index d8c2d39..2953f2c 100644 > --- a/fs/nfs/nfs4_fs.h > +++ b/fs/nfs/nfs4_fs.h > @@ -24,6 +24,7 @@ enum nfs4_client_state { > NFS4CLNT_RECALL_SLOT, > NFS4CLNT_LEASE_CONFIRM, > NFS4CLNT_SERVER_SCOPE_MISMATCH, > + NFS4CLNT_PURGE_STATE, > }; > > enum nfs4_session_state { > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c > index 84a26d9..b19cf81 100644 > --- a/fs/nfs/nfs4proc.c > +++ b/fs/nfs/nfs4proc.c > @@ -3878,8 +3878,13 @@ static void nfs4_construct_boot_verifier(struct nfs_client *clp, > { > __be32 verf[2]; > > - verf[0] = (__be32)clp->cl_boot_time.tv_sec; > - verf[1] = (__be32)clp->cl_boot_time.tv_nsec; > + if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) { > + verf[0] = (__be32)CURRENT_TIME.tv_sec; > + verf[1] = (__be32)CURRENT_TIME.tv_nsec; > + } else { > + verf[0] = (__be32)clp->cl_boot_time.tv_sec; > + verf[1] = (__be32)clp->cl_boot_time.tv_nsec; > + } > memcpy(bootverf->data, verf, sizeof(bootverf->data)); > } > > diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c > index cbef366..7f56502 100644 > --- a/fs/nfs/nfs4state.c > +++ b/fs/nfs/nfs4state.c > @@ -1612,7 +1612,7 @@ void nfs41_handle_recall_slot(struct nfs_client *clp) > static void nfs4_reset_all_state(struct nfs_client *clp) > { > if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { > - clp->cl_boot_time = CURRENT_TIME; > + set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); > nfs4_state_start_reclaim_nograce(clp); > nfs4_schedule_state_manager(clp); > } > @@ -1759,6 +1759,11 @@ static void nfs4_state_manager(struct nfs_client *clp) > > /* Ensure exclusive access to NFSv4 state */ > do { > + if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) { > + nfs4_reclaim_lease(clp); > + clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); This needs to set NFS4CLNT_LEASE_EXPIRED, so that we do a second SETCLIENTID after the state has been cleared. Otherwise we end up with a lease with the wrong verifier. > + } > + > if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { > /* We're going to have to re-establish a clientid */ > status = nfs4_reclaim_lease(clp); > -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@xxxxxxxxxx www.netapp.com ��.n��������+%������w��{.n�����{��w���jg��������ݢj����G�������j:+v���w�m������w�������h�����٥