aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
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
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')
-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 0ac6bbb8eaa..1c6fbd1cda9 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 d53aa2dace8..279ab36b5a6 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 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