server-list-and-volume-updates-20040730
authorJeffrey Altman <jaltman@mit.edu>
Fri, 30 Jul 2004 21:02:57 +0000 (21:02 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Fri, 30 Jul 2004 21:02:57 +0000 (21:02 +0000)
As discovered previously, the cm_serverRef_t objects were not reference
counted.  This resulted in the objects being freed while they were
still in use.  This patch adds reference counting to the cm_serverRef_t
objects which are locked using the cm_serverLock.

Once the reference counting was fixed it became immediately obvious
that cm_VolumeUpdates could not succeed in altering the state of a
server list from ALLOFFLINE to NOTBUSY. cm_VolumeUpdate calls cm_Analyze
without a fid_t object which was required to obtain the server list for
the affected volume.  Of course, cm_VolumeUpdate has a pointer to the
volume so cm_Analyze was updated to take an optional pointer to a
cm_serverRef_t which avoids the need for the fid_t object.

src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_cell.c
src/WINNT/afsd/cm_conn.c
src/WINNT/afsd/cm_conn.h
src/WINNT/afsd/cm_dcache.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_server.c
src/WINNT/afsd/cm_server.h
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_volume.c

index 48be6ff..b9bcaef 100644 (file)
@@ -814,7 +814,7 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
             code = RXAFS_FetchStatus(connp->callp, &tfid,
                                      &afsStatus, &callback, &volSync);
 
-               } while (cm_Analyze(connp, userp, reqp, &sfid, &volSync,
+               } while (cm_Analyze(connp, userp, reqp, &sfid, &volSync, NULL,
                             &cbr, code));
         code = cm_MapRPCError(code, reqp);
                osi_Log0(afsd_logp, "CALL FetchStatus DONE");
index 8314eef..bc7090f 100644 (file)
@@ -45,12 +45,15 @@ long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep)
                        tsp->cellp = cellp;
        }
        else
-               tsp = cm_NewServer(addrp, CM_SERVER_VLDB, cellp);
+        tsp = cm_NewServer(addrp, CM_SERVER_VLDB, cellp);
 
        /* Insert the vlserver into a sorted list, sorted by server rank */
        tsrp = cm_NewServerRef(tsp);
        cm_InsertServerList(&cellp->vlServersp, tsrp);
-
+    /* drop the allocation reference */
+    lock_ObtainWrite(&cm_serverLock);
+    tsrp->refCount--;
+    lock_ReleaseWrite(&cm_serverLock);
        return 0;
 }
 
index 856f31d..ae68422 100644 (file)
@@ -101,32 +101,23 @@ long cm_GetServerList(struct cm_fid *fidp, struct cm_user *userp,
        struct cm_req *reqp, cm_serverRef_t **serverspp)
 {
        long code;
-        cm_volume_t *volp = NULL;
-        cm_serverRef_t *serversp = NULL;
-        cm_cell_t *cellp = NULL;
+    cm_volume_t *volp = NULL;
+    cm_cell_t *cellp = NULL;
 
-        if (!fidp) {
+    if (!fidp) {
                *serverspp = NULL;
                return 0;
        }
 
        cellp = cm_FindCellByID(fidp->cell);
-        if (!cellp) return CM_ERROR_NOSUCHCELL;
+    if (!cellp) return CM_ERROR_NOSUCHCELL;
 
-        code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, &volp);
-        if (code) return code;
-        
-       if (fidp->volume == volp->rwID)
-               serversp = volp->rwServersp;
-       else if (fidp->volume == volp->roID)
-               serversp = volp->roServersp;
-       else if (fidp->volume == volp->bkID)
-               serversp = volp->bkServersp;
-       else
-               serversp = NULL;
-
-        cm_PutVolume(volp);
-       *serverspp = serversp;
+    code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, &volp);
+    if (code) return code;
+    
+    *serverspp = cm_GetVolServers(volp, fidp->volume);
+
+    cm_PutVolume(volp);
        return 0;
 }
 
@@ -148,13 +139,16 @@ long cm_GetServerList(struct cm_fid *fidp, struct cm_user *userp,
  */
 int
 cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
-       struct cm_fid *fidp,
-       AFSVolSync *volSyncp, cm_callbackRequest_t *cbrp, long errorCode)
+       struct cm_fid *fidp, 
+       AFSVolSync *volSyncp, 
+       cm_serverRef_t * serversp,
+       cm_callbackRequest_t *cbrp, long errorCode)
 {
        cm_server_t *serverp;
-       cm_serverRef_t *serversp, *tsrp;
+       cm_serverRef_t *tsrp;
        cm_ucell_t *ucellp;
-        int retry = 0;
+    int retry = 0;
+    int free_svr_list = 0;
        int dead_session;
         
        osi_Log2(afsd_logp, "cm_Analyze connp 0x%x, code %d",
@@ -167,7 +161,8 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                serverp = connp->serverp;
 
        /* Update callback pointer */
-        if (cbrp && errorCode == 0) cbrp->serverp = connp->serverp;
+    if (cbrp && errorCode == 0) 
+        cbrp->serverp = connp->serverp;
 
        /* If not allowed to retry, don't */
        if (reqp->flags & CM_REQ_NORETRY)
@@ -205,7 +200,10 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                 * the servers are marked as DOWN.  So clear the DOWN
                 * flag and reset the busy state as well.
                 */
-               cm_GetServerList(fidp, userp, reqp, &serversp);
+        if (!serversp) {
+            cm_GetServerList(fidp, userp, reqp, &serversp);
+            free_svr_list = 1;
+        }
         if (serversp) {
             lock_ObtainWrite(&cm_serverLock);
             for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
@@ -214,7 +212,8 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                     tsrp->status = not_busy;
             }
             lock_ReleaseWrite(&cm_serverLock);
-
+            if (free_svr_list)
+                cm_FreeServerList(&serversp);
             retry = 1;
         }
 
@@ -224,20 +223,28 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
 
        /* if all servers are busy, mark them non-busy and start over */
        if (errorCode == CM_ERROR_ALLBUSY) {
-               cm_GetServerList(fidp, userp, reqp, &serversp);
+        if (!serversp) {
+            cm_GetServerList(fidp, userp, reqp, &serversp);
+            free_svr_list = 1;
+        }
                lock_ObtainWrite(&cm_serverLock);
                for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
                        if (tsrp->status == busy)
                                tsrp->status = not_busy;
                }
         lock_ReleaseWrite(&cm_serverLock);
+        if (free_svr_list)
+            cm_FreeServerList(&serversp);
                thrd_Sleep(5000);
                retry = 1;
        }
 
        /* special codes:  VBUSY and VRESTARTING */
        if (errorCode == VBUSY || errorCode == VRESTARTING) {
-               cm_GetServerList(fidp, userp, reqp, &serversp);
+        if (!serversp) {
+            cm_GetServerList(fidp, userp, reqp, &serversp);
+            free_svr_list = 1;
+        }
                lock_ObtainWrite(&cm_serverLock);
                for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
                        if (tsrp->server == serverp
@@ -247,6 +254,8 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                        }
                }
         lock_ReleaseWrite(&cm_serverLock);
+        if (free_svr_list)
+            cm_FreeServerList(&serversp);
                retry = 1;
        }
 
@@ -278,12 +287,16 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
                }
 
                /* Mark server offline for this volume */
-               cm_GetServerList(fidp, userp, reqp, &serversp);
-
+        if (!serversp) {
+            cm_GetServerList(fidp, userp, reqp, &serversp);
+            free_svr_list = 1;
+        }
                for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
                        if (tsrp->server == serverp)
                                tsrp->status = offline;
                }
+        if (free_svr_list)
+            cm_FreeServerList(&serversp);
                retry = 1;
        }
 
@@ -312,10 +325,10 @@ cm_Analyze(cm_conn_t *connp, cm_user_t *userp, cm_req_t *reqp,
        else if (errorCode >= -64 && errorCode < 0) {
                /* mark server as down */
                lock_ObtainMutex(&serverp->mx);
-                serverp->flags |= CM_SERVERFLAG_DOWN;
+        serverp->flags |= CM_SERVERFLAG_DOWN;
                lock_ReleaseMutex(&serverp->mx);
-                retry = 1;
-        }
+        retry = 1;
+    }
 
        if (errorCode == RXKADEXPIRED && !dead_session) {
                lock_ObtainMutex(&userp->mx);
@@ -347,21 +360,21 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
 {
        long code;
        cm_serverRef_t *tsrp;
-        cm_server_t *tsp;
-        long firstError = 0;
+    cm_server_t *tsp;
+    long firstError = 0;
        int someBusy = 0, someOffline = 0, allBusy = 1, allDown = 1;
        long timeUsed, timeLeft, hardTimeLeft;
 #ifdef DJGPP
-        struct timeval now;
+    struct timeval now;
 #endif /* DJGPP */        
 
-        *connpp = NULL;
+    *connpp = NULL;
 
 #ifndef DJGPP
        timeUsed = (GetCurrentTime() - reqp->startTime) / 1000;
 #else
-        gettimeofday(&now, NULL);
-        timeUsed = sub_time(now, reqp->startTime) / 1000;
+    gettimeofday(&now, NULL);
+    timeUsed = sub_time(now, reqp->startTime) / 1000;
 #endif
         
        /* leave 5 seconds margin of safety */
@@ -369,8 +382,7 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp,
        hardTimeLeft = HardDeadtimeout - timeUsed - 5;
 
        lock_ObtainWrite(&cm_serverLock);
-
-    for(tsrp = serversp; tsrp; tsrp=tsrp->next) {
+    for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
         tsp = tsrp->server;
         tsp->refCount++;
         lock_ReleaseWrite(&cm_serverLock);
@@ -556,5 +568,6 @@ long cm_Conn(struct cm_fid *fidp, struct cm_user *userp, cm_req_t *reqp,
        }
 
        code = cm_ConnByMServers(serversp, userp, reqp, connpp);
-        return code;
+    cm_FreeServerList(&serversp);
+    return code;
 }
index 719d438..9404be8 100644 (file)
@@ -91,6 +91,7 @@ extern void cm_InitReq(cm_req_t *reqp);
 extern int cm_Analyze(cm_conn_t *connp, struct cm_user *up, struct cm_req *reqp,
        struct cm_fid *fidp,
        struct AFSVolSync *volInfop,
+    struct cm_serverRef_t * serversp,
        struct cm_callbackRequest *cbrp, long code);
 
 extern long cm_ConnByMServers(struct cm_serverRef *, struct cm_user *,
index 3086fd1..f65e9bb 100644 (file)
@@ -173,7 +173,7 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
         code = rx_EndCall(callp, code);
         osi_Log0(afsd_logp, "CALL StoreData DONE");
                 
-       } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, code));
+       } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
     code = cm_MapRPCError(code, reqp);
         
     /* now, clean up our state */
@@ -266,7 +266,7 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
                if (code == 0)
                        code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
         code = rx_EndCall(callp, code);
-       } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, code));
+       } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
     code = cm_MapRPCError(code, reqp);
         
     /* now, clean up our state */
@@ -1345,7 +1345,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
             osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
         osi_Log0(afsd_logp, "CALL FetchData DONE");
 
-       } while (cm_Analyze(connp, up, reqp, &scp->fid, &volSync, NULL, code));
+       } while (cm_Analyze(connp, up, reqp, &scp->fid, &volSync, NULL, NULL, code));
 
   fetchingcompleted:
     code = cm_MapRPCError(code, reqp);
index c88dd90..0104d1a 100644 (file)
@@ -419,8 +419,7 @@ long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
                 if (code) continue;
                 
                 code = RXAFS_FetchACL(connp->callp, &fid, &acl, &fileStatus, &volSync);
-       } while (cm_Analyze(connp, userp, &req, &scp->fid,
-                           &volSync, NULL, code));
+       } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
        cm_ReleaseSCache(scp);
         
@@ -485,8 +484,7 @@ long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
                 if (code) continue;
                 
                 code = RXAFS_StoreACL(connp->callp, &fid, &acl, &fileStatus, &volSync);
-       } while (cm_Analyze(connp, userp, &req, &scp->fid,
-                           &volSync, NULL, code));
+       } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
 
        /* invalidate cache info, since we just trashed the ACL cache */
@@ -611,7 +609,7 @@ long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
                code = RXAFS_SetVolumeStatus(tcp->callp, scp->fid.volume,
                        &storeStat, volName, offLineMsg, motd);
-       } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, code));
+       } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
 
        /* return on failure */
@@ -669,7 +667,7 @@ long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
 
                code = RXAFS_GetVolumeStatus(tcp->callp, scp->fid.volume,
                        &volStat, &Name, &OfflineMsg, &MOTD);
-       } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, code));
+       } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
 
        cm_ReleaseSCache(scp);
@@ -695,43 +693,43 @@ long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
 {
        long code;
-        cm_scache_t *scp;
-        cm_cell_t *cellp;
-        cm_volume_t *tvp;
-       cm_serverRef_t *tsrp;
-        cm_server_t *tsp;
-        unsigned long volume;
-        char *cp;
-        cm_req_t req;
+    cm_scache_t *scp;
+    cm_cell_t *cellp;
+    cm_volume_t *tvp;
+       cm_serverRef_t *tsrp, *current;
+    cm_server_t *tsp;
+    unsigned long volume;
+    char *cp;
+    cm_req_t req;
 
        cm_InitReq(&req);
 
-        code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
-        if (code) return code;
+    code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
+    if (code) return code;
         
        volume = scp->fid.volume;
 
        cellp = cm_FindCellByID(scp->fid.cell);
-        osi_assert(cellp);
+    osi_assert(cellp);
 
-        cm_ReleaseSCache(scp);
+    cm_ReleaseSCache(scp);
 
        code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
-        if (code) return code;
+    if (code) return code;
        
-        cp = ioctlp->outDatap;
+    cp = ioctlp->outDatap;
         
        lock_ObtainMutex(&tvp->mx);
        tsrp = cm_GetVolServers(tvp, volume);
        lock_ObtainRead(&cm_serverLock);
-       while(tsrp) {
-               tsp = tsrp->server;
+       for (current = tsrp; current; current = current->next) {
+               tsp = current->server;
                memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
                cp += sizeof(long);
-                tsrp = tsrp->next;
        }
        lock_ReleaseRead(&cm_serverLock);
-        lock_ReleaseMutex(&tvp->mx);
+    cm_FreeServerList(&tsrp);
+    lock_ReleaseMutex(&tvp->mx);
 
        /* still room for terminating NULL, add it on */
        volume = 0;     /* reuse vbl */
@@ -1007,14 +1005,14 @@ long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
 {
        long whichCell;
-        long magic = 0;
+    long magic = 0;
        cm_cell_t *tcellp;
        cm_serverRef_t *serverRefp;
-        cm_server_t *serverp;
+    cm_server_t *serverp;
        long i;
-        char *cp;
-        char *tp;
-        char *basep;
+    char *cp;
+    char *tp;
+    char *basep;
 
        cm_SkipIoctlPath(ioctlp);
 
@@ -1028,7 +1026,7 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
                memcpy((char *)&magic, tp, sizeof(long));
        }
 
-        lock_ObtainRead(&cm_cellLock);
+    lock_ObtainRead(&cm_cellLock);
        for(tcellp = cm_allCellsp; tcellp; tcellp = tcellp->nextp) {
                if (whichCell == 0) break;
                whichCell--;
@@ -1044,15 +1042,16 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
                        max = 13;
                }
                memset(cp, 0, max * sizeof(long));
-                basep = cp;
+        basep = cp;
                lock_ObtainRead(&cm_serverLock);        /* for going down server list */
+        /* jaltman - do the reference counts to serverRefp contents need to be increased? */
                serverRefp = tcellp->vlServersp;
                for(i=0; i<max; i++) {
                        if (!serverRefp) break;
                        serverp = serverRefp->server;
                        memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
                        cp += sizeof(long);
-                        serverRefp = serverRefp->next;
+            serverRefp = serverRefp->next;
                }
                lock_ReleaseRead(&cm_serverLock);
                cp = basep + max * sizeof(afs_int32);
@@ -1982,7 +1981,6 @@ long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
 {
        char afspath[MAX_PATH];
        char *submountreqp;
-       int iteration;
        int nextAutoSubmount;
     HKEY hkSubmounts;
     DWORD dwType, dwSize;
@@ -2021,7 +2019,6 @@ long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
     if (submountreqp && *submountreqp) {
                char submountPathNormalized[MAX_PATH];
                char submountPath[MAX_PATH];
-               int submountPathLen;
 
         dwSize = sizeof(submountPath);
         status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
index 248050f..e5df624 100644 (file)
@@ -142,6 +142,11 @@ void cm_PutServer(cm_server_t *serverp)
        lock_ReleaseWrite(&cm_serverLock);
 }
 
+void cm_PutServerNoLock(cm_server_t *serverp)
+{
+       osi_assert(serverp->refCount-- > 0);
+}
+
 void cm_SetServerPrefs(cm_server_t * serverp)
 {
        unsigned long   serverAddr;     /* in host byte order */
@@ -243,13 +248,14 @@ cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp)
 {
        cm_serverRef_t *tsrp;
 
-        lock_ObtainWrite(&cm_serverLock);
+    lock_ObtainWrite(&cm_serverLock);
        serverp->refCount++;
-        lock_ReleaseWrite(&cm_serverLock);
+    lock_ReleaseWrite(&cm_serverLock);
        tsrp = malloc(sizeof(*tsrp));
        tsrp->server = serverp;
        tsrp->status = not_busy;
        tsrp->next = NULL;
+    tsrp->refCount = 1;
 
        return tsrp;
 }
@@ -261,7 +267,6 @@ long cm_ChecksumServerList(cm_serverRef_t *serversp)
        cm_serverRef_t *tsrp;
 
     lock_ObtainWrite(&cm_serverLock);
-
        for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
                if (first)
                        first = 0;
@@ -277,6 +282,8 @@ long cm_ChecksumServerList(cm_serverRef_t *serversp)
 /*
 ** Insert a server into the server list keeping the list sorted in 
 ** asending order of ipRank. 
+** 
+** The refCount of the cm_serverRef_t is increased
 */
 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
 {
@@ -284,8 +291,9 @@ void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
        unsigned short ipRank = element->server->ipRank;
 
     lock_ObtainWrite(&cm_serverLock);
+    element->refCount++;                /* increase refCount */
 
-       /* insertion into empty list  or at the beginning of the list */
+    /* insertion into empty list  or at the beginning of the list */
        if ( !current || (current->server->ipRank > ipRank) )
        {
                element->next = *list;
@@ -338,6 +346,11 @@ long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*       server)
 
        /* re-insert deleted element into the list with modified rank*/
        cm_InsertServerList(list, element);
+
+    /* reduce refCount which was increased by cm_InsertServerList */
+    lock_ObtainWrite(&cm_serverLock);
+    element->refCount--;
+    lock_ReleaseWrite(&cm_serverLock);
        return 0;
 }
 /*
@@ -427,8 +440,10 @@ void cm_FreeServerList(cm_serverRef_t** list)
     while (current)
     {
         next = current->next;
-        cm_FreeServer(current->server);
-        free(current);
+        if (--current->refCount == 0) {
+            cm_FreeServer(current->server);
+            free(current);
+        }
         current = next;
     }
   
index 114a378..cabaf7c 100644 (file)
  */
 typedef struct cm_server {
        struct cm_server *allNextp;             /* locked by cm_serverLock */
-        struct sockaddr_in addr;               /* by mx */
-        int type;                              /* by mx */
+    struct sockaddr_in addr;           /* by mx */
+    int type;                          /* by mx */
        struct cm_conn *connsp;                 /* locked by cm_connLock */
-        long flags;                            /* by mx */
-        struct cm_cell *cellp;                 /* cell containing this server */
+    long flags;                                /* by mx */
+    struct cm_cell *cellp;                     /* cell containing this server */
        int refCount;                           /* locked by cm_serverLock */
-        osi_mutex_t mx;
+    osi_mutex_t mx;
        unsigned short ipRank;                  /* server priority */
 } cm_server_t;
 
 enum repstate {not_busy, busy, offline};
 
 typedef struct cm_serverRef {
-       struct cm_serverRef *next;
-       struct cm_server *server;
-       enum repstate status;
+       struct cm_serverRef *next;      /* locked by cm_serverLock */
+       struct cm_server *server;       /* locked by cm_serverLock */
+       enum repstate status;           /* locked by cm_serverLock */
+    int refCount;                   /* locked by cm_serverLock */
 } cm_serverRef_t;
 
 /* types */
@@ -75,6 +76,8 @@ extern long cm_ChecksumServerList(cm_serverRef_t *serversp);
 
 extern void cm_PutServer(cm_server_t *);
 
+extern void cm_PutServerNoLock(cm_server_t *);
+
 extern cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type);
 
 extern osi_rwlock_t cm_serverLock;
index 3ffb9fb..9ef59eb 100644 (file)
@@ -1114,8 +1114,7 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
                 code = RXAFS_RemoveFile(connp->callp, &afsFid, namep,
                                        &newDirStatus, &volSync);
                
-       } while (cm_Analyze(connp, userp, reqp,
-                           &dscp->fid, &volSync, NULL, code));
+       } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
         code = cm_MapRPCError(code, reqp);
 
         lock_ObtainMutex(&dscp->mx);
@@ -1630,7 +1629,7 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
                                &statStruct, &callbackStruct, &volSync);
 
                } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
-                                   &volSync, &cbReq, code));
+                                   &volSync, NULL, &cbReq, code));
                 code = cm_MapRPCError(code, reqp);
 
                 osi_Log0(afsd_logp, "CALL BulkStatus DONE");
@@ -1850,7 +1849,7 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
                        &afsInStatus, &afsOutStatus, &volSync);
 
        } while (cm_Analyze(connp, userp, reqp,
-                           &scp->fid, &volSync, NULL, code));
+                           &scp->fid, &volSync, NULL, NULL, code));
         code = cm_MapRPCError(code, reqp);
 
        osi_Log1(afsd_logp, "CALL StoreStatus DONE, code %d", code);
@@ -1923,7 +1922,7 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
                                        &updatedDirStatus, &newFileCallback,
                                        &volSync);
        } while (cm_Analyze(connp, userp, reqp,
-                           &dscp->fid, &volSync, &cbReq, code));
+                           &dscp->fid, &volSync, NULL, &cbReq, code));
         code = cm_MapRPCError(code, reqp);
         
         lock_ObtainMutex(&dscp->mx);
@@ -2039,7 +2038,7 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
                                     &updatedDirStatus, &newDirCallback,
                                     &volSync);
        } while (cm_Analyze(connp, userp, reqp,
-                           &dscp->fid, &volSync, &cbReq, code));
+                           &dscp->fid, &volSync, NULL, &cbReq, code));
         code = cm_MapRPCError(code, reqp);
         
         lock_ObtainMutex(&dscp->mx);
@@ -2121,7 +2120,7 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
                                     &inStatus, &newAFSFid, &newLinkStatus,
                                     &updatedDirStatus, &volSync);
        } while (cm_Analyze(connp, userp, reqp,
-                           &dscp->fid, &volSync, NULL, code));
+                           &dscp->fid, &volSync, NULL, NULL, code));
         code = cm_MapRPCError(code, reqp);
         
         lock_ObtainMutex(&dscp->mx);
@@ -2190,7 +2189,7 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
                 code = RXAFS_RemoveDir(connp->callp, &dirAFSFid, namep,
                                        &updatedDirStatus, &volSync);
        } while (cm_Analyze(connp, userp, reqp,
-                           &dscp->fid, &volSync, NULL, code));
+                           &dscp->fid, &volSync, NULL, NULL, code));
         code = cm_MapRPCErrorRmdir(code, reqp);
         
         lock_ObtainMutex(&dscp->mx);
@@ -2330,7 +2329,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
                        &updatedOldDirStatus, &updatedNewDirStatus,
                        &volSync);
        } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
-                           &volSync, NULL, code));
+                           &volSync, NULL, NULL, code));
         code = cm_MapRPCError(code, reqp);
         
        /* update the individual stat cache entries for the directories */
@@ -2402,7 +2401,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char LockType,
                        code = RXAFS_SetLock(connp->callp, &tfid, Which,
                                             &volSync);
                } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync,
-                                   NULL, code));
+                                   NULL, NULL, code));
                lock_ObtainMutex(&scp->mx);
                code = cm_MapRPCError(code, reqp);
        }
@@ -2493,7 +2492,7 @@ long cm_Unlock(cm_scache_t *scp, unsigned char LockType,
                 break;
                        code = RXAFS_ReleaseLock(connp->callp, &tfid, &volSync);
                } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync,
-                                   NULL, code));
+                                   NULL, NULL, code));
                code = cm_MapRPCError(code, reqp);
                lock_ObtainMutex(&scp->mx);
        }
@@ -2534,7 +2533,7 @@ void cm_CheckLocks()
                                code = RXAFS_ExtendLock(connp->callp, &tfid,
                                                        &volSync);
                        } while (cm_Analyze(connp, fileLock->userp, &req,
-                                           &fileLock->fid, &volSync, NULL,
+                                           &fileLock->fid, &volSync, NULL, NULL,
                                            code));
                        code = cm_MapRPCError(code, &req);
                        lock_ObtainWrite(&cm_scacheLock);
@@ -2602,7 +2601,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int vcp_is_dead)
                                             &volSync);
                } while (cm_Analyze(connp, oldFileLock->userp, &req,
                                    &oldFileLock->fid, &volSync,
-                                   NULL, code));
+                                   NULL, NULL, code));
                code = cm_MapRPCError(code, &req);
        }
 
index 7143a52..aa1ebd4 100644 (file)
@@ -55,21 +55,9 @@ long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
        long code;
 
        /* clear out old bindings */
-       while (tsrp = volp->rwServersp) {
-               volp->rwServersp = tsrp->next;
-               cm_PutServer(tsrp->server);
-               free(tsrp);
-       }
-       while (tsrp = volp->roServersp) {
-               volp->roServersp = tsrp->next;
-               cm_PutServer(tsrp->server);
-               free(tsrp);
-       }
-       while (tsrp = volp->bkServersp) {
-               volp->bkServersp = tsrp->next;
-               cm_PutServer(tsrp->server);
-               free(tsrp);
-       }
+    cm_FreeServerList(&volp->rwServersp);
+    cm_FreeServerList(&volp->roServersp);
+    cm_FreeServerList(&volp->bkServersp);
 
     /* now we have volume structure locked and held; make RPC to fill it */
     do {
@@ -79,7 +67,7 @@ long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
                osi_Log1(afsd_logp, "CALL VL_GetEntryByNameO name %s",
                   volp->namep);
         code = VL_GetEntryByNameO(connp->callp, volp->namep, &vldbEntry);
-       } while (cm_Analyze(connp, userp, reqp, NULL, NULL, NULL, code));
+       } while (cm_Analyze(connp, userp, reqp, NULL, NULL, cellp->vlServersp, NULL, code));
     code = cm_MapVLRPCError(code, reqp);
 
     if (code == 0) {
@@ -126,21 +114,28 @@ long cm_UpdateVolume(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *reqp,
                        if ((tflags & VLSF_RWVOL)
                  && (vldbEntry.flags & VLF_RWEXISTS)) {
                                tsrp = cm_NewServerRef(tsp);
-                               tsrp->next = volp->rwServersp;
-                volp->rwServersp = tsrp;
+                cm_InsertServerList(&volp->rwServersp, tsrp);
+                lock_ObtainWrite(&cm_serverLock);
+                tsrp->refCount--;       /* drop allocation reference */
+                lock_ReleaseWrite(&cm_serverLock);
                        }
             if ((tflags & VLSF_ROVOL)
                  && (vldbEntry.flags & VLF_ROEXISTS)) {
                                tsrp = cm_NewServerRef(tsp);
                                cm_InsertServerList(&volp->roServersp, tsrp);
+                lock_ObtainWrite(&cm_serverLock);
+                tsrp->refCount--;       /* drop allocation reference */
+                lock_ReleaseWrite(&cm_serverLock);
                                ROcount++;
             }
                        /* We don't use VLSF_BACKVOL !?! */
             if ((tflags & VLSF_RWVOL)
                  && (vldbEntry.flags & VLF_BACKEXISTS)) {
                                tsrp = cm_NewServerRef(tsp);
-                tsrp->next = volp->bkServersp;
-                volp->bkServersp = tsrp;
+                cm_InsertServerList(&volp->bkServersp, tsrp);
+                lock_ObtainWrite(&cm_serverLock);
+                tsrp->refCount--;       /* drop allocation reference */
+                lock_ReleaseWrite(&cm_serverLock);
                        }
                        /* Drop the reference obtained by cm_FindServer() */
                        cm_PutServer(tsp);
@@ -311,16 +306,24 @@ void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
 cm_serverRef_t *cm_GetVolServers(cm_volume_t *volp, unsigned long volume)
 {
        cm_serverRef_t *serversp;
+    cm_serverRef_t *current;;
+
+    lock_ObtainWrite(&cm_serverLock);
 
        if (volume == volp->rwID)
-               serversp = volp->rwServersp;
+        serversp = volp->rwServersp;
        else if (volume == volp->roID)
-               serversp = volp->roServersp;
+        serversp = volp->roServersp;
        else if (volume == volp->bkID)
-               serversp = volp->bkServersp;
+        serversp = volp->bkServersp;
        else osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
         
-        return serversp;
+    for (current = serversp; current; current = current->next)
+        current->refCount++;
+
+    lock_ReleaseWrite(&cm_serverLock);
+
+    return serversp;
 }
 
 void cm_PutVolume(cm_volume_t *volp)