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