windows-vnovol-20080911
authorJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 11 Sep 2008 18:24:38 +0000 (18:24 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 11 Sep 2008 18:24:38 +0000 (18:24 +0000)
LICENSE MIT

Modify MSG_SERVER_REPORTS_VNOVOL to mention that the volume may
have been moved or deleted.

In cm_Analyze(), do not call cm_ForceUpdateVolume() or force a retry
when processing CM_ERROR_NOSUCHVOLUME.  This CM error value is the
result of a VNOVOL already being processed which would have forced
the update.

When a VMOVED or VNOVOL error is received, remove the volume id from
the server's volume list.

If cm_ForceUpdateVolume() returns a failure, do not retry if a
VMOVED or VNOVOL error was received.

Make sure that if a cm_serverRef_t object is marked srv_deleted
that its references not be used.

Now that cm_ForceUpdateVolume() is being called only when processing
VMOVED and VNOVOL errors, permit it to call cm_UpdateVolumeLocation()
immediately.

Refactor cm_CheckOfflineVolume() to reduce code duplication.

src/WINNT/afsd/afsd_eventmessages.mc
src/WINNT/afsd/cm_conn.c
src/WINNT/afsd/cm_volume.c
src/WINNT/afsd/cm_volume.h

index 2cab32c..f01059d 100644 (file)
@@ -114,7 +114,7 @@ Severity=Warning
 Facility=System
 SymbolicName=MSG_SERVER_REPORTS_VNOVOL
 Language=English
-Server %1 reported volume %2 as not attached.
+Server %1 reported volume %2 as not attached (may have been moved or deleted).
 .
 
 MessageId=
index 5d923b4..c919ebb 100644 (file)
@@ -266,14 +266,10 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
      */
     else if (errorCode == CM_ERROR_NOSUCHVOLUME) {
        osi_Log0(afsd_logp, "cm_Analyze passed CM_ERROR_NOSUCHVOLUME.");
-        if (timeLeft > 7) {
-            thrd_Sleep(5000);
-            
-            retry = 1;
-
-            if (fidp != NULL)   /* Not a VLDB call */
-                cm_ForceUpdateVolume(fidp, userp, reqp);
-        }
+        /* 
+         * The VNOVOL or VL_NOENT error has already been translated
+         * to CM_ERROR_NOSUCHVOLUME.  There is nothing for us to do.
+         */
     }
 
     else if (errorCode == CM_ERROR_ALLDOWN) {
@@ -431,7 +427,7 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
         switch ( errorCode ) {
         case VNOVOL:
            msgID = MSG_SERVER_REPORTS_VNOVOL;
-            format = "Server %s reported volume %d as not attached.";
+            format = "Server %s reported volume %d as not attached (does not exist).";
             break;
         case VMOVED:
            msgID = MSG_SERVER_REPORTS_VMOVED;
@@ -482,6 +478,8 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                 /* REDIRECT */
                 if (errorCode == VMOVED || errorCode == VNOVOL) {
                     tsrp->status = srv_deleted;
+                    if (fidp)
+                        cm_RemoveVolumeFromServer(serverp, fidp->volume);
                 } else {
                     tsrp->status = srv_offline;
                 }
@@ -499,8 +497,11 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
         }   
         lock_ReleaseWrite(&cm_serverLock);
 
-        if (fidp && (errorCode == VMOVED || errorCode == VNOVOL))
-            cm_ForceUpdateVolume(fidp, userp, reqp);
+        if (fidp && (errorCode == VMOVED || errorCode == VNOVOL)) {
+            code = cm_ForceUpdateVolume(fidp, userp, reqp);
+            if (code) 
+                timeLeft = 0;   /* prevent a retry on failure */
+        }
 
         if (statep) {
             cm_UpdateVolumeStatus(volp, statep->ID);
@@ -812,11 +813,9 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
         if (tsp) {
             cm_GetServerNoLock(tsp);
             lock_ReleaseRead(&cm_serverLock);
-            if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
+            if ((tsrp->status != srv_deleted) && !(tsp->flags & CM_SERVERFLAG_DOWN)) {
                 allDown = 0;
-                if (tsrp->status == srv_deleted) {
-                    /* skip this entry.  no longer valid. */;
-                } else if (tsrp->status == srv_busy) {
+                if (tsrp->status == srv_busy) {
                     allOffline = 0;
                     someBusy = 1;
                 } else if (tsrp->status == srv_offline) {
@@ -1044,7 +1043,7 @@ long cm_ServerAvailable(struct cm_fid *fidp, struct cm_user *userp)
     lock_ObtainRead(&cm_serverLock);
     for (tsrp = *serverspp; tsrp; tsrp=tsrp->next) {
         tsp = tsrp->server;
-        if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
+        if ((tsrp->status != srv_deleted) && !(tsp->flags & CM_SERVERFLAG_DOWN)) {
            allDown = 0;
             if (tsrp->status == srv_busy) {
                allOffline = 0;
index 4bf0584..5af1993 100644 (file)
@@ -107,7 +107,7 @@ void cm_InitVolume(int newFile, long maxVols)
                     volp->vol[volType].state = vl_unknown;
                     volp->vol[volType].serversp = NULL;
                     if (volp->vol[volType].ID)
-                        cm_VolumeStatusNotification(volp, volp->vol[volType].ID, vl_alldown, volp->vol[volType].state);
+                        cm_VolumeStatusNotification(volp, volp->vol[volType].ID, vl_unknown, volp->vol[volType].state);
                 }
                 volp->cbExpiresRO = 0;
             }
@@ -910,7 +910,12 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
     return code;
 }      
 
-void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
+/* 
+ * Only call this function in response to a VNOVOL or VMOVED error
+ * from a file server.  Do not call it in response to CM_ERROR_NOSUCHVOLUME
+ * as that can lead to recursive calls.
+ */
+long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
 {
     cm_cell_t *cellp;
     cm_volume_t *volp;
@@ -918,11 +923,14 @@ void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
     cm_volume_t *volp2;
 #endif
     afs_uint32  hash;
+    long code;
 
-    if (!fidp) return;
+    if (!fidp) 
+        return CM_ERROR_INVAL;
 
     cellp = cm_FindCellByID(fidp->cell, 0);
-    if (!cellp) return;
+    if (!cellp) 
+        return CM_ERROR_NOSUCHCELL;
 
     /* search for the volume */
     lock_ObtainRead(&cm_volumeLock);
@@ -970,30 +978,21 @@ void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
     lock_ReleaseRead(&cm_volumeLock);
 
     if (!volp)
-        return;
+        return CM_ERROR_NOSUCHVOLUME;
 
     /* update it */
     cm_data.mountRootGen = time(NULL);
     lock_ObtainWrite(&volp->rw);
     volp->flags |= CM_VOLUMEFLAG_RESET;
-#ifdef COMMENT
-    /* Mark the volume to be updated but don't update it now.
-     * This function is called only from within cm_Analyze
-     * when cm_ConnByMServers has failed with all servers down
-     * The problem is that cm_UpdateVolume is going to call
-     * cm_ConnByMServers which may cause a recursive chain
-     * of calls each returning a retry on failure.
-     * Instead, set the flag so the next time the volume is
-     * accessed by Name or ID the UpdateVolume call will
-     * occur.
-     */
+
     code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
-#endif
     lock_ReleaseWrite(&volp->rw);
 
     lock_ObtainRead(&cm_volumeLock);
     cm_PutVolume(volp);
     lock_ReleaseRead(&cm_volumeLock);
+
+    return code;
 }
 
 /* find the appropriate servers from a volume */
@@ -1088,12 +1087,9 @@ void cm_RefreshVolumes(void)
 
 }
 
-
-/* The return code is 0 if the volume is not online and 
- * 1 if the volume is online
- */
-long
-cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
+void
+cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
+                           afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
 {
     cm_conn_t *connp;
     long code;
@@ -1106,140 +1102,101 @@ cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
     char volName[32];
     char offLineMsg[256];
     char motd[256];
-    long online = 0;
+    long alldown, alldeleted;
     cm_serverRef_t *serversp;
 
     Name = volName;
     OfflineMsg = offLineMsg;
     MOTD = motd;
 
-    lock_ObtainWrite(&volp->rw);
-
-    if (volp->flags & CM_VOLUMEFLAG_RESET) {
-        cm_InitReq(&req);
-        code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
-    }
-
-    if (volp->vol[RWVOL].ID != 0 && (!volID || volID == volp->vol[RWVOL].ID) &&
-         volp->vol[RWVOL].serversp) {
-       
-        for (serversp = volp->vol[RWVOL].serversp; serversp; serversp = serversp->next) {
-            if (serversp->status == srv_busy || serversp->status == srv_offline) {
-                serversp->status = srv_not_busy;
-                online = 1;
-            }
-        }
-
-        if (volp->vol[RWVOL].state == vl_busy || volp->vol[RWVOL].state == vl_offline || volp->vol[RWVOL].state == vl_unknown) {
+    if (statep->ID != 0 && (!volID || volID == statep->ID)) {
+        if (!statep->serversp && !(*volumeUpdatedp)) {
             cm_InitReq(&req);
-
-            lock_ReleaseWrite(&volp->rw);
-            do {
-                code = cm_ConnFromVolume(volp, volp->vol[RWVOL].ID, cm_rootUserp, &req, &connp);
-                if (code) 
-                    continue;
-
-                rxconnp = cm_GetRxConn(connp);
-                code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[RWVOL].ID,
-                                             &volStat, &Name, &OfflineMsg, &MOTD);
-                rx_PutConnection(rxconnp);            
-
-            } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
-            code = cm_MapRPCError(code, &req);
-
-            lock_ObtainWrite(&volp->rw);
-            if (code == 0 && volStat.Online) {
-                cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, vl_online);
-                volp->vol[RWVOL].state = vl_online;
-                online = 1;
-            } else if (code == CM_ERROR_NOACCESS) {
-                cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, vl_unknown);
-                volp->vol[RWVOL].state = vl_unknown;
-                online = 1;
-            }
+            code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
+            *volumeUpdatedp = 1;
         }
-    }
 
-    if (volp->vol[ROVOL].ID != 0 && (!volID || volID == volp->vol[ROVOL].ID) &&
-         volp->vol[ROVOL].serversp) {
+        if (statep->serversp) {
+            alldown = 1;
+            alldeleted = 1;
+            for (serversp = statep->serversp; serversp; serversp = serversp->next) {
+                if (serversp->status != srv_deleted) {
+                    alldeleted = 0;
+                    *onlinep = 1;
+                    alldown = 0;
+                }
+                if (serversp->status == srv_busy || serversp->status == srv_offline) 
+                    serversp->status = srv_not_busy;
+            }
 
-        for (serversp = volp->vol[ROVOL].serversp; serversp; serversp = serversp->next) {
-            if (serversp->status == srv_busy || serversp->status == srv_offline) {
-                serversp->status = srv_not_busy;
-                online = 1;
+            if (alldeleted && !(*volumeUpdatedp)) {
+                cm_InitReq(&req);
+                code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
+                *volumeUpdatedp = 1;
             }
-        }
 
-        if (volp->vol[ROVOL].state == vl_busy || volp->vol[ROVOL].state == vl_offline || volp->vol[ROVOL].state == vl_unknown) {
-            cm_InitReq(&req);
+            if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
+                (!alldown && statep->state == vl_alldown)) {
+                cm_InitReq(&req);
 
-            lock_ReleaseWrite(&volp->rw);
-            do {
-                code = cm_ConnFromVolume(volp, volp->vol[ROVOL].ID, cm_rootUserp, &req, &connp);
-                if (code) 
-                    continue;
+                lock_ReleaseWrite(&volp->rw);
+                do {
+                    code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
+                    if (code) 
+                        continue;
 
-                rxconnp = cm_GetRxConn(connp);
-                code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[ROVOL].ID,
-                                              &volStat, &Name, &OfflineMsg, &MOTD);
-                rx_PutConnection(rxconnp);        
+                    rxconnp = cm_GetRxConn(connp);
+                    code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
+                                                 &volStat, &Name, &OfflineMsg, &MOTD);
+                    rx_PutConnection(rxconnp);            
 
-            } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
-            code = cm_MapRPCError(code, &req);
+                } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
+                code = cm_MapRPCError(code, &req);
 
-            lock_ObtainWrite(&volp->rw);
-            if (code == 0 && volStat.Online) {
-                cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, vl_online);
-                volp->vol[ROVOL].state = vl_online;
-                online = 1;
-            } else if (code == CM_ERROR_NOACCESS) {
-                cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, vl_unknown);
-                volp->vol[ROVOL].state = vl_unknown;
-                online = 1;
+                lock_ObtainWrite(&volp->rw);
+                if (code == 0 && volStat.Online) {
+                    cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
+                    statep->state = vl_online;
+                    *onlinep = 1;
+                } else if (code == CM_ERROR_NOACCESS) {
+                    cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
+                    statep->state = vl_unknown;
+                    *onlinep = 1;
+                }
+            } else if (alldown && statep->state != vl_alldown) {
+                cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
+                statep->state = vl_alldown;
             }
+        } else if (statep->state != vl_alldown) {
+            cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
+            statep->state = vl_alldown;
         }
     }
+}
 
-    if (volp->vol[BACKVOL].ID != 0 && (!volID || volID == volp->vol[BACKVOL].ID) &&
-         volp->vol[BACKVOL].serversp) {
-        
-        for (serversp = volp->vol[BACKVOL].serversp; serversp; serversp = serversp->next) {
-            if (serversp->status == srv_busy || serversp->status == srv_offline) {
-                serversp->status = srv_not_busy;
-                online = 1;
-            }
-        }
-
-        if (volp->vol[BACKVOL].state == vl_busy || volp->vol[BACKVOL].state == vl_offline || volp->vol[BACKVOL].state == vl_unknown) {
-            cm_InitReq(&req);
-
-            lock_ReleaseWrite(&volp->rw);
-            do {
-                code = cm_ConnFromVolume(volp, volp->vol[BACKVOL].ID, cm_rootUserp, &req, &connp);
-                if (code) 
-                    continue;
-
-                rxconnp = cm_GetRxConn(connp);
-                code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[BACKVOL].ID,
-                                              &volStat, &Name, &OfflineMsg, &MOTD);
-                rx_PutConnection(rxconnp);        
+/* The return code is 0 if the volume is not online and 
+ * 1 if the volume is online
+ */
+long
+cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
+{
+    long code;
+    cm_req_t req;
+    afs_uint32 online = 0;
+    afs_uint32 volumeUpdated = 0;
 
-            } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
-            code = cm_MapRPCError(code, &req);
+    lock_ObtainWrite(&volp->rw);
 
-            lock_ObtainWrite(&volp->rw);
-            if (code == 0 && volStat.Online) {
-                cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, vl_online);
-                volp->vol[BACKVOL].state = vl_online;
-                online = 1;
-            } else if (code == CM_ERROR_NOACCESS) {
-                cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, vl_unknown);
-                volp->vol[BACKVOL].state = vl_unknown;
-                online = 1;
-            }
-        }
+    if (volp->flags & CM_VOLUMEFLAG_RESET) {
+        cm_InitReq(&req);
+        code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
+        volumeUpdated = 1;
     }
 
+    cm_CheckOfflineVolumeState(volp, &volp->vol[RWVOL], volID, &online, &volumeUpdated);
+    cm_CheckOfflineVolumeState(volp, &volp->vol[ROVOL], volID, &online, &volumeUpdated);
+    cm_CheckOfflineVolumeState(volp, &volp->vol[BACKVOL], volID, &online, &volumeUpdated);
+
     lock_ReleaseWrite(&volp->rw);
     return online;
 }
index cc4f0ba..9a27639 100644 (file)
@@ -89,7 +89,7 @@ extern void cm_PutVolume(cm_volume_t *volp);
 
 extern long cm_GetROVolumeID(cm_volume_t *volp);
 
-extern void cm_ForceUpdateVolume(struct cm_fid *fidp, cm_user_t *userp,
+extern long cm_ForceUpdateVolume(struct cm_fid *fidp, cm_user_t *userp,
        cm_req_t *reqp);
 
 extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume);
@@ -124,6 +124,10 @@ extern void cm_CheckOfflineVolumes(void);
 
 extern long cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID);
 
+extern void cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, 
+                                       afs_uint32 volID,  afs_uint32 *onlinep, 
+                                       afs_uint32 *volumeUpdatedp);
+
 extern void cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
 
 extern void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus oldState, enum volstatus newState);