aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
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 300faba9a18..e5cd8cacdce 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