aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4_fs.h8
-rw-r--r--fs/nfs/nfs4proc.c7
-rw-r--r--fs/nfs/nfs4state.c189
3 files changed, 155 insertions, 49 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 0ac6bbb8eaa4..1c6fbd1cda97 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -40,6 +40,9 @@ struct idmap;
40enum nfs4_client_state { 40enum nfs4_client_state {
41 NFS4CLNT_STATE_RECOVER = 0, 41 NFS4CLNT_STATE_RECOVER = 0,
42 NFS4CLNT_LEASE_EXPIRED, 42 NFS4CLNT_LEASE_EXPIRED,
43 NFS4CLNT_RECLAIM_REBOOT,
44 NFS4CLNT_RECLAIM_NOGRACE,
45 NFS4CLNT_CB_PATH_DOWN,
43}; 46};
44 47
45/* 48/*
@@ -128,6 +131,8 @@ enum {
128 NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ 131 NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
129 NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ 132 NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
130 NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ 133 NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
134 NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */
135 NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */
131}; 136};
132 137
133struct nfs4_state { 138struct nfs4_state {
@@ -160,6 +165,7 @@ struct nfs4_exception {
160}; 165};
161 166
162struct nfs4_state_recovery_ops { 167struct nfs4_state_recovery_ops {
168 int state_flag_bit;
163 int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); 169 int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);
164 int (*recover_lock)(struct nfs4_state *, struct file_lock *); 170 int (*recover_lock)(struct nfs4_state *, struct file_lock *);
165}; 171};
@@ -187,7 +193,7 @@ extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
187 struct nfs4_fs_locations *fs_locations, struct page *page); 193 struct nfs4_fs_locations *fs_locations, struct page *page);
188 194
189extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; 195extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
190extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; 196extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops;
191 197
192extern const u32 nfs4_fattr_bitmap[2]; 198extern const u32 nfs4_fattr_bitmap[2];
193extern const u32 nfs4_statfs_bitmap[2]; 199extern const u32 nfs4_statfs_bitmap[2];
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d53aa2dace84..279ab36b5a67 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -984,7 +984,7 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
984 ret = nfs4_wait_clnt_recover(server->client, clp); 984 ret = nfs4_wait_clnt_recover(server->client, clp);
985 if (ret != 0) 985 if (ret != 0)
986 return ret; 986 return ret;
987 if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) 987 if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
988 break; 988 break;
989 nfs4_schedule_state_recovery(clp); 989 nfs4_schedule_state_recovery(clp);
990 } 990 }
@@ -2942,7 +2942,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre
2942 spin_lock(&clp->cl_lock); 2942 spin_lock(&clp->cl_lock);
2943 clp->cl_lease_time = fsinfo.lease_time * HZ; 2943 clp->cl_lease_time = fsinfo.lease_time * HZ;
2944 clp->cl_last_renewal = now; 2944 clp->cl_last_renewal = now;
2945 clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
2946 spin_unlock(&clp->cl_lock); 2945 spin_unlock(&clp->cl_lock);
2947 } 2946 }
2948 return status; 2947 return status;
@@ -3690,11 +3689,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
3690} 3689}
3691 3690
3692struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { 3691struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
3692 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
3693 .recover_open = nfs4_open_reclaim, 3693 .recover_open = nfs4_open_reclaim,
3694 .recover_lock = nfs4_lock_reclaim, 3694 .recover_lock = nfs4_lock_reclaim,
3695}; 3695};
3696 3696
3697struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { 3697struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = {
3698 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
3698 .recover_open = nfs4_open_expired, 3699 .recover_open = nfs4_open_expired,
3699 .recover_lock = nfs4_lock_expired, 3700 .recover_lock = nfs4_lock_expired,
3700}; 3701};
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