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.c153
1 files changed, 135 insertions, 18 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 0298e909559f..2cfca9929c9a 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid;
60 60
61static LIST_HEAD(nfs4_clientid_list); 61static LIST_HEAD(nfs4_clientid_list);
62 62
63static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) 63int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
64{ 64{
65 unsigned short port; 65 unsigned short port;
66 int status; 66 int status;
@@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
77 return status; 77 return status;
78} 78}
79 79
80static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) 80struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
81{ 81{
82 struct rpc_cred *cred = NULL; 82 struct rpc_cred *cred = NULL;
83 83
@@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
114 return cred; 114 return cred;
115} 115}
116 116
117static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) 117#if defined(CONFIG_NFS_V4_1)
118
119struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
118{ 120{
119 struct rpc_cred *cred; 121 struct rpc_cred *cred;
120 122
121 spin_lock(&clp->cl_lock); 123 spin_lock(&clp->cl_lock);
122 cred = nfs4_get_renew_cred_locked(clp); 124 cred = nfs4_get_machine_cred_locked(clp);
123 spin_unlock(&clp->cl_lock); 125 spin_unlock(&clp->cl_lock);
124 return cred; 126 return cred;
125} 127}
126 128
127static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) 129#endif /* CONFIG_NFS_V4_1 */
130
131struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
128{ 132{
129 struct nfs4_state_owner *sp; 133 struct nfs4_state_owner *sp;
130 struct rb_node *pos; 134 struct rb_node *pos;
@@ -738,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
738 742
739void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) 743void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
740{ 744{
741 if (status == -NFS4ERR_BAD_SEQID) { 745 struct nfs4_state_owner *sp = container_of(seqid->sequence,
742 struct nfs4_state_owner *sp = container_of(seqid->sequence, 746 struct nfs4_state_owner, so_seqid);
743 struct nfs4_state_owner, so_seqid); 747 struct nfs_server *server = sp->so_server;
748
749 if (status == -NFS4ERR_BAD_SEQID)
744 nfs4_drop_state_owner(sp); 750 nfs4_drop_state_owner(sp);
745 } 751 if (!nfs4_has_session(server->nfs_client))
746 nfs_increment_seqid(status, seqid); 752 nfs_increment_seqid(status, seqid);
747} 753}
748 754
749/* 755/*
@@ -1042,6 +1048,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1042 case -NFS4ERR_EXPIRED: 1048 case -NFS4ERR_EXPIRED:
1043 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); 1049 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1044 nfs4_state_start_reclaim_nograce(clp); 1050 nfs4_state_start_reclaim_nograce(clp);
1051 case -NFS4ERR_BADSESSION:
1052 case -NFS4ERR_BADSLOT:
1053 case -NFS4ERR_BAD_HIGH_SLOT:
1054 case -NFS4ERR_DEADSESSION:
1055 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1056 case -NFS4ERR_SEQ_FALSE_RETRY:
1057 case -NFS4ERR_SEQ_MISORDERED:
1058 set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
1045 } 1059 }
1046} 1060}
1047 1061
@@ -1075,18 +1089,22 @@ restart:
1075static int nfs4_check_lease(struct nfs_client *clp) 1089static int nfs4_check_lease(struct nfs_client *clp)
1076{ 1090{
1077 struct rpc_cred *cred; 1091 struct rpc_cred *cred;
1092 struct nfs4_state_maintenance_ops *ops =
1093 nfs4_state_renewal_ops[clp->cl_minorversion];
1078 int status = -NFS4ERR_EXPIRED; 1094 int status = -NFS4ERR_EXPIRED;
1079 1095
1080 /* Is the client already known to have an expired lease? */ 1096 /* Is the client already known to have an expired lease? */
1081 if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) 1097 if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1082 return 0; 1098 return 0;
1083 cred = nfs4_get_renew_cred(clp); 1099 spin_lock(&clp->cl_lock);
1100 cred = ops->get_state_renewal_cred_locked(clp);
1101 spin_unlock(&clp->cl_lock);
1084 if (cred == NULL) { 1102 if (cred == NULL) {
1085 cred = nfs4_get_setclientid_cred(clp); 1103 cred = nfs4_get_setclientid_cred(clp);
1086 if (cred == NULL) 1104 if (cred == NULL)
1087 goto out; 1105 goto out;
1088 } 1106 }
1089 status = nfs4_proc_renew(clp, cred); 1107 status = ops->renew_lease(clp, cred);
1090 put_rpccred(cred); 1108 put_rpccred(cred);
1091out: 1109out:
1092 nfs4_recovery_handle_error(clp, status); 1110 nfs4_recovery_handle_error(clp, status);
@@ -1096,21 +1114,98 @@ out:
1096static int nfs4_reclaim_lease(struct nfs_client *clp) 1114static int nfs4_reclaim_lease(struct nfs_client *clp)
1097{ 1115{
1098 struct rpc_cred *cred; 1116 struct rpc_cred *cred;
1117 struct nfs4_state_recovery_ops *ops =
1118 nfs4_reboot_recovery_ops[clp->cl_minorversion];
1099 int status = -ENOENT; 1119 int status = -ENOENT;
1100 1120
1101 cred = nfs4_get_setclientid_cred(clp); 1121 cred = ops->get_clid_cred(clp);
1102 if (cred != NULL) { 1122 if (cred != NULL) {
1103 status = nfs4_init_client(clp, cred); 1123 status = ops->establish_clid(clp, cred);
1104 put_rpccred(cred); 1124 put_rpccred(cred);
1105 /* Handle case where the user hasn't set up machine creds */ 1125 /* Handle case where the user hasn't set up machine creds */
1106 if (status == -EACCES && cred == clp->cl_machine_cred) { 1126 if (status == -EACCES && cred == clp->cl_machine_cred) {
1107 nfs4_clear_machine_cred(clp); 1127 nfs4_clear_machine_cred(clp);
1108 status = -EAGAIN; 1128 status = -EAGAIN;
1109 } 1129 }
1130 if (status == -NFS4ERR_MINOR_VERS_MISMATCH)
1131 status = -EPROTONOSUPPORT;
1110 } 1132 }
1111 return status; 1133 return status;
1112} 1134}
1113 1135
1136#ifdef CONFIG_NFS_V4_1
1137static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err)
1138{
1139 switch (err) {
1140 case -NFS4ERR_STALE_CLIENTID:
1141 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1142 set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
1143 }
1144}
1145
1146static int nfs4_reset_session(struct nfs_client *clp)
1147{
1148 int status;
1149
1150 status = nfs4_proc_destroy_session(clp->cl_session);
1151 if (status && status != -NFS4ERR_BADSESSION &&
1152 status != -NFS4ERR_DEADSESSION) {
1153 nfs4_session_recovery_handle_error(clp, status);
1154 goto out;
1155 }
1156
1157 memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
1158 status = nfs4_proc_create_session(clp, 1);
1159 if (status)
1160 nfs4_session_recovery_handle_error(clp, status);
1161 /* fall through*/
1162out:
1163 /* Wake up the next rpc task even on error */
1164 rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq);
1165 return status;
1166}
1167
1168static int nfs4_initialize_session(struct nfs_client *clp)
1169{
1170 int status;
1171
1172 status = nfs4_proc_create_session(clp, 0);
1173 if (!status) {
1174 nfs_mark_client_ready(clp, NFS_CS_READY);
1175 } else if (status == -NFS4ERR_STALE_CLIENTID) {
1176 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1177 set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
1178 } else {
1179 nfs_mark_client_ready(clp, status);
1180 }
1181 return status;
1182}
1183#else /* CONFIG_NFS_V4_1 */
1184static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
1185static int nfs4_initialize_session(struct nfs_client *clp) { return 0; }
1186#endif /* CONFIG_NFS_V4_1 */
1187
1188/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
1189 * on EXCHANGE_ID for v4.1
1190 */
1191static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
1192{
1193 if (nfs4_has_session(clp)) {
1194 switch (status) {
1195 case -NFS4ERR_DELAY:
1196 case -NFS4ERR_CLID_INUSE:
1197 case -EAGAIN:
1198 break;
1199
1200 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
1201 * in nfs4_exchange_id */
1202 default:
1203 return;
1204 }
1205 }
1206 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1207}
1208
1114static void nfs4_state_manager(struct nfs_client *clp) 1209static void nfs4_state_manager(struct nfs_client *clp)
1115{ 1210{
1116 int status = 0; 1211 int status = 0;
@@ -1121,9 +1216,12 @@ static void nfs4_state_manager(struct nfs_client *clp)
1121 /* We're going to have to re-establish a clientid */ 1216 /* We're going to have to re-establish a clientid */
1122 status = nfs4_reclaim_lease(clp); 1217 status = nfs4_reclaim_lease(clp);
1123 if (status) { 1218 if (status) {
1124 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); 1219 nfs4_set_lease_expired(clp, status);
1125 if (status == -EAGAIN) 1220 if (status == -EAGAIN)
1126 continue; 1221 continue;
1222 if (clp->cl_cons_state ==
1223 NFS_CS_SESSION_INITING)
1224 nfs_mark_client_ready(clp, status);
1127 goto out_error; 1225 goto out_error;
1128 } 1226 }
1129 clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); 1227 clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
@@ -1134,25 +1232,44 @@ static void nfs4_state_manager(struct nfs_client *clp)
1134 if (status != 0) 1232 if (status != 0)
1135 continue; 1233 continue;
1136 } 1234 }
1137 1235 /* Initialize or reset the session */
1236 if (nfs4_has_session(clp) &&
1237 test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) {
1238 if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
1239 status = nfs4_initialize_session(clp);
1240 else
1241 status = nfs4_reset_session(clp);
1242 if (status) {
1243 if (status == -NFS4ERR_STALE_CLIENTID)
1244 continue;
1245 goto out_error;
1246 }
1247 }
1138 /* First recover reboot state... */ 1248 /* First recover reboot state... */
1139 if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { 1249 if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
1140 status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); 1250 status = nfs4_do_reclaim(clp,
1251 nfs4_reboot_recovery_ops[clp->cl_minorversion]);
1141 if (status == -NFS4ERR_STALE_CLIENTID) 1252 if (status == -NFS4ERR_STALE_CLIENTID)
1142 continue; 1253 continue;
1254 if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state))
1255 continue;
1143 nfs4_state_end_reclaim_reboot(clp); 1256 nfs4_state_end_reclaim_reboot(clp);
1144 continue; 1257 continue;
1145 } 1258 }
1146 1259
1147 /* Now recover expired state... */ 1260 /* Now recover expired state... */
1148 if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { 1261 if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
1149 status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); 1262 status = nfs4_do_reclaim(clp,
1263 nfs4_nograce_recovery_ops[clp->cl_minorversion]);
1150 if (status < 0) { 1264 if (status < 0) {
1151 set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); 1265 set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
1152 if (status == -NFS4ERR_STALE_CLIENTID) 1266 if (status == -NFS4ERR_STALE_CLIENTID)
1153 continue; 1267 continue;
1154 if (status == -NFS4ERR_EXPIRED) 1268 if (status == -NFS4ERR_EXPIRED)
1155 continue; 1269 continue;
1270 if (test_bit(NFS4CLNT_SESSION_SETUP,
1271 &clp->cl_state))
1272 continue;
1156 goto out_error; 1273 goto out_error;
1157 } else 1274 } else
1158 nfs4_state_end_reclaim_nograce(clp); 1275 nfs4_state_end_reclaim_nograce(clp);