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