windows-check-server-memleak-20080606
[openafs.git] / src / WINNT / afsd / cm_server.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <winsock2.h>
15 #include <nb30.h>
16 #include <stdlib.h>
17 #include <malloc.h>
18 #include <string.h>
19
20 #include "afsd.h"
21 #include <WINNT\syscfg.h>
22 #include <osi.h>
23 #include <rx/rx.h>
24
25 osi_rwlock_t cm_serverLock;
26 osi_rwlock_t cm_syscfgLock;
27
28 cm_server_t *cm_allServersp;
29 afs_uint32   cm_numFileServers = 0;
30 afs_uint32   cm_numVldbServers = 0;
31
32 void
33 cm_ForceNewConnectionsAllServers(void)
34 {
35     cm_server_t *tsp;
36
37     lock_ObtainRead(&cm_serverLock);
38     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
39         cm_GetServerNoLock(tsp);
40         cm_ForceNewConnections(tsp);
41         cm_PutServerNoLock(tsp);
42     }
43     lock_ReleaseRead(&cm_serverLock);
44 }
45
46 void 
47 cm_PingServer(cm_server_t *tsp)
48 {
49     long code;
50     int wasDown = 0;
51     cm_conn_t *connp;
52     struct rx_connection * rxconnp;
53     long secs;
54     long usecs;
55     Capabilities caps = {0, 0};
56     char hoststr[16];
57     cm_req_t req;
58
59     lock_ObtainMutex(&tsp->mx);
60     if (tsp->flags & CM_SERVERFLAG_PINGING) {
61         tsp->waitCount++;
62         osi_SleepM((LONG_PTR)tsp, &tsp->mx);
63         lock_ObtainMutex(&tsp->mx);
64         tsp->waitCount--;
65         if (tsp->waitCount == 0)
66             tsp->flags &= ~CM_SERVERFLAG_PINGING;
67         else 
68             osi_Wakeup((LONG_PTR)tsp);
69         lock_ReleaseMutex(&tsp->mx);
70         return;
71     }
72     tsp->flags |= CM_SERVERFLAG_PINGING;
73     wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
74     afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
75     lock_ReleaseMutex(&tsp->mx);
76
77     code = cm_ConnByServer(tsp, cm_rootUserp, &connp);
78     if (code == 0) {
79         /* now call the appropriate ping call.  Drop the timeout if
80         * the server is known to be down, so that we don't waste a
81         * lot of time retiming out down servers.
82         */
83
84         osi_Log4(afsd_logp, "cm_PingServer server %s (%s) was %s with caps 0x%x",
85                   osi_LogSaveString(afsd_logp, hoststr), 
86                   tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
87                   wasDown ? "down" : "up",
88                   tsp->capabilities);
89
90         rxconnp = cm_GetRxConn(connp);
91         if (wasDown)
92             rx_SetConnDeadTime(rxconnp, 10);
93         if (tsp->type == CM_SERVER_VLDB) {
94             code = VL_ProbeServer(rxconnp);
95         }
96         else {
97             /* file server */
98             code = RXAFS_GetCapabilities(rxconnp, &caps);
99             if (code == RXGEN_OPCODE)
100                 code = RXAFS_GetTime(rxconnp, &secs, &usecs);
101         }
102         if (wasDown)
103             rx_SetConnDeadTime(rxconnp, ConnDeadtimeout);
104         rx_PutConnection(rxconnp);
105         cm_PutConn(connp);
106     }   /* got an unauthenticated connection to this server */
107
108     lock_ObtainMutex(&tsp->mx);
109     if (code >= 0) {
110         /* mark server as up */
111         tsp->flags &= ~CM_SERVERFLAG_DOWN;
112         tsp->downTime = 0;
113
114         /* we currently handle 32-bits of capabilities */
115         if (caps.Capabilities_len > 0) {
116             tsp->capabilities = caps.Capabilities_val[0];
117             free(caps.Capabilities_val);
118             caps.Capabilities_len = 0;
119             caps.Capabilities_val = 0;
120         } else {
121             tsp->capabilities = 0;
122         }
123
124         osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is up with caps 0x%x",
125                   osi_LogSaveString(afsd_logp, hoststr), 
126                   tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
127                   tsp->capabilities);
128
129         /* Now update the volume status if necessary */
130         if (wasDown) {
131             cm_server_vols_t * tsrvp;
132             cm_volume_t * volp;
133             int i;
134
135             for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
136                 for (i=0; i<NUM_SERVER_VOLS; i++) {
137                     if (tsrvp->ids[i] != 0) {
138                         cm_InitReq(&req);
139
140                         lock_ReleaseMutex(&tsp->mx);
141                         code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
142                                                 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
143                         lock_ObtainMutex(&tsp->mx);
144                         if (code == 0) {
145                             cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
146                             cm_PutVolume(volp);
147                         }
148                     }
149                 }
150             }
151         }
152     } else {
153         /* mark server as down */
154         if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
155             tsp->flags |= CM_SERVERFLAG_DOWN;
156             tsp->downTime = time(NULL);
157         }
158         if (code != VRESTARTING)
159             cm_ForceNewConnections(tsp);
160
161         osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
162                   osi_LogSaveString(afsd_logp, hoststr), 
163                   tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
164                   tsp->capabilities);
165
166         /* Now update the volume status if necessary */
167         if (!wasDown) {
168             cm_server_vols_t * tsrvp;
169             cm_volume_t * volp;
170             int i;
171
172             for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
173                 for (i=0; i<NUM_SERVER_VOLS; i++) {
174                     if (tsrvp->ids[i] != 0) {
175                         cm_InitReq(&req);
176
177                         lock_ReleaseMutex(&tsp->mx);
178                         code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
179                                                 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
180                         lock_ObtainMutex(&tsp->mx);
181                         if (code == 0) {
182                             cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
183                             cm_PutVolume(volp);
184                         }
185                     }
186                 }
187             }
188         }
189     }
190
191     if (tsp->waitCount == 0)
192         tsp->flags &= ~CM_SERVERFLAG_PINGING;
193     else 
194         osi_Wakeup((LONG_PTR)tsp);
195     lock_ReleaseMutex(&tsp->mx);
196 }
197
198 #define MULTI_CHECKSERVERS 1
199 #ifndef MULTI_CHECKSERVERS
200 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
201 {
202     /* ping all file servers, up or down, with unauthenticated connection,
203      * to find out whether we have all our callbacks from the server still.
204      * Also, ping down VLDBs.
205      */
206     cm_server_t *tsp;
207     int doPing;
208     int isDown;
209     int isFS;
210
211     lock_ObtainRead(&cm_serverLock);
212     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
213         cm_GetServerNoLock(tsp);
214         lock_ReleaseRead(&cm_serverLock);
215
216         /* now process the server */
217         lock_ObtainMutex(&tsp->mx);
218
219         doPing = 0;
220         isDown = tsp->flags & CM_SERVERFLAG_DOWN;
221         isFS   = tsp->type == CM_SERVER_FILE;
222
223         /* only do the ping if the cell matches the requested cell, or we're
224          * matching all cells (cellp == NULL), and if we've requested to ping
225          * this type of {up, down} servers.
226          */
227         if ((cellp == NULL || cellp == tsp->cellp) &&
228              ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
229                (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
230              ((!(flags & CM_FLAG_CHECKVLDBSERVERS) || 
231                !isFS && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
232               (!(flags & CM_FLAG_CHECKFILESERVERS) || 
233                  isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
234             doPing = 1;
235         }       /* we're supposed to check this up/down server */
236         lock_ReleaseMutex(&tsp->mx);
237
238         /* at this point, we've adjusted the server state, so do the ping and
239          * adjust things.
240          */
241         if (doPing) 
242             cm_PingServer(tsp);
243
244         /* also, run the GC function for connections on all of the
245          * server's connections.
246          */
247         cm_GCConnections(tsp);
248
249         lock_ObtainRead(&cm_serverLock);
250         cm_PutServerNoLock(tsp);
251     }
252     lock_ReleaseRead(&cm_serverLock);
253 }       
254 #else /* MULTI_CHECKSERVERS */
255 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
256 {
257     /* 
258      * The goal of this function is to probe simultaneously 
259      * probe all of the up/down servers (vldb/file) as 
260      * specified by flags in the minimum number of RPCs.
261      * Effectively that means use one multi_RXAFS_GetCapabilities()
262      * followed by possibly one multi_RXAFS_GetTime() and 
263      * one multi_VL_ProbeServer().
264      *
265      * To make this work we must construct the list of vldb
266      * and file servers that are to be probed as well as the
267      * associated data structures.
268      */
269
270     int srvAddrCount = 0;
271     struct srvAddr **addrs = NULL;
272     cm_conn_t **conns = NULL;
273     struct rx_connection **rxconns = NULL;
274     cm_req_t req;
275     afs_int32 i, j, nconns = 0;
276     afs_int32 *conntimer, *results;
277     Capabilities *caps = NULL;
278     cm_server_t ** serversp, *tsp;
279     afs_uint32 isDown, wasDown;
280     afs_uint32 code;
281     time_t start, end, *deltas;
282     afs_int32 secs;
283     afs_int32 usecs;
284     char hoststr[16];
285
286     cm_InitReq(&req);
287
288     j = max(cm_numFileServers,cm_numVldbServers);
289     conns = (cm_conn_t **)malloc(j * sizeof(cm_conn_t *));
290     rxconns = (struct rx_connection **)malloc(j * sizeof(struct rx_connection *));
291     conntimer = (afs_int32 *)malloc(j * sizeof (afs_int32));
292     deltas = (time_t *)malloc(j * sizeof (time_t));
293     results = (afs_int32 *)malloc(j * sizeof (afs_int32));
294     serversp = (cm_server_t **)malloc(j * sizeof(cm_server_t *));
295     caps = (Capabilities *)malloc(j * sizeof(Capabilities));
296
297     memset(caps, 0, j * sizeof(Capabilities));
298
299     if ((flags & CM_FLAG_CHECKFILESERVERS) || 
300         !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
301     {
302         lock_ObtainRead(&cm_serverLock);
303         nconns = 0;
304         for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
305             if (tsp->type != CM_SERVER_FILE || 
306                 tsp->cellp == NULL ||           /* SetPref only */
307                 cellp && cellp != tsp->cellp)
308                 continue;
309
310             cm_GetServerNoLock(tsp);
311             lock_ReleaseRead(&cm_serverLock);
312
313             lock_ObtainMutex(&tsp->mx);
314             isDown = tsp->flags & CM_SERVERFLAG_DOWN;
315
316             if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
317                 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
318                    (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
319                 lock_ReleaseMutex(&tsp->mx);
320                 lock_ObtainRead(&cm_serverLock);
321                 cm_PutServerNoLock(tsp);
322                 continue;
323             }
324
325             tsp->flags |= CM_SERVERFLAG_PINGING;
326             lock_ReleaseMutex(&tsp->mx);
327
328             serversp[nconns] = tsp;
329             code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
330             if (code) {
331                 lock_ObtainRead(&cm_serverLock);
332                 cm_PutServerNoLock(tsp);
333                 continue;
334             }
335             lock_ObtainRead(&cm_serverLock);
336             rxconns[nconns] = cm_GetRxConn(conns[nconns]);
337             if (conntimer[nconns] = (isDown ? 1 : 0))
338                 rx_SetConnDeadTime(rxconns[nconns], 10);
339
340             nconns++;
341         }
342         lock_ReleaseRead(&cm_serverLock);
343
344         if (nconns) {
345             /* Perform the multi call */
346             start = time(NULL);
347             multi_Rx(rxconns,nconns)
348             {
349                 multi_RXAFS_GetCapabilities(&caps[multi_i]);
350                 results[multi_i]=multi_error;
351             } multi_End;
352         }
353
354         /* Process results of servers that support RXAFS_GetCapabilities */
355         for (i=0; i<nconns; i++) {
356             /* Leave the servers that did not support GetCapabilities alone */
357             if (results[i] == RXGEN_OPCODE)
358                 continue;
359
360             if (conntimer[i])
361                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
362             rx_PutConnection(rxconns[i]);
363             cm_PutConn(conns[i]);
364
365             tsp = serversp[i];
366             cm_GCConnections(tsp);
367
368             lock_ObtainMutex(&tsp->mx);
369             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
370
371             if (results[i] >= 0)  {
372                 /* mark server as up */
373                 tsp->flags &= ~CM_SERVERFLAG_DOWN;
374                 tsp->downTime = 0;
375
376                 /* we currently handle 32-bits of capabilities */
377                 if (caps[i].Capabilities_len > 0) {
378                     tsp->capabilities = caps[i].Capabilities_val[0];
379                     free(caps[i].Capabilities_val);
380                     caps[i].Capabilities_len = 0;
381                     caps[i].Capabilities_val = 0;
382                 } else {
383                     tsp->capabilities = 0;
384                 }
385
386                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
387                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
388                           osi_LogSaveString(afsd_logp, hoststr), 
389                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
390                           tsp->capabilities);
391
392                 /* Now update the volume status if necessary */
393                 if (wasDown) {
394                     cm_server_vols_t * tsrvp;
395                     cm_volume_t * volp;
396                     int i;
397
398                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
399                         for (i=0; i<NUM_SERVER_VOLS; i++) {
400                             if (tsrvp->ids[i] != 0) {
401                                 cm_InitReq(&req);
402
403                                 lock_ReleaseMutex(&tsp->mx);
404                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
405                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
406                                 lock_ObtainMutex(&tsp->mx);
407                                 if (code == 0) {
408                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
409                                     cm_PutVolume(volp);
410                                 }
411                             }
412                         }
413                     }
414                 }
415             } else {
416                 /* mark server as down */
417                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
418                     tsp->flags |= CM_SERVERFLAG_DOWN;
419                     tsp->downTime = time(NULL);
420                 }
421                 if (code != VRESTARTING)
422                     cm_ForceNewConnections(tsp);
423
424                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
425                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
426                           osi_LogSaveString(afsd_logp, hoststr), 
427                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
428                           tsp->capabilities);
429
430                 /* Now update the volume status if necessary */
431                 if (!wasDown) {
432                     cm_server_vols_t * tsrvp;
433                     cm_volume_t * volp;
434                     int i;
435
436                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
437                         for (i=0; i<NUM_SERVER_VOLS; i++) {
438                             if (tsrvp->ids[i] != 0) {
439                                 cm_InitReq(&req);
440
441                                 lock_ReleaseMutex(&tsp->mx);
442                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
443                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
444                                 lock_ObtainMutex(&tsp->mx);
445                                 if (code == 0) {
446                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
447                                     cm_PutVolume(volp);
448                                 }
449                             }
450                         }
451                     }
452                 }
453             }
454
455             if (tsp->waitCount == 0)
456                 tsp->flags &= ~CM_SERVERFLAG_PINGING;
457             else 
458                 osi_Wakeup((LONG_PTR)tsp);
459             
460             lock_ReleaseMutex(&tsp->mx);
461
462             cm_PutServer(tsp);
463         }
464
465         /* 
466          * At this point we have handled any responses that did not indicate
467          * that RXAFS_GetCapabilities is not supported.
468          */
469         for ( i=0, j=0; i<nconns; i++) {
470             if (results[i] == RXGEN_OPCODE) {
471                 if (i != j) {
472                     conns[j] = conns[i];
473                     rxconns[j] = rxconns[i];
474                     serversp[j] = serversp[i];
475                 }
476                 j++;
477             }
478         }
479         nconns = j;
480
481         if (nconns) {
482             /* Perform the multi call */
483             start = time(NULL);
484             multi_Rx(rxconns,nconns)
485             {
486                 secs = usecs = 0;
487                 multi_RXAFS_GetTime(&secs, &usecs);
488                 end = time(NULL);
489                 results[multi_i]=multi_error;
490                 if ((start == end) && !multi_error)
491                     deltas[multi_i] = end - secs;
492             } multi_End;
493         }
494
495         /* Process Results of servers that only support RXAFS_GetTime */
496         for (i=0; i<nconns; i++) {
497             /* Leave the servers that did not support GetCapabilities alone */
498             if (conntimer[i])
499                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
500             rx_PutConnection(rxconns[i]);
501             cm_PutConn(conns[i]);
502
503             tsp = serversp[i];
504             cm_GCConnections(tsp);
505
506             lock_ObtainMutex(&tsp->mx);
507             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
508
509             if (results[i] >= 0)  {
510                 /* mark server as up */
511                 tsp->flags &= ~CM_SERVERFLAG_DOWN;
512                 tsp->downTime = 0;
513                 tsp->capabilities = 0;
514
515                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
516                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
517                           osi_LogSaveString(afsd_logp, hoststr), 
518                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
519                           tsp->capabilities);
520
521                 /* Now update the volume status if necessary */
522                 if (wasDown) {
523                     cm_server_vols_t * tsrvp;
524                     cm_volume_t * volp;
525                     int i;
526
527                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
528                         for (i=0; i<NUM_SERVER_VOLS; i++) {
529                             if (tsrvp->ids[i] != 0) {
530                                 cm_InitReq(&req);
531
532                                 lock_ReleaseMutex(&tsp->mx);
533                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
534                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
535                                 lock_ObtainMutex(&tsp->mx);
536                                 if (code == 0) {
537                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
538                                     cm_PutVolume(volp);
539                                 }
540                             }
541                         }
542                     }
543                 }
544             } else {
545                 /* mark server as down */
546                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
547                     tsp->flags |= CM_SERVERFLAG_DOWN;
548                     tsp->downTime = time(NULL);
549                 }
550                 if (code != VRESTARTING)
551                     cm_ForceNewConnections(tsp);
552
553                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
554                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
555                           osi_LogSaveString(afsd_logp, hoststr), 
556                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
557                           tsp->capabilities);
558
559                 /* Now update the volume status if necessary */
560                 if (!wasDown) {
561                     cm_server_vols_t * tsrvp;
562                     cm_volume_t * volp;
563                     int i;
564
565                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
566                         for (i=0; i<NUM_SERVER_VOLS; i++) {
567                             if (tsrvp->ids[i] != 0) {
568                                 cm_InitReq(&req);
569
570                                 lock_ReleaseMutex(&tsp->mx);
571                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
572                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
573                                 lock_ObtainMutex(&tsp->mx);
574                                 if (code == 0) {
575                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
576                                     cm_PutVolume(volp);
577                                 }
578                             }
579                         }
580                     }
581                 }
582             }
583
584             if (tsp->waitCount == 0)
585                 tsp->flags &= ~CM_SERVERFLAG_PINGING;
586             else 
587                 osi_Wakeup((LONG_PTR)tsp);
588             
589             lock_ReleaseMutex(&tsp->mx);
590
591             cm_PutServer(tsp);
592         }
593     }
594
595     if ((flags & CM_FLAG_CHECKVLDBSERVERS) || 
596         !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
597     {
598         lock_ObtainRead(&cm_serverLock);
599         nconns = 0;
600         for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
601             if (tsp->type != CM_SERVER_VLDB ||
602                 tsp->cellp == NULL ||           /* SetPref only */
603                 cellp && cellp != tsp->cellp)
604                 continue;
605
606             cm_GetServerNoLock(tsp);
607             lock_ReleaseRead(&cm_serverLock);
608
609             lock_ObtainMutex(&tsp->mx);
610             isDown = tsp->flags & CM_SERVERFLAG_DOWN;
611
612             if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
613                 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
614                    (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
615                 lock_ReleaseMutex(&tsp->mx);
616                 lock_ObtainRead(&cm_serverLock);
617                 cm_PutServerNoLock(tsp);
618                 continue;
619             }
620
621             tsp->flags |= CM_SERVERFLAG_PINGING;
622             lock_ReleaseMutex(&tsp->mx);
623
624             serversp[nconns] = tsp;
625             code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
626             if (code) {
627                 lock_ObtainRead(&cm_serverLock);
628                 cm_PutServerNoLock(tsp);
629                 continue;
630             }
631             lock_ObtainRead(&cm_serverLock);
632             rxconns[nconns] = cm_GetRxConn(conns[nconns]);
633             conntimer[nconns] = (isDown ? 1 : 0);
634             if (isDown)
635                 rx_SetConnDeadTime(rxconns[nconns], 10);
636
637             nconns++;
638         }
639         lock_ReleaseRead(&cm_serverLock);
640
641         if (nconns) {
642             /* Perform the multi call */
643             start = time(NULL);
644             multi_Rx(rxconns,nconns)
645             {
646                 multi_VL_ProbeServer();
647                 results[multi_i]=multi_error;
648             } multi_End;
649         }
650
651         /* Process results of servers that support RXAFS_GetCapabilities */
652         for (i=0; i<nconns; i++) {
653             if (conntimer[i])
654                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
655             rx_PutConnection(rxconns[i]);
656             cm_PutConn(conns[i]);
657
658             tsp = serversp[i];
659             cm_GCConnections(tsp);
660
661             lock_ObtainMutex(&tsp->mx);
662             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
663
664             if (results[i] >= 0)  {
665                 /* mark server as up */
666                 tsp->flags &= ~CM_SERVERFLAG_DOWN;
667                 tsp->downTime = 0;
668                 tsp->capabilities = 0;
669
670                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
671                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
672                           osi_LogSaveString(afsd_logp, hoststr), 
673                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
674                           tsp->capabilities);
675
676                 /* Now update the volume status if necessary */
677                 if (wasDown) {
678                     cm_server_vols_t * tsrvp;
679                     cm_volume_t * volp;
680                     int i;
681
682                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
683                         for (i=0; i<NUM_SERVER_VOLS; i++) {
684                             if (tsrvp->ids[i] != 0) {
685                                 cm_InitReq(&req);
686
687                                 lock_ReleaseMutex(&tsp->mx);
688                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
689                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
690                                 lock_ObtainMutex(&tsp->mx);
691                                 if (code == 0) {
692                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
693                                     cm_PutVolume(volp);
694                                 }
695                             }
696                         }
697                     }
698                 }
699             } else {
700                 /* mark server as down */
701                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
702                     tsp->flags |= CM_SERVERFLAG_DOWN;
703                     tsp->downTime = time(NULL);
704                 }
705                 if (code != VRESTARTING)
706                     cm_ForceNewConnections(tsp);
707
708                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
709                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
710                           osi_LogSaveString(afsd_logp, hoststr), 
711                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
712                           tsp->capabilities);
713
714                 /* Now update the volume status if necessary */
715                 if (!wasDown) {
716                     cm_server_vols_t * tsrvp;
717                     cm_volume_t * volp;
718                     int i;
719
720                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
721                         for (i=0; i<NUM_SERVER_VOLS; i++) {
722                             if (tsrvp->ids[i] != 0) {
723                                 cm_InitReq(&req);
724
725                                 lock_ReleaseMutex(&tsp->mx);
726                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
727                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
728                                 lock_ObtainMutex(&tsp->mx);
729                                 if (code == 0) {
730                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
731                                     cm_PutVolume(volp);
732                                 }
733                             }
734                         }
735                     }
736                 }
737             }
738
739             if (tsp->waitCount == 0)
740                 tsp->flags &= ~CM_SERVERFLAG_PINGING;
741             else 
742                 osi_Wakeup((LONG_PTR)tsp);
743             
744             lock_ReleaseMutex(&tsp->mx);
745
746             cm_PutServer(tsp);
747         }
748     }
749
750     free(conns);
751     free(rxconns);
752     free(conntimer);
753     free(deltas);
754     free(results);
755     free(serversp);
756     free(caps);
757 }
758 #endif /* MULTI_CHECKSERVERS */
759
760 void cm_InitServer(void)
761 {
762     static osi_once_t once;
763         
764     if (osi_Once(&once)) {
765         lock_InitializeRWLock(&cm_serverLock, "cm_serverLock");
766         lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock");
767         osi_EndOnce(&once);
768     }
769 }
770
771 /* Protected by cm_syscfgLock (rw) */
772 int cm_noIPAddr;         /* number of client network interfaces */
773 int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
774 int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
775 int cm_NetMtu[CM_MAXINTERFACE_ADDR];    /* client's MTU sizes */
776 int cm_NetFlags[CM_MAXINTERFACE_ADDR];  /* network flags */
777 int cm_LanAdapterChangeDetected = 1;
778
779 void cm_SetLanAdapterChangeDetected(void)
780 {
781     lock_ObtainWrite(&cm_syscfgLock);
782     cm_LanAdapterChangeDetected = 1;
783     lock_ReleaseWrite(&cm_syscfgLock);
784 }
785
786 void cm_GetServer(cm_server_t *serverp)
787 {
788     lock_ObtainRead(&cm_serverLock);
789     InterlockedIncrement(&serverp->refCount);
790     lock_ReleaseRead(&cm_serverLock);
791 }
792
793 void cm_GetServerNoLock(cm_server_t *serverp)
794 {
795     InterlockedIncrement(&serverp->refCount);
796 }
797
798 void cm_PutServer(cm_server_t *serverp)
799 {
800     afs_int32 refCount;
801     lock_ObtainRead(&cm_serverLock);
802     refCount = InterlockedDecrement(&serverp->refCount);
803     osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
804     lock_ReleaseRead(&cm_serverLock);
805 }
806
807 void cm_PutServerNoLock(cm_server_t *serverp)
808 {
809     afs_int32 refCount = InterlockedDecrement(&serverp->refCount);
810     osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
811 }
812
813 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
814 {
815     lock_ObtainMutex(&serverp->mx);
816     if (no64bit)
817         serverp->flags |= CM_SERVERFLAG_NO64BIT;
818     else
819         serverp->flags &= ~CM_SERVERFLAG_NO64BIT;
820     lock_ReleaseMutex(&serverp->mx);
821 }
822
823 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
824 {
825     lock_ObtainMutex(&serverp->mx);
826     if (no)
827         serverp->flags |= CM_SERVERFLAG_NOINLINEBULK;
828     else
829         serverp->flags &= ~CM_SERVERFLAG_NOINLINEBULK;
830     lock_ReleaseMutex(&serverp->mx);
831 }
832
833 void cm_SetServerPrefs(cm_server_t * serverp)
834 {
835     unsigned long       serverAddr;     /* in host byte order */
836     unsigned long       myAddr, myNet, mySubnet;/* in host byte order */
837     unsigned long       netMask;
838     int                 i;
839     long code;
840     int writeLock = 0;
841
842     lock_ObtainRead(&cm_syscfgLock);
843     if (cm_LanAdapterChangeDetected) {
844         lock_ConvertRToW(&cm_syscfgLock);
845         writeLock = 1;
846         if (cm_LanAdapterChangeDetected) {
847             /* get network related info */
848             cm_noIPAddr = CM_MAXINTERFACE_ADDR;
849             code = syscfg_GetIFInfo(&cm_noIPAddr,
850                                      cm_IPAddr, cm_SubnetMask,
851                                      cm_NetMtu, cm_NetFlags);
852             cm_LanAdapterChangeDetected = 0;
853         }
854         lock_ConvertWToR(&cm_syscfgLock);
855     }
856
857     serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
858     serverp->ipRank  = CM_IPRANK_LOW;   /* default setings */
859
860     for ( i=0; i < cm_noIPAddr; i++)
861     {
862         /* loop through all the client's IP address and compare
863         ** each of them against the server's IP address */
864
865         myAddr = cm_IPAddr[i];
866         if ( IN_CLASSA(myAddr) )
867             netMask = IN_CLASSA_NET;
868         else if ( IN_CLASSB(myAddr) )
869             netMask = IN_CLASSB_NET;
870         else if ( IN_CLASSC(myAddr) )
871             netMask = IN_CLASSC_NET;
872         else
873             netMask = 0;
874
875         myNet    =  myAddr & netMask;
876         mySubnet =  myAddr & cm_SubnetMask[i];
877
878         if ( (serverAddr & netMask) == myNet ) 
879         {
880             if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
881             {
882                 if ( serverAddr == myAddr ) 
883                     serverp->ipRank = min(serverp->ipRank,
884                                            CM_IPRANK_TOP);/* same machine */
885                 else serverp->ipRank = min(serverp->ipRank,
886                                             CM_IPRANK_HI); /* same subnet */
887             }
888             else serverp->ipRank = min(serverp->ipRank,CM_IPRANK_MED);
889             /* same net */
890         }       
891         /* random between 0..15*/
892         serverp->ipRank += min(serverp->ipRank, rand() % 0x000f);
893     } /* and of for loop */
894     lock_ReleaseRead(&cm_syscfgLock);
895 }
896
897 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afs_uint32 flags) {
898     cm_server_t *tsp;
899
900     osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
901
902     tsp = malloc(sizeof(*tsp));
903     if (tsp) {
904         memset(tsp, 0, sizeof(*tsp));
905         tsp->type = type;
906         tsp->cellp = cellp;
907         tsp->refCount = 1;
908         lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
909         tsp->addr = *socketp;
910
911         cm_SetServerPrefs(tsp); 
912
913         lock_ObtainWrite(&cm_serverLock);       /* get server lock */
914         tsp->allNextp = cm_allServersp;
915         cm_allServersp = tsp;
916
917         switch (type) {
918         case CM_SERVER_VLDB:
919             cm_numVldbServers++;
920             break;      
921         case CM_SERVER_FILE:
922             cm_numFileServers++;
923             break;
924         }
925
926         lock_ReleaseWrite(&cm_serverLock);      /* release server lock */
927
928         if ( !(flags & CM_FLAG_NOPROBE) ) {
929             tsp->flags = CM_SERVERFLAG_DOWN;    /* assume down; ping will mark up if available */
930             cm_PingServer(tsp);                 /* Obtain Capabilities and check up/down state */
931         }
932     }
933     return tsp;
934 }
935
936 cm_server_t *
937 cm_FindServerByIP(afs_uint32 ipaddr, int type)
938 {
939     cm_server_t *tsp;
940
941     lock_ObtainRead(&cm_serverLock);
942     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
943         if (tsp->type == type &&
944             tsp->addr.sin_addr.S_un.S_addr == ipaddr)
945             break;
946     }
947     lock_ReleaseRead(&cm_serverLock);
948
949     return tsp;
950 }
951
952 /* find a server based on its properties */
953 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type)
954 {
955     cm_server_t *tsp;
956
957     osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
958         
959     lock_ObtainRead(&cm_serverLock);
960     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
961         if (tsp->type == type &&
962             tsp->addr.sin_addr.s_addr == addrp->sin_addr.s_addr) 
963             break;
964     }       
965
966     /* bump ref count if we found the server */
967     if (tsp) 
968         cm_GetServerNoLock(tsp);
969
970     /* drop big table lock */
971     lock_ReleaseRead(&cm_serverLock);
972         
973     /* return what we found */
974     return tsp;
975 }       
976
977 cm_server_vols_t *cm_NewServerVols(void) {
978     cm_server_vols_t *tsvp;
979
980     tsvp = malloc(sizeof(*tsvp));
981     if (tsvp)
982         memset(tsvp, 0, sizeof(*tsvp));
983
984     return tsvp;
985 }
986
987 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
988 {
989     cm_serverRef_t *tsrp;
990     cm_server_vols_t **tsrvpp = NULL;
991     afs_uint32 *slotp = NULL;
992     int found = 0;
993
994     cm_GetServer(serverp);
995     tsrp = malloc(sizeof(*tsrp));
996     tsrp->server = serverp;
997     tsrp->status = srv_not_busy;
998     tsrp->next = NULL;
999     tsrp->volID = volID;
1000     tsrp->refCount = 1;
1001
1002     /* if we have a non-zero volID, we need to add it to the list
1003      * of volumes maintained by the server.  There are two phases:
1004      * (1) see if the volID is already in the list and (2) insert
1005      * it into the first empty slot if it is not.
1006      */
1007     if (volID) {
1008         lock_ObtainMutex(&serverp->mx);
1009
1010         tsrvpp = &serverp->vols;
1011         while (*tsrvpp) {
1012             int i;
1013
1014             for (i=0; i<NUM_SERVER_VOLS; i++) {
1015                 if ((*tsrvpp)->ids[i] == volID) {
1016                     found = 1;
1017                     break;
1018                 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
1019                     slotp = &(*tsrvpp)->ids[i];
1020                 }
1021             }
1022
1023             if (found)
1024                 break;
1025
1026             tsrvpp = &(*tsrvpp)->nextp;
1027         }
1028
1029         if (!found) {
1030             if (slotp) {
1031                 *slotp = volID;
1032             } else {
1033                 /* if we didn't find an empty slot in a current
1034                  * page we must need a new page */
1035                 *tsrvpp = cm_NewServerVols();
1036                 if (*tsrvpp)
1037                     (*tsrvpp)->ids[0] = volID;
1038             }
1039         }
1040
1041         lock_ReleaseMutex(&serverp->mx);
1042     }
1043
1044     return tsrp;
1045 }
1046
1047 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1048 {
1049     LONG_PTR sum = 0;
1050     int first = 1;
1051     cm_serverRef_t *tsrp;
1052
1053     lock_ObtainRead(&cm_serverLock);
1054     for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1055         if (first)
1056             first = 0;
1057         else
1058             sum <<= 1;
1059         sum ^= (LONG_PTR) tsrp->server;
1060     }
1061
1062     lock_ReleaseRead(&cm_serverLock);
1063     return sum;
1064 }
1065
1066 /*
1067 ** Insert a server into the server list keeping the list sorted in 
1068 ** ascending order of ipRank. 
1069 ** 
1070 ** The refCount of the cm_serverRef_t is increased
1071 */
1072 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1073 {
1074     cm_serverRef_t      *current=*list;
1075     unsigned short ipRank = element->server->ipRank;
1076
1077     lock_ObtainWrite(&cm_serverLock);
1078     element->refCount++;                /* increase refCount */
1079
1080     /* insertion into empty list  or at the beginning of the list */
1081     if ( !current || (current->server->ipRank > ipRank) )
1082     {
1083         element->next = *list;
1084         *list = element;
1085         lock_ReleaseWrite(&cm_serverLock);
1086         return ;        
1087     }
1088         
1089     while ( current->next ) /* find appropriate place to insert */
1090     {
1091         if ( current->next->server->ipRank > ipRank )
1092             break;
1093         else current = current->next;
1094     }
1095     element->next = current->next;
1096     current->next = element;
1097     lock_ReleaseWrite(&cm_serverLock);
1098 }       
1099 /*
1100 ** Re-sort the server list with the modified rank
1101 ** returns 0 if element was changed successfully. 
1102 ** returns 1 if  list remained unchanged.
1103 */
1104 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*    server)
1105 {
1106     cm_serverRef_t  **current=list;
1107     cm_serverRef_t      *element=0;
1108
1109     /* if there is max of one element in the list, nothing to sort */
1110     if ( (!*current) || !((*current)->next)  )
1111         return 1;               /* list unchanged: return success */
1112
1113     lock_ObtainWrite(&cm_serverLock);
1114     /* if the server is on the list, delete it from list */
1115     while ( *current )
1116     {
1117         if ( (*current)->server == server)
1118         {
1119             element = (*current);
1120             *current = (*current)->next; /* delete it */
1121             break;
1122         }
1123         current = & ( (*current)->next);        
1124     }
1125     lock_ReleaseWrite(&cm_serverLock);
1126
1127     /* if this volume is not replicated on this server  */
1128     if (!element)
1129         return 1;       /* server is not on list */
1130
1131     /* re-insert deleted element into the list with modified rank*/
1132     cm_InsertServerList(list, element);
1133
1134     /* reduce refCount which was increased by cm_InsertServerList */
1135     lock_ObtainWrite(&cm_serverLock);
1136     element->refCount--;
1137     lock_ReleaseWrite(&cm_serverLock);
1138     return 0;
1139 }
1140 /*
1141 ** If there are more than one server on the list and the first n servers on 
1142 ** the list have the same rank( n>1), then randomise among the first n servers.
1143 */
1144 void cm_RandomizeServer(cm_serverRef_t** list)
1145 {
1146     int                 count, picked;
1147     cm_serverRef_t*     tsrp = *list, *lastTsrp;
1148     unsigned short      lowestRank;
1149
1150     /* an empty list or a list with only one element */
1151     if ( !tsrp || ! tsrp->next )
1152         return ; 
1153
1154     lock_ObtainWrite(&cm_serverLock);
1155
1156     /* count the number of servers with the lowest rank */
1157     lowestRank = tsrp->server->ipRank;
1158     for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
1159     {
1160         if ( tsrp->server->ipRank != lowestRank)
1161             break;
1162         else
1163             count++;
1164     }           
1165
1166     /* if there is only one server with the lowest rank, we are done */
1167     if ( count <= 1 ) {
1168         lock_ReleaseWrite(&cm_serverLock);
1169         return ;
1170     }   
1171
1172     picked = rand() % count;
1173     if ( !picked ) {
1174         lock_ReleaseWrite(&cm_serverLock);
1175         return ;
1176     }   
1177
1178     tsrp = *list;
1179     while (--picked >= 0)
1180     {
1181         lastTsrp = tsrp;
1182         tsrp = tsrp->next;
1183     }
1184     lastTsrp->next = tsrp->next;  /* delete random element from list*/
1185     tsrp->next     = *list; /* insert element at the beginning of list */
1186     *list          = tsrp;
1187     lock_ReleaseWrite(&cm_serverLock);
1188 }       
1189
1190 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1191 void cm_FreeServer(cm_server_t* serverp)
1192 {
1193     cm_server_vols_t * tsrvp, *nextp;
1194
1195     cm_PutServerNoLock(serverp);
1196     if (serverp->refCount == 0)
1197     {
1198         /* we need to check to ensure that all of the connections
1199          * for this server have a 0 refCount; otherwise, they will
1200          * not be garbage collected 
1201          */
1202         cm_GCConnections(serverp);  /* connsp */
1203
1204         if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1205             switch (serverp->type) {
1206             case CM_SERVER_VLDB:
1207                 cm_numVldbServers--;
1208                 break;      
1209             case CM_SERVER_FILE:
1210                 cm_numFileServers--;
1211                 break;
1212             }
1213
1214             lock_FinalizeMutex(&serverp->mx);
1215             if ( cm_allServersp == serverp )
1216                 cm_allServersp = serverp->allNextp;
1217             else {
1218                 cm_server_t *tsp;
1219
1220                 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1221                     if ( tsp->allNextp == serverp ) {
1222                         tsp->allNextp = serverp->allNextp;
1223                         break;
1224                     }
1225                 }
1226             }
1227
1228             /* free the volid list */
1229             for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1230                 nextp = tsrvp->nextp;
1231                 free(tsrvp);
1232             }
1233
1234             free(serverp);
1235         }
1236     }
1237 }
1238
1239 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1240 {
1241     cm_server_vols_t * tsrvp;
1242     int i;
1243
1244     if (volID == 0)
1245         return;
1246
1247     for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1248         for (i=0; i<NUM_SERVER_VOLS; i++) {
1249             if (tsrvp->ids[i] == volID) {
1250                 tsrvp->ids[i] = 0;;
1251                 break;
1252             }
1253         }
1254     }
1255 }
1256
1257 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1258 {
1259     cm_serverRef_t  **current = list;
1260     cm_serverRef_t  **nextp = 0;
1261     cm_serverRef_t  * next = 0;
1262
1263     lock_ObtainWrite(&cm_serverLock);
1264
1265     while (*current)
1266     {
1267         nextp = &(*current)->next;
1268         if (--((*current)->refCount) == 0) {
1269             next = *nextp;
1270
1271             if ((*current)->volID)
1272                 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1273             cm_FreeServer((*current)->server);
1274             free(*current);
1275             *current = next;
1276         } else {
1277             if (flags & CM_FREESERVERLIST_DELETE) {
1278                 (*current)->status = srv_deleted;
1279                 if ((*current)->volID)
1280                     cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1281             }
1282             current = nextp;
1283         }
1284     }
1285   
1286     lock_ReleaseWrite(&cm_serverLock);
1287 }