windows-volume-recycling-race-condition-20080731
[openafs.git] / src / WINNT / afsd / cm_volume.c
index 8563783..fbe2b55 100644 (file)
@@ -102,6 +102,7 @@ void cm_InitVolume(int newFile, long maxVols)
 
                 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock");
                 volp->flags |= CM_VOLUMEFLAG_RESET;
+                volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
                 for (volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
                     volp->vol[volType].state = vl_unknown;
                     volp->vol[volType].serversp = NULL;
@@ -184,12 +185,6 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
 #endif
     afs_uint32 volType;
 
-    /* clear out old bindings */
-    for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
-        if (volp->vol[volType].serversp)
-            cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
-    }
-
 #ifdef AFS_FREELANCE_CLIENT
     if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && volp->vol[RWVOL].ID == AFS_FAKE_ROOT_VOL_ID ) 
     {
@@ -203,11 +198,24 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
 #endif
     {
         while (volp->flags & CM_VOLUMEFLAG_UPDATING_VL) {
+            osi_Log3(afsd_logp, "cm_UpdateVolumeLocation sleeping name %s:%s flags 0x%x", 
+                     volp->cellp->name, volp->namep, volp->flags);
             osi_SleepW((LONG_PTR) &volp->flags, &volp->rw);
             lock_ObtainWrite(&volp->rw);
-
-            if (!(volp->flags & CM_VOLUMEFLAG_RESET))
+            osi_Log3(afsd_logp, "cm_UpdateVolumeLocation awake name %s:%s flags 0x%x", 
+                     volp->cellp->name, volp->namep, volp->flags);
+            if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
+                osi_Log3(afsd_logp, "cm_UpdateVolumeLocation nothing to do, waking others name %s:%s flags 0x%x", 
+                         volp->cellp->name, volp->namep, volp->flags);
+                osi_Wakeup((LONG_PTR) &volp->flags);
                 return 0;
+            }
+        }
+
+        /* clear out old bindings */
+        for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
+            if (volp->vol[volType].serversp)
+                cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
         }
 
         volp->flags |= CM_VOLUMEFLAG_UPDATING_VL;
@@ -219,22 +227,27 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         /* now we have volume structure locked and held; make RPC to fill it */
        osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", volp->cellp->name, volp->namep);
         do {
+            struct rx_connection * rxconnp;
+
             code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
             if (code) 
                 continue;
+
+            rxconnp = cm_GetRxConn(connp);
 #ifdef MULTIHOMED
-            code = VL_GetEntryByNameU(connp->callp, volp->namep, &uvldbEntry);
+            code = VL_GetEntryByNameU(rxconnp, volp->namep, &uvldbEntry);
             method = 2;
             if ( code == RXGEN_OPCODE ) 
 #endif
             {
-                code = VL_GetEntryByNameN(connp->callp, volp->namep, &nvldbEntry);
+                code = VL_GetEntryByNameN(rxconnp, volp->namep, &nvldbEntry);
                 method = 1;
             }
             if ( code == RXGEN_OPCODE ) {
-                code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
+                code = VL_GetEntryByNameO(rxconnp, volp->namep, &vldbEntry);
                 method = 0;
             }
+            rx_PutConnection(rxconnp);
         } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
         code = cm_MapVLRPCError(code, reqp);
        if ( code )
@@ -259,22 +272,27 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
        osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", volp->cellp->name, 
                  osi_LogSaveString(afsd_logp,name));
         do {
+            struct rx_connection * rxconnp;
+
             code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
             if (code) 
                 continue;
+
+            rxconnp = cm_GetRxConn(connp);
 #ifdef MULTIHOMED
-            code = VL_GetEntryByNameU(connp->callp, name, &uvldbEntry);
+            code = VL_GetEntryByNameU(connp->rxconnp, name, &uvldbEntry);
             method = 2;
             if ( code == RXGEN_OPCODE ) 
 #endif
             {
-                code = VL_GetEntryByNameN(connp->callp, name, &nvldbEntry);
+                code = VL_GetEntryByNameN(connp->rxconnp, name, &nvldbEntry);
                 method = 1;
             }
             if ( code == RXGEN_OPCODE ) {
-                code = VL_GetEntryByNameO(connp->callp, name, &vldbEntry);
+                code = VL_GetEntryByNameO(connp->rxconnp, name, &vldbEntry);
                 method = 0;
             }
+            rx_PutConnection(rxconnp);
         } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
         code = cm_MapVLRPCError(code, reqp);
        if ( code )
@@ -356,11 +374,15 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
                     memset((char *)&addrs, 0, sizeof(addrs));
 
                     do {
+                        struct rx_connection *rxconnp;
+
                         code = cm_ConnByMServers(cellp->vlServersp, userp, reqp, &connp);
                         if (code) 
                             continue;
                    
-                        code = VL_GetAddrsU(connp->callp, &attrs, &uuid, &unique, &nentries, &addrs);
+                        rxconnp = cm_GetRxConn(connp);
+                        code = VL_GetAddrsU(rxconnp, &attrs, &uuid, &unique, &nentries, &addrs);
+                        rx_PutConnection(rxconnp);
                     } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
 
                     if ( code ) {
@@ -459,10 +481,13 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
             tempAddr = htonl(serverNumber[i]);
             tsockAddr.sin_addr.s_addr = tempAddr;
             tsp = cm_FindServer(&tsockAddr, CM_SERVER_FILE);
-            if (!tsp)
-                tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE,
-                                    cellp, 0);
-
+            if (!tsp) {
+                /* cm_NewServer will probe the server which in turn will
+                 * update the state on the volume group object */
+                lock_ReleaseWrite(&volp->rw);
+                tsp = cm_NewServer(&tsockAddr, CM_SERVER_FILE, cellp, 0);
+                lock_ObtainWrite(&volp->rw);
+            }
             /* if this server was created by fs setserverprefs */
             if ( !tsp->cellp ) 
                 tsp->cellp = cellp;
@@ -576,6 +601,8 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         volp->flags &= ~CM_VOLUMEFLAG_RESET;
 
     volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
+    osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x", 
+             volp->cellp->name, volp->namep, volp->flags, code);
     osi_Wakeup((LONG_PTR) &volp->flags);
 
     return code;
@@ -768,6 +795,13 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
         afs_uint32 volType;
         /* otherwise, get from VLDB */
 
+        /* 
+         * Change to a write lock so that we have exclusive use of
+         * the first cm_volume_t with a refCount of 0 so that we 
+         * have time to increment it.
+         */
+        lock_ConvertRToW(&cm_volumeLock);
+
        if ( cm_data.currentVolumes >= cm_data.maxVolumes ) {
 #ifdef RECYCLE_FROM_ALL_VOLUMES_LIST
            for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
@@ -790,7 +824,8 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
            if (!volp)
                osi_panic("Exceeded Max Volumes", __FILE__, __LINE__);
 
-            lock_ReleaseRead(&cm_volumeLock);
+            InterlockedIncrement(&volp->refCount);
+            lock_ReleaseWrite(&cm_volumeLock);
             lock_ObtainWrite(&volp->rw);
             lock_ObtainWrite(&cm_volumeLock);
 
@@ -817,14 +852,14 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep,
            volp->allNextp = cm_data.allVolumesp;
            cm_data.allVolumesp = volp;
            lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock");
-            lock_ReleaseRead(&cm_volumeLock);
+            lock_ReleaseWrite(&cm_volumeLock);
             lock_ObtainWrite(&volp->rw);
             lock_ObtainWrite(&cm_volumeLock);
+            volp->refCount = 1;        /* starts off held */
         }
        volp->cellp = cellp;
        strncpy(volp->namep, name, VL_MAXNAMELEN);
        volp->namep[VL_MAXNAMELEN-1] = '\0';
-        volp->refCount = 1;    /* starts off held */
        volp->flags = CM_VOLUMEFLAG_RESET;
     
         for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
@@ -1065,7 +1100,7 @@ cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
     char *OfflineMsg;
     char *MOTD;
     cm_req_t req;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     char volName[32];
     char offLineMsg[256];
     char motd[256];
@@ -1102,10 +1137,10 @@ cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
                 if (code) 
                     continue;
 
-                callp = cm_GetRxConn(connp);
-                code = RXAFS_GetVolumeStatus(callp, volp->vol[RWVOL].ID,
+                rxconnp = cm_GetRxConn(connp);
+                code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[RWVOL].ID,
                                              &volStat, &Name, &OfflineMsg, &MOTD);
-                rx_PutConnection(callp);            
+                rx_PutConnection(rxconnp);            
 
             } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
             code = cm_MapRPCError(code, &req);
@@ -1142,10 +1177,10 @@ cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
                 if (code) 
                     continue;
 
-                callp = cm_GetRxConn(connp);
-                code = RXAFS_GetVolumeStatus(callp, volp->vol[ROVOL].ID,
+                rxconnp = cm_GetRxConn(connp);
+                code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[ROVOL].ID,
                                               &volStat, &Name, &OfflineMsg, &MOTD);
-                rx_PutConnection(callp);        
+                rx_PutConnection(rxconnp);        
 
             } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
             code = cm_MapRPCError(code, &req);
@@ -1182,10 +1217,10 @@ cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
                 if (code) 
                     continue;
 
-                callp = cm_GetRxConn(connp);
-                code = RXAFS_GetVolumeStatus(callp, volp->vol[BACKVOL].ID,
+                rxconnp = cm_GetRxConn(connp);
+                code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[BACKVOL].ID,
                                               &volStat, &Name, &OfflineMsg, &MOTD);
-                rx_PutConnection(callp);        
+                rx_PutConnection(rxconnp);        
 
             } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
             code = cm_MapRPCError(code, &req);