aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:41 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:41 -0500
commitb79a4a1b45b2543e38026303a1956bdc0aababa0 (patch)
tree73c7dba187dbe05f5527f47ccb42523f4655f77b /fs/nfs/nfs4state.c
parent6dc9d57af9917f5c7faa13c17b770dce17c3972b (diff)
NFSv4: Fix state recovery when the client runs over the grace period
If the client for some reason is not able to recover all its state within the time allotted for the grace period, and the server reboots again, the client is not allowed to recover the state that was 'lost' using reboot recovery. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r--fs/nfs/nfs4state.c189
1 files changed, 144 insertions, 45 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 300faba9a18a..e5cd8cacdcee 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -821,6 +821,27 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp)
821 nfs4_recover_state(clp); 821 nfs4_recover_state(clp);
822} 822}
823 823
824static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
825{
826
827 set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
828 /* Don't recover state that expired before the reboot */
829 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) {
830 clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
831 return 0;
832 }
833 set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
834 return 1;
835}
836
837static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
838{
839 set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
840 clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
841 set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
842 return 1;
843}
844
824static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) 845static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
825{ 846{
826 struct inode *inode = state->inode; 847 struct inode *inode = state->inode;
@@ -869,6 +890,8 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
869 * server that doesn't support a grace period. 890 * server that doesn't support a grace period.
870 */ 891 */
871 list_for_each_entry(state, &sp->so_states, open_states) { 892 list_for_each_entry(state, &sp->so_states, open_states) {
893 if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
894 continue;
872 if (state->state == 0) 895 if (state->state == 0)
873 continue; 896 continue;
874 status = ops->recover_open(sp, state); 897 status = ops->recover_open(sp, state);
@@ -888,8 +911,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
888 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", 911 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
889 __func__, status); 912 __func__, status);
890 case -ENOENT: 913 case -ENOENT:
891 case -NFS4ERR_RECLAIM_BAD: 914 case -ESTALE:
892 case -NFS4ERR_RECLAIM_CONFLICT:
893 /* 915 /*
894 * Open state on this file cannot be recovered 916 * Open state on this file cannot be recovered
895 * All we can do is revert to using the zero stateid. 917 * All we can do is revert to using the zero stateid.
@@ -899,8 +921,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
899 /* Mark the file as being 'closed' */ 921 /* Mark the file as being 'closed' */
900 state->state = 0; 922 state->state = 0;
901 break; 923 break;
924 case -NFS4ERR_RECLAIM_BAD:
925 case -NFS4ERR_RECLAIM_CONFLICT:
926 nfs4_state_mark_reclaim_nograce(sp->so_client, state);
927 break;
902 case -NFS4ERR_EXPIRED: 928 case -NFS4ERR_EXPIRED:
903 case -NFS4ERR_NO_GRACE: 929 case -NFS4ERR_NO_GRACE:
930 nfs4_state_mark_reclaim_nograce(sp->so_client, state);
904 case -NFS4ERR_STALE_CLIENTID: 931 case -NFS4ERR_STALE_CLIENTID:
905 goto out_err; 932 goto out_err;
906 } 933 }
@@ -910,12 +937,26 @@ out_err:
910 return status; 937 return status;
911} 938}
912 939
913static void nfs4_state_mark_reclaim(struct nfs_client *clp) 940static void nfs4_clear_open_state(struct nfs4_state *state)
941{
942 struct nfs4_lock_state *lock;
943
944 clear_bit(NFS_DELEGATED_STATE, &state->flags);
945 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
946 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
947 clear_bit(NFS_O_RDWR_STATE, &state->flags);
948 list_for_each_entry(lock, &state->lock_states, ls_locks) {
949 lock->ls_seqid.counter = 0;
950 lock->ls_seqid.flags = 0;
951 lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
952 }
953}
954
955static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
914{ 956{
915 struct nfs4_state_owner *sp; 957 struct nfs4_state_owner *sp;
916 struct rb_node *pos; 958 struct rb_node *pos;
917 struct nfs4_state *state; 959 struct nfs4_state *state;
918 struct nfs4_lock_state *lock;
919 960
920 /* Reset all sequence ids to zero */ 961 /* Reset all sequence ids to zero */
921 for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { 962 for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
@@ -924,20 +965,60 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp)
924 sp->so_seqid.flags = 0; 965 sp->so_seqid.flags = 0;
925 spin_lock(&sp->so_lock); 966 spin_lock(&sp->so_lock);
926 list_for_each_entry(state, &sp->so_states, open_states) { 967 list_for_each_entry(state, &sp->so_states, open_states) {
927 clear_bit(NFS_DELEGATED_STATE, &state->flags); 968 if (mark_reclaim(clp, state))
928 clear_bit(NFS_O_RDONLY_STATE, &state->flags); 969 nfs4_clear_open_state(state);
929 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
930 clear_bit(NFS_O_RDWR_STATE, &state->flags);
931 list_for_each_entry(lock, &state->lock_states, ls_locks) {
932 lock->ls_seqid.counter = 0;
933 lock->ls_seqid.flags = 0;
934 lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
935 }
936 } 970 }
937 spin_unlock(&sp->so_lock); 971 spin_unlock(&sp->so_lock);
938 } 972 }
939} 973}
940 974
975static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
976{
977 /* Mark all delegations for reclaim */
978 nfs_delegation_mark_reclaim(clp);
979 nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
980}
981
982static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
983{
984 struct nfs4_state_owner *sp;
985 struct rb_node *pos;
986 struct nfs4_state *state;
987
988 if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
989 return;
990
991 for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
992 sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
993 spin_lock(&sp->so_lock);
994 list_for_each_entry(state, &sp->so_states, open_states) {
995 if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags))
996 continue;
997 nfs4_state_mark_reclaim_nograce(clp, state);
998 }
999 spin_unlock(&sp->so_lock);
1000 }
1001
1002 nfs_delegation_reap_unclaimed(clp);
1003}
1004
1005static void nfs_delegation_clear_all(struct nfs_client *clp)
1006{
1007 nfs_delegation_mark_reclaim(clp);
1008 nfs_delegation_reap_unclaimed(clp);
1009}
1010
1011static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
1012{
1013 nfs_delegation_clear_all(clp);
1014 nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
1015}
1016
1017static void nfs4_state_end_reclaim_nograce(struct nfs_client *clp)
1018{
1019 clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
1020}
1021
941static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) 1022static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
942{ 1023{
943 struct rb_node *pos; 1024 struct rb_node *pos;
@@ -964,11 +1045,25 @@ static int nfs4_check_lease(struct nfs_client *clp)
964 /* Yes there are: try to renew the old lease */ 1045 /* Yes there are: try to renew the old lease */
965 status = nfs4_proc_renew(clp, cred); 1046 status = nfs4_proc_renew(clp, cred);
966 put_rpccred(cred); 1047 put_rpccred(cred);
1048 switch (status) {
1049 case -NFS4ERR_CB_PATH_DOWN:
1050 set_bit(NFS4CLNT_CB_PATH_DOWN, &clp->cl_state);
1051 break;
1052 case -NFS4ERR_STALE_CLIENTID:
1053 case -NFS4ERR_LEASE_MOVED:
1054 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1055 nfs4_state_start_reclaim_reboot(clp);
1056 break;
1057 case -NFS4ERR_EXPIRED:
1058 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1059 nfs4_state_start_reclaim_nograce(clp);
1060 }
967 return status; 1061 return status;
968 } 1062 }
969 1063
970 /* "reboot" to ensure we clear all state on the server */ 1064 /* "reboot" to ensure we clear all state on the server */
971 clp->cl_boot_time = CURRENT_TIME; 1065 clp->cl_boot_time = CURRENT_TIME;
1066 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
972 return status; 1067 return status;
973} 1068}
974 1069
@@ -993,7 +1088,6 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
993static int reclaimer(void *ptr) 1088static int reclaimer(void *ptr)
994{ 1089{
995 struct nfs_client *clp = ptr; 1090 struct nfs_client *clp = ptr;
996 const struct nfs4_state_recovery_ops *ops;
997 int status = 0; 1091 int status = 0;
998 1092
999 allow_signal(SIGKILL); 1093 allow_signal(SIGKILL);
@@ -1001,47 +1095,51 @@ static int reclaimer(void *ptr)
1001 /* Ensure exclusive access to NFSv4 state */ 1095 /* Ensure exclusive access to NFSv4 state */
1002 down_write(&clp->cl_sem); 1096 down_write(&clp->cl_sem);
1003 while (!list_empty(&clp->cl_superblocks)) { 1097 while (!list_empty(&clp->cl_superblocks)) {
1004 ops = &nfs4_network_partition_recovery_ops;
1005 status = nfs4_check_lease(clp); 1098 status = nfs4_check_lease(clp);
1006 switch (status) {
1007 case 0:
1008 case -NFS4ERR_CB_PATH_DOWN:
1009 goto out;
1010 case -NFS4ERR_STALE_CLIENTID:
1011 case -NFS4ERR_LEASE_MOVED:
1012 ops = &nfs4_reboot_recovery_ops;
1013 }
1014 1099
1015 /* We're going to have to re-establish a clientid */ 1100 if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
1016 nfs4_state_mark_reclaim(clp); 1101 /* We're going to have to re-establish a clientid */
1102 status = nfs4_reclaim_lease(clp);
1103 if (status) {
1104 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1105 if (status == -EAGAIN)
1106 continue;
1107 goto out_error;
1108 }
1109 }
1017 1110
1018 status = nfs4_reclaim_lease(clp); 1111 /* First recover reboot state... */
1019 if (status) { 1112 if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
1020 if (status == -EAGAIN) 1113 /* Note: list is protected by exclusive lock on cl->cl_sem */
1114 status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops);
1115 if (status == -NFS4ERR_STALE_CLIENTID) {
1116 set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
1021 continue; 1117 continue;
1022 goto out_error; 1118 }
1119 nfs4_state_end_reclaim_reboot(clp);
1120 continue;
1023 } 1121 }
1024 1122
1025 /* Mark all delegations for reclaim */ 1123 /* Now recover expired state... */
1026 nfs_delegation_mark_reclaim(clp); 1124 if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
1027 /* Note: list is protected by exclusive lock on cl->cl_sem */ 1125 /* Note: list is protected by exclusive lock on cl->cl_sem */
1028 status = nfs4_do_reclaim(clp, ops); 1126 status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops);
1029 if (status < 0) { 1127 if (status < 0) {
1030 if (status == -NFS4ERR_NO_GRACE) { 1128 set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
1031 ops = &nfs4_network_partition_recovery_ops; 1129 if (status == -NFS4ERR_STALE_CLIENTID)
1032 status = nfs4_do_reclaim(clp, ops); 1130 continue;
1033 } 1131 if (status == -NFS4ERR_EXPIRED)
1034 if (status == -NFS4ERR_STALE_CLIENTID) 1132 continue;
1035 continue; 1133 goto out_error;
1036 if (status == -NFS4ERR_EXPIRED) 1134 } else
1037 continue; 1135 nfs4_state_end_reclaim_nograce(clp);
1136 continue;
1038 } 1137 }
1039 nfs_delegation_reap_unclaimed(clp);
1040 break; 1138 break;
1041 } 1139 }
1042out: 1140out:
1043 up_write(&clp->cl_sem); 1141 up_write(&clp->cl_sem);
1044 if (status == -NFS4ERR_CB_PATH_DOWN) 1142 if (test_and_clear_bit(NFS4CLNT_CB_PATH_DOWN, &clp->cl_state))
1045 nfs_handle_cb_pathdown(clp); 1143 nfs_handle_cb_pathdown(clp);
1046 nfs4_clear_recover_bit(clp); 1144 nfs4_clear_recover_bit(clp);
1047 nfs_put_client(clp); 1145 nfs_put_client(clp);
@@ -1050,7 +1148,8 @@ out:
1050out_error: 1148out_error:
1051 printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s" 1149 printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s"
1052 " with error %d\n", clp->cl_hostname, -status); 1150 " with error %d\n", clp->cl_hostname, -status);
1053 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); 1151 if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
1152 nfs4_state_end_reclaim_reboot(clp);
1054 goto out; 1153 goto out;
1055} 1154}
1056 1155