Windows: avoid vldb lookup race with network stack
[openafs.git] / src / WINNT / afsd / cm_volume.c
index a63bd8f..c85107b 100644 (file)
@@ -20,6 +20,7 @@
 #include <strsafe.h>
 #include <malloc.h>
 #include "afsd.h"
+#include "cm_getaddrs.h"
 #include <osi.h>
 #include <rx/rx.h>
 
@@ -32,21 +33,48 @@ cm_ValidateVolume(void)
     afs_uint32 count;
 
     for (volp = cm_data.allVolumesp, count = 0; volp; volp=volp->allNextp, count++) {
+
+       if ( volp < (cm_volume_t *)cm_data.volumeBaseAddress ||
+            volp >= (cm_volume_t *)cm_data.cellBaseAddress) {
+           afsi_log("cm_ValidateVolume failure: out of range cm_volume_t pointers");
+           fprintf(stderr, "cm_ValidateVolume failure: out of range cm_volume_t pointers\n");
+           return -10;
+       }
+
         if ( volp->magic != CM_VOLUME_MAGIC ) {
             afsi_log("cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC");
             fprintf(stderr, "cm_ValidateVolume failure: volp->magic != CM_VOLUME_MAGIC\n");
             return -1;
         }
+
+       if ( volp->cellp < (cm_cell_t *)cm_data.cellBaseAddress ||
+            volp->cellp >= (cm_cell_t *)cm_data.aclBaseAddress) {
+           afsi_log("cm_ValidateVolume failure: out of range cm_cell_t pointers");
+           fprintf(stderr, "cm_ValidateVolume failure: out of range cm_cell_t pointers\n");
+           return -11;
+       }
+
         if ( volp->cellp && volp->cellp->magic != CM_CELL_MAGIC ) {
             afsi_log("cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC");
             fprintf(stderr, "cm_ValidateVolume failure: volp->cellp->magic != CM_CELL_MAGIC\n");
             return -2;
         }
-        if ( volp->allNextp && volp->allNextp->magic != CM_VOLUME_MAGIC ) {
-            afsi_log("cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC");
-            fprintf(stderr, "cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC\n");
-            return -3;
-        }
+
+       if ( volp->allNextp) {
+           if ( volp->allNextp < (cm_volume_t *)cm_data.volumeBaseAddress ||
+                volp->allNextp >= (cm_volume_t *)cm_data.cellBaseAddress) {
+               afsi_log("cm_ValidateVolume failure: out of range cm_volume_t pointers");
+               fprintf(stderr, "cm_ValidateVolume failure: out of range cm_volume_t pointers\n");
+               return -12;
+           }
+
+           if ( volp->allNextp->magic != CM_VOLUME_MAGIC ) {
+               afsi_log("cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC");
+               fprintf(stderr, "cm_ValidateVolume failure: volp->allNextp->magic != CM_VOLUME_MAGIC\n");
+               return -3;
+           }
+       }
+
         if ( count != 0 && volp == cm_data.allVolumesp ||
              count > cm_data.maxVolumes ) {
             afsi_log("cm_ValidateVolume failure: cm_data.allVolumep loop detected");
@@ -78,9 +106,14 @@ cm_ShutdownVolume(void)
         volp->cbExpiresRO = 0;
         volp->cbIssuedRO = 0;
         volp->cbServerpRO = NULL;
+        volp->volumeSizeRO = 0;
+        _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RO_SIZE_VALID);
+
         lock_FinalizeRWLock(&volp->rw);
     }
 
+    cm_getaddrsShutdown();
+
     return 0;
 }
 
@@ -119,9 +152,14 @@ void cm_InitVolume(int newFile, long maxVols)
                 volp->cbExpiresRO = 0;
                 volp->cbIssuedRO = 0;
                 volp->cbServerpRO = NULL;
+                volp->volumeSizeRO = 0;
+                _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_RO_SIZE_VALID);
             }
         }
-        osi_EndOnce(&once);
+
+       cm_getaddrsInit();
+
+       osi_EndOnce(&once);
     }
 }
 
@@ -203,7 +241,7 @@ cm_GetEntryByName( struct cm_cell *cellp, const char *name,
             *methodp = 0;
         }
         rx_PutConnection(rxconnp);
-    } while (cm_Analyze(connp, userp, reqp, NULL, cellp, 0, NULL, cellp->vlServersp, NULL, code));
+    } while (cm_Analyze(connp, userp, reqp, NULL, cellp, 0, NULL, NULL, &cellp->vlServersp, NULL, code));
     code = cm_MapVLRPCError(code, reqp);
     if ( code )
         osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x",
@@ -236,10 +274,8 @@ cm_GetEntryByID( struct cm_cell *cellp, afs_uint32 id,
 long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
                     cm_volume_t *volp)
 {
-    struct rx_connection *rxconnp;
-    cm_conn_t *connp;
     int i;
-    afs_uint32 j, k;
+    afs_uint32 j;
     cm_serverRef_t *tsrp;
     cm_server_t *tsp;
     struct sockaddr_in tsockAddr;
@@ -316,8 +352,14 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         /* Do not hold the volume lock across the RPC calls */
         lock_ReleaseWrite(&volp->rw);
 
-        if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID)
-             cm_UpdateCell(cellp, 0);
+       if (cellp->flags & CM_CELLFLAG_VLSERVER_INVALID) {
+           cellp = cm_UpdateCell(cellp, 0);
+           if (cellp == NULL) {
+               lock_ObtainWrite(&volp->rw);
+               _InterlockedAnd(&volp->flags, ~CM_VOLUMEFLAG_UPDATING_VL);
+               return(CM_ERROR_NOSUCHCELL);
+           }
+       }
 
         /* now we have volume structure locked and held; make RPC to fill it */
         code = cm_GetEntryByName(cellp, volp->namep, &vldbEntry, &nvldbEntry,
@@ -369,6 +411,7 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         afs_int32 roID;
         afs_int32 bkID;
         afs_int32 serverNumber[NMAXNSERVERS];
+       afs_int32 serverUnique[NMAXNSERVERS];
         afs_int32 serverFlags[NMAXNSERVERS];
         afsUUID   serverUUID[NMAXNSERVERS];
         afs_int32 rwServers_alldown = 1;
@@ -388,6 +431,7 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         }
 
         memset(serverUUID, 0, sizeof(serverUUID));
+       memset(serverUnique, 0, sizeof(serverUnique));
 
         switch ( method ) {
         case 0:
@@ -428,46 +472,14 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
                     serverNumber[j] = uvldbEntry.serverNumber[i].time_low;
                     j++;
                 } else {
-                    afs_uint32 * addrp, nentries, code, unique;
-                    bulkaddrs  addrs;
-                    ListAddrByAttributes attrs;
-                    afsUUID uuid;
-
-                    memset(&attrs, 0, sizeof(attrs));
-                    attrs.Mask = VLADDR_UUID;
-                    attrs.uuid = uvldbEntry.serverNumber[i];
-                    memset(&uuid, 0, sizeof(uuid));
-                    memset(&addrs, 0, sizeof(addrs));
-
-                    do {
-                        code = cm_ConnByMServers(cellp->vlServersp, FALSE, userp, reqp, &connp);
-                        if (code)
-                            continue;
-
-                        rxconnp = cm_GetRxConn(connp);
-                        code = VL_GetAddrsU(rxconnp, &attrs, &uuid, &unique, &nentries, &addrs);
-                        rx_PutConnection(rxconnp);
-                    } while (cm_Analyze(connp, userp, reqp, NULL, cellp, 0, NULL, cellp->vlServersp, NULL, code));
-
-                    if ( code ) {
-                        code = cm_MapVLRPCError(code, reqp);
-                        osi_Log2(afsd_logp, "CALL VL_GetAddrsU serverNumber %u FAILURE, code 0x%x",
-                                 i, code);
-                        continue;
-                    }
-                    osi_Log1(afsd_logp, "CALL VL_GetAddrsU serverNumber %u SUCCESS", i);
-
-                    addrp = addrs.bulkaddrs_val;
-                    for (k = 0; k < nentries && j < NMAXNSERVERS; j++, k++) {
-                        serverFlags[j] = uvldbEntry.serverFlags[i];
-                        serverNumber[j] = addrp[k];
-                        serverUUID[j] = uuid;
-                    }
-
-                    xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
-
-                    if (nentries == 0)
-                        code = CM_ERROR_INVAL;
+                   code = cm_GetAddrsU(cellp, userp, reqp,
+                                       &uvldbEntry.serverNumber[i],
+                                       uvldbEntry.serverUnique[i],
+                                       uvldbEntry.serverFlags[i], &j,
+                                       serverFlags, serverNumber,
+                                       serverUUID, serverUnique);
+                   if (code == CM_ERROR_RETRY)
+                       continue;
                 }
             }
             nServers = j;                                      /* update the server count */
@@ -701,7 +713,9 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         volp->vol[BACKVOL].state = bkNewstate;
     }
 
-    volp->lastUpdateTime = time(NULL);
+    if (code == 0 || (volp->flags & CM_VOLUMEFLAG_NOEXIST))
+       volp->lastUpdateTime = time(NULL);
+
     if (isMixed)
         _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_MIXED);
     else
@@ -763,6 +777,24 @@ cm_volume_t *cm_GetVolumeByFID(cm_fid_t *fidp)
     return volp;
 }
 
+cm_volume_t *cm_FindVolumeByFID(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
+{
+    cm_volume_t *volp = NULL;
+    cm_cell_t   *cellp;
+    long         code;
+
+    cellp = cm_FindCellByID(fidp->cell, CM_FLAG_NOPROBE);
+    if (!cellp) {
+       return NULL;
+    }
+
+    code = cm_FindVolumeByID(cellp, fidp->volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &volp);
+    if (code)
+       return NULL;
+
+    return volp;
+}
+
 long cm_FindVolumeByID(cm_cell_t *cellp, afs_uint32 volumeID, cm_user_t *userp,
                       cm_req_t *reqp, afs_uint32 flags, cm_volume_t **outVolpp)
 {
@@ -1285,6 +1317,7 @@ cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32
     cm_req_t req;
     struct rx_connection * rxconnp;
     char volName[32];
+    afs_uint32 volType;
     char offLineMsg[256];
     char motd[256];
     long alldown, alldeleted;
@@ -1296,6 +1329,8 @@ cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32
     OfflineMsg = offLineMsg;
     MOTD = motd;
 
+    volType = cm_VolumeType(volp, volID);
+
     if (statep->ID != 0 && (!volID || volID == statep->ID)) {
         /* create fid for volume root so that VNOVOL and VMOVED errors can be processed */
         cm_SetFid(&vfid, volp->cellp->cellID, statep->ID, 1, 1);
@@ -1338,28 +1373,27 @@ cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32
 
                 code = cm_GetSCache(&vfid, NULL, &vscp, cm_rootUserp, &req);
                 if (code = 0) {
-                    lock_ObtainWrite(&vscp->rw);
-                    code = cm_SyncOp(vscp, NULL, cm_rootUserp, &req, PRSFS_READ,
-                                     CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-                    lock_ReleaseWrite(&vscp->rw);
-                    if (code == 0) {
-                        do {
-                            code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
-                            if (code)
-                                continue;
-
-                            rxconnp = cm_GetRxConn(connp);
-                            code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
-                                                         &volStat, &Name, &OfflineMsg, &MOTD);
-                            rx_PutConnection(rxconnp);
-                        } while (cm_Analyze(connp, cm_rootUserp, &req, &vfid, NULL, 0, NULL, NULL, NULL, code));
-                        code = cm_MapRPCError(code, &req);
-                    }
-
-                    lock_ObtainWrite(&vscp->rw);
-                    cm_SyncOpDone(vscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-                    lock_ReleaseWrite(&vscp->rw);
-                    cm_ReleaseSCache(vscp);
+                   do {
+                       code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
+                       if (code)
+                          continue;
+
+                       rxconnp = cm_GetRxConn(connp);
+                       code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
+                                                    &volStat, &Name, &OfflineMsg, &MOTD);
+                       rx_PutConnection(rxconnp);
+                   } while (cm_Analyze(connp, cm_rootUserp, &req, &vfid, NULL, 0, NULL, NULL, NULL, NULL, code));
+                   code = cm_MapRPCError(code, &req);
+
+                   if (code == 0 && volType == ROVOL)
+                   {
+                       lock_ObtainWrite(&volp->rw);
+                       volp->volumeSizeRO = volStat.BlocksInUse * 1024;
+                       _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_SIZE_VALID);
+                       lock_ReleaseWrite(&volp->rw);
+                   }
+
+                   cm_ReleaseSCache(vscp);
                 }
                 lock_ObtainWrite(&volp->rw);
                 if (code == 0 && volStat.Online) {