return serversleft;
}
+/*------------------------------------------------------------------------
+ * afs_ClearStatus
+ *
+ * Description:
+ * Analyze the outcome of an RPC operation, taking whatever support
+ * actions are necessary.
+ *
+ * Arguments:
+ * afid : The FID of the file involved in the action. This argument
+ * may be null if none was involved.
+ * op : which RPC we are analyzing.
+ * avp : A pointer to the struct volume, if we already have one.
+ *
+ * Returns:
+ * Non-zero value if the related RPC operation can be retried,
+ * zero otherwise.
+ *
+ * Environment:
+ * This routine is called when we got a network error,
+ * and discards state if the operation was a data-mutating
+ * operation.
+ *------------------------------------------------------------------------*/
+static int
+afs_ClearStatus(struct VenusFid *afid, int op, struct volume *avp)
+{
+ struct volume *tvp = NULL;
+
+ /* if it's not a write op, we have nothing to veto and shouldn't clear. */
+ if (!AFS_STATS_FS_RPCIDXES_ISWRITE(op)) {
+ return 1;
+ }
+
+ if (avp)
+ tvp = avp;
+ else if (afid)
+ tvp = afs_FindVolume(afid, READ_LOCK);
+
+ /* don't assume just discarding will fix if no cached volume */
+ if (tvp) {
+ struct vcache *tvc;
+ ObtainReadLock(&afs_xvcache);
+ if ((tvc = afs_FindVCache(afid, 0, 0))) {
+ ReleaseReadLock(&afs_xvcache);
+ tvc->f.states &= ~(CStatd | CUnique);
+ afs_PutVCache(tvc);
+ } else {
+ ReleaseReadLock(&afs_xvcache);
+ }
+ }
+ if (!avp)
+ afs_PutVolume(tvp, READ_LOCK);
+
+ /* not retriable: we may have raced ourselves */
+ return 0;
+}
/*------------------------------------------------------------------------
* EXPORTED afs_Analyze
VSleep(hm_retry_int);
afs_CheckServers(1, cellp);
+ /* clear the black listed servers on this request. */
+ memset(areq->skipserver, 0, sizeof(areq->skipserver));
if (vp_vhm) {
tvp = afs_FindVolume(afid, READ_LOCK);
else {
if (acode == RX_MSGSIZE)
shouldRetry = 1;
- else
+ else {
areq->networkError = 1;
+ /* do not promote to shouldRetry if not already */
+ if (afs_ClearStatus(afid, op, NULL) == 0)
+ shouldRetry = 0;
+ }
}
}
return shouldRetry;
serversleft = afs_BlackListOnce(areq, afid, tsp);
if (afid)
tvp = afs_FindVolume(afid, READ_LOCK);
- if (!afid || !tvp || (tvp->states & VRO))
- areq->idleError++;
if ((serversleft == 0) && tvp &&
((tvp->states & VRO) || (tvp->states & VBackup))) {
shouldRetry = 0;
} else {
shouldRetry = 1;
}
+ if (!afid || !tvp || (tvp->states & VRO))
+ areq->idleError++;
+ else if (afs_ClearStatus(afid, op, tvp) == 0)
+ shouldRetry = 0;
+
if (tvp)
afs_PutVolume(tvp, READ_LOCK);
/* By doing this, we avoid ever marking a server down
*/
goto out;
}
- afs_ServerDown(sa);
+ afs_ServerDown(sa, acode);
ForceNewConnections(sa); /**multi homed clients lock:afs_xsrvAddr? */
if (aerrP)
(aerrP->err_Server)++;
}
/* check for ubik errors; treat them like crashed servers */
else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U + 255) {
- afs_ServerDown(sa);
+ afs_ServerDown(sa, acode);
if (aerrP)
(aerrP->err_Server)++;
shouldRetry = 1; /* retryable (maybe one is working) */