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