afs: discard cached state when we are unsure of validity
authorDerrick Brashear <shadow@dementix.org>
Wed, 4 Jan 2012 20:04:41 +0000 (15:04 -0500)
committerDerrick Brashear <shadow@dementix.org>
Sat, 7 Jan 2012 14:18:35 +0000 (06:18 -0800)
in the event we got a network error, we don't know if the server
completed (or will complete) our operation. we can assume nothing.
a more complicated version of this could attempt to verify that the
state is what we expect it to be, but in extended callbacks universe
this is potentially easier to solve anyway. for now, return the
error to the caller, and mark the vcache unstat'd.

Change-Id: Iafb67f24b89d78b8236660d047da12fce1dd6061
Reviewed-on: http://gerrit.openafs.org/6510
Reviewed-by: Derrick Brashear <shadow@dementix.org>
Tested-by: Derrick Brashear <shadow@dementix.org>

src/afs/afs_analyze.c
src/afs/afs_stats.h

index 47fdff3..0023d5b 100644 (file)
@@ -271,6 +271,61 @@ afs_BlackListOnce(struct vrequest *areq, struct VenusFid *afid,
     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
@@ -463,8 +518,12 @@ afs_Analyze(struct afs_conn *aconn, struct rx_connection *rxconn,
            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;
@@ -514,14 +573,17 @@ afs_Analyze(struct afs_conn *aconn, struct rx_connection *rxconn,
            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
index 60f2e93..37b9aad 100644 (file)
@@ -869,6 +869,8 @@ struct afs_stats_CMPerf {
 
 #define AFS_STATS_NUM_FS_RPC_OPS               29
 
+#define AFS_STATS_FS_RPCIDXES_ISWRITE(X)        (((X > AFS_STATS_FS_RPCIDX_FETCHSTATUS) && (X < AFS_STATS_FS_RPCIDX_GETSTATISTICS)) || (X == AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS))
+
 #define AFS_STATS_FS_XFERIDX_FETCHDATA          0
 #define AFS_STATS_FS_XFERIDX_STOREDATA          1