aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2012-05-21 22:45:33 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-05-22 16:45:45 -0400
commit2c820d9a97f07b273b2c8a5960bd52b1b5864c68 (patch)
tree5dfdd518744f4987775e8ad531029239efda4b05 /fs
parentce1c8fc12d99386737953dfeb7b531dfa3d18e5e (diff)
NFS: Force server to drop NFSv4 state
nfs4_reset_all_state() refreshes the boot verifier a server sees to trigger that server to wipe this client's state. This function is invoked when an NFSv4.1 server reports that it has revoked some or all of a client's NFSv4 state. To facilitate server trunking discovery, we will eventually want to move the cl_boot_time field to a more global structure. The Uniform Client String model (and specifically, server trunking detection) requires that all servers see the same boot verifier until the client actually does reboot, and not a fresh verifier every time the client unmounts and remounts the server. Without the cl_boot_time field, however, nfs4_reset_all_state() will have to find some other 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 happen to be timestamps), we can force the server to wipe NFSv4 state by updating the boot verifier as we do now, then immediately 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@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4proc.c11
-rw-r--r--fs/nfs/nfs4state.c13
3 files changed, 21 insertions, 4 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1526fdf47c4c..e6da02124c4e 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -24,6 +24,7 @@ enum nfs4_client_state {
24 NFS4CLNT_RECALL_SLOT, 24 NFS4CLNT_RECALL_SLOT,
25 NFS4CLNT_LEASE_CONFIRM, 25 NFS4CLNT_LEASE_CONFIRM,
26 NFS4CLNT_SERVER_SCOPE_MISMATCH, 26 NFS4CLNT_SERVER_SCOPE_MISMATCH,
27 NFS4CLNT_PURGE_STATE,
27}; 28};
28 29
29enum nfs4_session_state { 30enum nfs4_session_state {
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ab6b2e5c923e..81ccdbbb43e8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3908,8 +3908,15 @@ static void nfs4_construct_boot_verifier(struct nfs_client *clp,
3908{ 3908{
3909 __be32 verf[2]; 3909 __be32 verf[2];
3910 3910
3911 verf[0] = (__be32)clp->cl_boot_time.tv_sec; 3911 if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
3912 verf[1] = (__be32)clp->cl_boot_time.tv_nsec; 3912 /* An impossible timestamp guarantees this value
3913 * will never match a generated boot time. */
3914 verf[0] = 0;
3915 verf[1] = (__be32)(NSEC_PER_SEC + 1);
3916 } else {
3917 verf[0] = (__be32)clp->cl_boot_time.tv_sec;
3918 verf[1] = (__be32)clp->cl_boot_time.tv_nsec;
3919 }
3913 memcpy(bootverf->data, verf, sizeof(bootverf->data)); 3920 memcpy(bootverf->data, verf, sizeof(bootverf->data));
3914} 3921}
3915 3922
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index f8c06dec6563..32cce4a276e8 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1615,7 +1615,7 @@ void nfs41_handle_recall_slot(struct nfs_client *clp)
1615static void nfs4_reset_all_state(struct nfs_client *clp) 1615static void nfs4_reset_all_state(struct nfs_client *clp)
1616{ 1616{
1617 if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { 1617 if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
1618 clp->cl_boot_time = CURRENT_TIME; 1618 set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
1619 nfs4_state_start_reclaim_nograce(clp); 1619 nfs4_state_start_reclaim_nograce(clp);
1620 nfs4_schedule_state_manager(clp); 1620 nfs4_schedule_state_manager(clp);
1621 } 1621 }
@@ -1631,7 +1631,6 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp)
1631 1631
1632static void nfs41_handle_state_revoked(struct nfs_client *clp) 1632static void nfs41_handle_state_revoked(struct nfs_client *clp)
1633{ 1633{
1634 /* Temporary */
1635 nfs4_reset_all_state(clp); 1634 nfs4_reset_all_state(clp);
1636} 1635}
1637 1636
@@ -1652,6 +1651,10 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
1652{ 1651{
1653 if (!flags) 1652 if (!flags)
1654 return; 1653 return;
1654
1655 dprintk("%s: \"%s\" (client ID %llx) flags=0x%08x\n",
1656 __func__, clp->cl_hostname, clp->cl_clientid, flags);
1657
1655 if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) 1658 if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
1656 nfs41_handle_server_reboot(clp); 1659 nfs41_handle_server_reboot(clp);
1657 if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | 1660 if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
@@ -1762,6 +1765,12 @@ static void nfs4_state_manager(struct nfs_client *clp)
1762 1765
1763 /* Ensure exclusive access to NFSv4 state */ 1766 /* Ensure exclusive access to NFSv4 state */
1764 do { 1767 do {
1768 if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
1769 nfs4_reclaim_lease(clp);
1770 clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
1771 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1772 }
1773
1765 if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { 1774 if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
1766 /* We're going to have to re-establish a clientid */ 1775 /* We're going to have to re-establish a clientid */
1767 status = nfs4_reclaim_lease(clp); 1776 status = nfs4_reclaim_lease(clp);