diff options
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r-- | fs/nfs/nfs4state.c | 153 |
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 | ||
61 | static LIST_HEAD(nfs4_clientid_list); | 61 | static LIST_HEAD(nfs4_clientid_list); |
62 | 62 | ||
63 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int 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 | ||
80 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | 80 | struct 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 | ||
117 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 117 | #if defined(CONFIG_NFS_V4_1) |
118 | |||
119 | struct 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 | ||
127 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 129 | #endif /* CONFIG_NFS_V4_1 */ |
130 | |||
131 | struct 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 | ||
739 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | 743 | void 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: | |||
1075 | static int nfs4_check_lease(struct nfs_client *clp) | 1089 | static 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); |
1091 | out: | 1109 | out: |
1092 | nfs4_recovery_handle_error(clp, status); | 1110 | nfs4_recovery_handle_error(clp, status); |
@@ -1096,21 +1114,98 @@ out: | |||
1096 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1114 | static 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 | ||
1137 | static 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 | |||
1146 | static 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*/ | ||
1162 | out: | ||
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 | |||
1168 | static 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 */ | ||
1184 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | ||
1185 | static 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 | */ | ||
1191 | static 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 | |||
1114 | static void nfs4_state_manager(struct nfs_client *clp) | 1209 | static 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); |