windows-multi-check-servers-20080207
[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     struct rx_connection **rxconns = NULL;
273     cm_req_t req;
274     afs_int32 i, j, nconns = 0;
275     afs_int32 *conntimer, *results;
276     Capabilities *caps = NULL;
277     cm_server_t ** serversp, *tsp;
278     afs_uint32 isDown, wasDown;
279     afs_uint32 code;
280     time_t start, end, *deltas;
281     afs_int32 secs;
282     afs_int32 usecs;
283     char hoststr[16];
284
285     cm_InitReq(&req);
286
287     j = max(cm_numFileServers,cm_numVldbServers);
288     conns = (cm_conn_t **)malloc(j * sizeof(cm_conn_t *));
289     rxconns = (struct rx_connection **)malloc(j * sizeof(struct rx_connection *));
290     conntimer = (afs_int32 *)malloc(j * sizeof (afs_int32));
291     deltas = (time_t *)malloc(j * sizeof (time_t));
292     results = (afs_int32 *)malloc(j * sizeof (afs_int32));
293     serversp = (cm_server_t **)malloc(j * sizeof(cm_server_t *));
294     caps = (Capabilities *)malloc(j * sizeof(Capabilities));
295
296     memset(caps, 0, j * sizeof(Capabilities));
297
298     if ((flags & CM_FLAG_CHECKFILESERVERS) || 
299         !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
300     {
301         lock_ObtainWrite(&cm_serverLock);
302         nconns = 0;
303         for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
304             if (tsp->type != CM_SERVER_FILE || 
305                 tsp->cellp == NULL ||           /* SetPref only */
306                 cellp && cellp != tsp->cellp)
307                 continue;
308
309             cm_GetServerNoLock(tsp);
310             lock_ReleaseWrite(&cm_serverLock);
311
312             lock_ObtainMutex(&tsp->mx);
313             isDown = tsp->flags & CM_SERVERFLAG_DOWN;
314
315             if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
316                 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
317                    (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
318                 lock_ReleaseMutex(&tsp->mx);
319                 lock_ObtainWrite(&cm_serverLock);
320                 continue;
321             }
322
323             tsp->flags |= CM_SERVERFLAG_PINGING;
324             lock_ReleaseMutex(&tsp->mx);
325
326             serversp[nconns] = tsp;
327             code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
328             if (code) {
329                     lock_ObtainWrite(&cm_serverLock);
330                 cm_PutServerNoLock(tsp);
331                 continue;
332             }
333             lock_ObtainWrite(&cm_serverLock);
334                         rxconns[nconns] = cm_GetRxConn(conns[nconns]);
335             if (conntimer[nconns] = (isDown ? 1 : 0))
336                 rx_SetConnDeadTime(rxconns[nconns], 10);
337
338             nconns++;
339         }
340         lock_ReleaseWrite(&cm_serverLock);
341
342         /* Perform the multi call */
343         start = time(NULL);
344         multi_Rx(rxconns,nconns)
345         {
346             multi_RXAFS_GetCapabilities(&caps[multi_i]);
347             results[multi_i]=multi_error;
348         } multi_End;
349
350
351         /* Process results of servers that support RXAFS_GetCapabilities */
352         for (i=0; i<nconns; i++) {
353             /* Leave the servers that did not support GetCapabilities alone */
354             if (results[i] == RXGEN_OPCODE)
355                 continue;
356
357             if (conntimer[i])
358                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
359             rx_PutConnection(rxconns[i]);
360             cm_PutConn(conns[i]);
361
362             tsp = serversp[i];
363             cm_GCConnections(tsp);
364
365             lock_ObtainMutex(&tsp->mx);
366             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
367
368             if (results[i] >= 0)  {
369                 /* mark server as up */
370                 tsp->flags &= ~CM_SERVERFLAG_DOWN;
371                 tsp->downTime = 0;
372
373                 /* we currently handle 32-bits of capabilities */
374                 if (caps[i].Capabilities_len > 0) {
375                     tsp->capabilities = caps[i].Capabilities_val[0];
376                     free(caps[i].Capabilities_val);
377                     caps[i].Capabilities_len = 0;
378                     caps[i].Capabilities_val = 0;
379                 } else {
380                     tsp->capabilities = 0;
381                 }
382
383                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
384                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
385                           osi_LogSaveString(afsd_logp, hoststr), 
386                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
387                           tsp->capabilities);
388
389                 /* Now update the volume status if necessary */
390                 if (wasDown) {
391                     cm_server_vols_t * tsrvp;
392                     cm_volume_t * volp;
393                     int i;
394
395                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
396                         for (i=0; i<NUM_SERVER_VOLS; i++) {
397                             if (tsrvp->ids[i] != 0) {
398                                 cm_InitReq(&req);
399
400                                 lock_ReleaseMutex(&tsp->mx);
401                                 code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
402                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
403                                 lock_ObtainMutex(&tsp->mx);
404                                 if (code == 0) {
405                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
406                                     cm_PutVolume(volp);
407                                 }
408                             }
409                         }
410                     }
411                 }
412             } else {
413                 /* mark server as down */
414                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
415                     tsp->flags |= CM_SERVERFLAG_DOWN;
416                     tsp->downTime = time(NULL);
417                 }
418                 if (code != VRESTARTING)
419                     cm_ForceNewConnections(tsp);
420
421                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
422                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
423                           osi_LogSaveString(afsd_logp, hoststr), 
424                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
425                           tsp->capabilities);
426
427                 /* Now update the volume status if necessary */
428                 if (!wasDown) {
429                     cm_server_vols_t * tsrvp;
430                     cm_volume_t * volp;
431                     int i;
432
433                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
434                         for (i=0; i<NUM_SERVER_VOLS; i++) {
435                             if (tsrvp->ids[i] != 0) {
436                                 cm_InitReq(&req);
437
438                                 lock_ReleaseMutex(&tsp->mx);
439                                 code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
440                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
441                                 lock_ObtainMutex(&tsp->mx);
442                                 if (code == 0) {
443                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
444                                     cm_PutVolume(volp);
445                                 }
446                             }
447                         }
448                     }
449                 }
450             }
451
452             if (tsp->waitCount == 0)
453                 tsp->flags &= ~CM_SERVERFLAG_PINGING;
454             else 
455                 osi_Wakeup((LONG_PTR)tsp);
456             
457             lock_ReleaseMutex(&tsp->mx);
458
459             cm_PutServer(tsp);
460         }
461
462         /* 
463          * At this point we have handled any responses that did not indicate
464          * that RXAFS_GetCapabilities is not supported.
465          */
466         for ( i=0, j=0; i<nconns; i++) {
467             if (results[i] == RXGEN_OPCODE) {
468                 if (i != j) {
469                     conns[j] = conns[i];
470                     rxconns[j] = rxconns[i];
471                     serversp[j] = serversp[i];
472                 }
473                 j++;
474             }
475         }
476         nconns = j;
477
478         /* Perform the multi call */
479         start = time(NULL);
480         multi_Rx(rxconns,nconns)
481         {
482             secs = usecs = 0;
483             multi_RXAFS_GetTime(&secs, &usecs);
484             end = time(NULL);
485             results[multi_i]=multi_error;
486             if ((start == end) && !multi_error)
487                 deltas[multi_i] = end - secs;
488         } multi_End;
489
490
491         /* Process Results of servers that only support RXAFS_GetTime */
492         for (i=0; i<nconns; i++) {
493             /* Leave the servers that did not support GetCapabilities alone */
494             if (conntimer[i])
495                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
496             rx_PutConnection(rxconns[i]);
497             cm_PutConn(conns[i]);
498
499             tsp = serversp[i];
500             cm_GCConnections(tsp);
501
502             lock_ObtainMutex(&tsp->mx);
503             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
504
505             if (results[i] >= 0)  {
506                 /* mark server as up */
507                 tsp->flags &= ~CM_SERVERFLAG_DOWN;
508                 tsp->downTime = 0;
509                 tsp->capabilities = 0;
510
511                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
512                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
513                           osi_LogSaveString(afsd_logp, hoststr), 
514                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
515                           tsp->capabilities);
516
517                 /* Now update the volume status if necessary */
518                 if (wasDown) {
519                     cm_server_vols_t * tsrvp;
520                     cm_volume_t * volp;
521                     int i;
522
523                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
524                         for (i=0; i<NUM_SERVER_VOLS; i++) {
525                             if (tsrvp->ids[i] != 0) {
526                                 cm_InitReq(&req);
527
528                                 lock_ReleaseMutex(&tsp->mx);
529                                 code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
530                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
531                                 lock_ObtainMutex(&tsp->mx);
532                                 if (code == 0) {
533                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
534                                     cm_PutVolume(volp);
535                                 }
536                             }
537                         }
538                     }
539                 }
540             } else {
541                 /* mark server as down */
542                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
543                     tsp->flags |= CM_SERVERFLAG_DOWN;
544                     tsp->downTime = time(NULL);
545                 }
546                 if (code != VRESTARTING)
547                     cm_ForceNewConnections(tsp);
548
549                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
550                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
551                           osi_LogSaveString(afsd_logp, hoststr), 
552                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
553                           tsp->capabilities);
554
555                 /* Now update the volume status if necessary */
556                 if (!wasDown) {
557                     cm_server_vols_t * tsrvp;
558                     cm_volume_t * volp;
559                     int i;
560
561                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
562                         for (i=0; i<NUM_SERVER_VOLS; i++) {
563                             if (tsrvp->ids[i] != 0) {
564                                 cm_InitReq(&req);
565
566                                 lock_ReleaseMutex(&tsp->mx);
567                                 code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
568                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
569                                 lock_ObtainMutex(&tsp->mx);
570                                 if (code == 0) {
571                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
572                                     cm_PutVolume(volp);
573                                 }
574                             }
575                         }
576                     }
577                 }
578             }
579
580             if (tsp->waitCount == 0)
581                 tsp->flags &= ~CM_SERVERFLAG_PINGING;
582             else 
583                 osi_Wakeup((LONG_PTR)tsp);
584             
585             lock_ReleaseMutex(&tsp->mx);
586
587             cm_PutServer(tsp);
588         }
589     }
590
591     if ((flags & CM_FLAG_CHECKVLDBSERVERS) || 
592         !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
593     {
594         lock_ObtainWrite(&cm_serverLock);
595         nconns = 0;
596         for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
597             if (tsp->type != CM_SERVER_VLDB ||
598                 tsp->cellp == NULL ||           /* SetPref only */
599                 cellp && cellp != tsp->cellp)
600                 continue;
601
602             cm_GetServerNoLock(tsp);
603             lock_ReleaseWrite(&cm_serverLock);
604
605             lock_ObtainMutex(&tsp->mx);
606             isDown = tsp->flags & CM_SERVERFLAG_DOWN;
607
608             if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
609                 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
610                    (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
611                 lock_ReleaseMutex(&tsp->mx);
612                 lock_ObtainWrite(&cm_serverLock);
613                 continue;
614             }
615
616             tsp->flags |= CM_SERVERFLAG_PINGING;
617             lock_ReleaseMutex(&tsp->mx);
618
619             serversp[nconns] = tsp;
620             code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
621             if (code) {
622                     lock_ObtainWrite(&cm_serverLock);
623                 cm_PutServerNoLock(tsp);
624                 continue;
625             }
626             lock_ObtainWrite(&cm_serverLock);
627             rxconns[nconns] = cm_GetRxConn(conns[nconns]);
628             conntimer[nconns] = (isDown ? 1 : 0);
629             if (isDown)
630                 rx_SetConnDeadTime(rxconns[nconns], 10);
631
632             nconns++;
633         }
634         lock_ReleaseWrite(&cm_serverLock);
635
636         /* Perform the multi call */
637         start = time(NULL);
638         multi_Rx(rxconns,nconns)
639         {
640             multi_VL_ProbeServer();
641             results[multi_i]=multi_error;
642         } multi_End;
643
644
645         /* Process results of servers that support RXAFS_GetCapabilities */
646         for (i=0; i<nconns; i++) {
647             if (conntimer[i])
648                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
649             rx_PutConnection(rxconns[i]);
650             cm_PutConn(conns[i]);
651
652             tsp = serversp[i];
653             cm_GCConnections(tsp);
654
655             lock_ObtainMutex(&tsp->mx);
656             wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
657
658             if (results[i] >= 0)  {
659                 /* mark server as up */
660                 tsp->flags &= ~CM_SERVERFLAG_DOWN;
661                 tsp->downTime = 0;
662                 tsp->capabilities = 0;
663
664                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
665                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
666                           osi_LogSaveString(afsd_logp, hoststr), 
667                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
668                           tsp->capabilities);
669
670                 /* Now update the volume status if necessary */
671                 if (wasDown) {
672                     cm_server_vols_t * tsrvp;
673                     cm_volume_t * volp;
674                     int i;
675
676                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
677                         for (i=0; i<NUM_SERVER_VOLS; i++) {
678                             if (tsrvp->ids[i] != 0) {
679                                 cm_InitReq(&req);
680
681                                 lock_ReleaseMutex(&tsp->mx);
682                                 code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
683                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
684                                 lock_ObtainMutex(&tsp->mx);
685                                 if (code == 0) {
686                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
687                                     cm_PutVolume(volp);
688                                 }
689                             }
690                         }
691                     }
692                 }
693             } else {
694                 /* mark server as down */
695                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
696                     tsp->flags |= CM_SERVERFLAG_DOWN;
697                     tsp->downTime = time(NULL);
698                 }
699                 if (code != VRESTARTING)
700                     cm_ForceNewConnections(tsp);
701
702                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
703                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
704                           osi_LogSaveString(afsd_logp, hoststr), 
705                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
706                           tsp->capabilities);
707
708                 /* Now update the volume status if necessary */
709                 if (!wasDown) {
710                     cm_server_vols_t * tsrvp;
711                     cm_volume_t * volp;
712                     int i;
713
714                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
715                         for (i=0; i<NUM_SERVER_VOLS; i++) {
716                             if (tsrvp->ids[i] != 0) {
717                                 cm_InitReq(&req);
718
719                                 lock_ReleaseMutex(&tsp->mx);
720                                 code = cm_GetVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
721                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
722                                 lock_ObtainMutex(&tsp->mx);
723                                 if (code == 0) {
724                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
725                                     cm_PutVolume(volp);
726                                 }
727                             }
728                         }
729                     }
730                 }
731             }
732
733             if (tsp->waitCount == 0)
734                 tsp->flags &= ~CM_SERVERFLAG_PINGING;
735             else 
736                 osi_Wakeup((LONG_PTR)tsp);
737             
738             lock_ReleaseMutex(&tsp->mx);
739
740             cm_PutServer(tsp);
741         }
742     }
743
744     free(conns);
745     free(rxconns);
746     free(conntimer);
747     free(deltas);
748     free(results);
749     free(caps);
750 }
751 #endif /* MULTI_CHECKSERVERS */
752
753 void cm_InitServer(void)
754 {
755     static osi_once_t once;
756         
757     if (osi_Once(&once)) {
758         lock_InitializeRWLock(&cm_serverLock, "cm_serverLock");
759         osi_EndOnce(&once);
760     }
761 }
762
763 void cm_GetServer(cm_server_t *serverp)
764 {
765     lock_ObtainWrite(&cm_serverLock);
766     serverp->refCount++;
767     lock_ReleaseWrite(&cm_serverLock);
768 }
769
770 void cm_GetServerNoLock(cm_server_t *serverp)
771 {
772     serverp->refCount++;
773 }
774
775 void cm_PutServer(cm_server_t *serverp)
776 {
777     lock_ObtainWrite(&cm_serverLock);
778     osi_assertx(serverp->refCount-- > 0, "cm_server_t refCount 0");
779     lock_ReleaseWrite(&cm_serverLock);
780 }
781
782 void cm_PutServerNoLock(cm_server_t *serverp)
783 {
784     osi_assertx(serverp->refCount-- > 0, "cm_server_t refCount 0");
785 }
786
787 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
788 {
789     lock_ObtainMutex(&serverp->mx);
790     if (no64bit)
791         serverp->flags |= CM_SERVERFLAG_NO64BIT;
792     else
793         serverp->flags &= ~CM_SERVERFLAG_NO64BIT;
794     lock_ReleaseMutex(&serverp->mx);
795 }
796
797 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
798 {
799     lock_ObtainMutex(&serverp->mx);
800     if (no)
801         serverp->flags |= CM_SERVERFLAG_NOINLINEBULK;
802     else
803         serverp->flags &= ~CM_SERVERFLAG_NOINLINEBULK;
804     lock_ReleaseMutex(&serverp->mx);
805 }
806
807 void cm_SetServerPrefs(cm_server_t * serverp)
808 {
809     unsigned long       serverAddr;     /* in host byte order */
810     unsigned long       myAddr, myNet, mySubnet;/* in host byte order */
811     unsigned long       netMask;
812     int                 i;
813
814     int cm_noIPAddr;         /* number of client network interfaces */
815     int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
816     int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
817     int cm_NetMtu[CM_MAXINTERFACE_ADDR];    /* client's MTU sizes */
818     int cm_NetFlags[CM_MAXINTERFACE_ADDR];  /* network flags */
819     long code;
820
821     /* get network related info */
822     cm_noIPAddr = CM_MAXINTERFACE_ADDR;
823     code = syscfg_GetIFInfo(&cm_noIPAddr,
824                             cm_IPAddr, cm_SubnetMask,
825                             cm_NetMtu, cm_NetFlags);
826
827     serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
828     serverp->ipRank  = CM_IPRANK_LOW;   /* default setings */
829
830     for ( i=0; i < cm_noIPAddr; i++)
831     {
832         /* loop through all the client's IP address and compare
833         ** each of them against the server's IP address */
834
835         myAddr = cm_IPAddr[i];
836         if ( IN_CLASSA(myAddr) )
837             netMask = IN_CLASSA_NET;
838         else if ( IN_CLASSB(myAddr) )
839             netMask = IN_CLASSB_NET;
840         else if ( IN_CLASSC(myAddr) )
841             netMask = IN_CLASSC_NET;
842         else
843             netMask = 0;
844
845         myNet    =  myAddr & netMask;
846         mySubnet =  myAddr & cm_SubnetMask[i];
847
848         if ( (serverAddr & netMask) == myNet ) 
849         {
850             if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
851             {
852                 if ( serverAddr == myAddr ) 
853                     serverp->ipRank = min(serverp->ipRank,
854                                            CM_IPRANK_TOP);/* same machine */
855                 else serverp->ipRank = min(serverp->ipRank,
856                                             CM_IPRANK_HI); /* same subnet */
857             }
858             else serverp->ipRank = min(serverp->ipRank,CM_IPRANK_MED);
859             /* same net */
860         }       
861         /* random between 0..15*/
862         serverp->ipRank += min(serverp->ipRank, rand() % 0x000f);
863     } /* and of for loop */
864 }
865
866 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afs_uint32 flags) {
867     cm_server_t *tsp;
868
869     osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
870
871     tsp = malloc(sizeof(*tsp));
872     if (tsp) {
873         memset(tsp, 0, sizeof(*tsp));
874         tsp->type = type;
875         tsp->cellp = cellp;
876         tsp->refCount = 1;
877         lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
878         tsp->addr = *socketp;
879
880         cm_SetServerPrefs(tsp); 
881
882         lock_ObtainWrite(&cm_serverLock);       /* get server lock */
883         tsp->allNextp = cm_allServersp;
884         cm_allServersp = tsp;
885
886         switch (type) {
887         case CM_SERVER_VLDB:
888             cm_numVldbServers++;
889             break;      
890         case CM_SERVER_FILE:
891             cm_numFileServers++;
892             break;
893         }
894
895         lock_ReleaseWrite(&cm_serverLock);      /* release server lock */
896
897         if ( !(flags & CM_FLAG_NOPROBE) ) {
898             tsp->flags = CM_SERVERFLAG_DOWN;    /* assume down; ping will mark up if available */
899             cm_PingServer(tsp);                 /* Obtain Capabilities and check up/down state */
900         }
901     }
902     return tsp;
903 }
904
905 cm_server_t *
906 cm_FindServerByIP(afs_uint32 ipaddr, int type)
907 {
908     cm_server_t *tsp;
909
910     lock_ObtainRead(&cm_serverLock);
911     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
912         if (tsp->type == type &&
913             tsp->addr.sin_addr.S_un.S_addr == ipaddr)
914             break;
915     }
916     lock_ReleaseRead(&cm_serverLock);
917
918     return tsp;
919 }
920
921 /* find a server based on its properties */
922 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type)
923 {
924     cm_server_t *tsp;
925
926     osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
927         
928     lock_ObtainWrite(&cm_serverLock);
929     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
930         if (tsp->type == type &&
931             tsp->addr.sin_addr.s_addr == addrp->sin_addr.s_addr) 
932             break;
933     }       
934
935     /* bump ref count if we found the server */
936     if (tsp) 
937         cm_GetServerNoLock(tsp);
938
939     /* drop big table lock */
940     lock_ReleaseWrite(&cm_serverLock);
941         
942     /* return what we found */
943     return tsp;
944 }       
945
946 cm_server_vols_t *cm_NewServerVols(void) {
947     cm_server_vols_t *tsvp;
948
949     tsvp = malloc(sizeof(*tsvp));
950     if (tsvp)
951         memset(tsvp, 0, sizeof(*tsvp));
952
953     return tsvp;
954 }
955
956 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
957 {
958     cm_serverRef_t *tsrp;
959     cm_server_vols_t **tsrvpp = NULL;
960     afs_uint32 *slotp = NULL;
961     int found = 0;
962
963     cm_GetServer(serverp);
964     tsrp = malloc(sizeof(*tsrp));
965     tsrp->server = serverp;
966     tsrp->status = srv_not_busy;
967     tsrp->next = NULL;
968     tsrp->volID = volID;
969     tsrp->refCount = 1;
970
971     /* if we have a non-zero volID, we need to add it to the list
972      * of volumes maintained by the server.  There are two phases:
973      * (1) see if the volID is already in the list and (2) insert
974      * it into the first empty slot if it is not.
975      */
976     if (volID) {
977         lock_ObtainMutex(&serverp->mx);
978
979         tsrvpp = &serverp->vols;
980         while (*tsrvpp) {
981             int i;
982
983             for (i=0; i<NUM_SERVER_VOLS; i++) {
984                 if ((*tsrvpp)->ids[i] == volID) {
985                     found = 1;
986                     break;
987                 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
988                     slotp = &(*tsrvpp)->ids[i];
989                 }
990             }
991
992             if (found)
993                 break;
994
995             tsrvpp = &(*tsrvpp)->nextp;
996         }
997
998         if (!found) {
999             if (slotp) {
1000                 *slotp = volID;
1001             } else {
1002                 /* if we didn't find an empty slot in a current
1003                  * page we must need a new page */
1004                 *tsrvpp = cm_NewServerVols();
1005                 if (*tsrvpp)
1006                     (*tsrvpp)->ids[0] = volID;
1007             }
1008         }
1009
1010         lock_ReleaseMutex(&serverp->mx);
1011     }
1012
1013     return tsrp;
1014 }
1015
1016 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1017 {
1018     LONG_PTR sum = 0;
1019     int first = 1;
1020     cm_serverRef_t *tsrp;
1021
1022     lock_ObtainWrite(&cm_serverLock);
1023     for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1024         if (first)
1025             first = 0;
1026         else
1027             sum <<= 1;
1028         sum ^= (LONG_PTR) tsrp->server;
1029     }
1030
1031     lock_ReleaseWrite(&cm_serverLock);
1032     return sum;
1033 }
1034
1035 /*
1036 ** Insert a server into the server list keeping the list sorted in 
1037 ** asending order of ipRank. 
1038 ** 
1039 ** The refCount of the cm_serverRef_t is increased
1040 */
1041 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1042 {
1043     cm_serverRef_t      *current=*list;
1044     unsigned short ipRank = element->server->ipRank;
1045
1046     lock_ObtainWrite(&cm_serverLock);
1047     element->refCount++;                /* increase refCount */
1048
1049     /* insertion into empty list  or at the beginning of the list */
1050     if ( !current || (current->server->ipRank > ipRank) )
1051     {
1052         element->next = *list;
1053         *list = element;
1054         lock_ReleaseWrite(&cm_serverLock);
1055         return ;        
1056     }
1057         
1058     while ( current->next ) /* find appropriate place to insert */
1059     {
1060         if ( current->next->server->ipRank > ipRank )
1061             break;
1062         else current = current->next;
1063     }
1064     element->next = current->next;
1065     current->next = element;
1066     lock_ReleaseWrite(&cm_serverLock);
1067 }       
1068 /*
1069 ** Re-sort the server list with the modified rank
1070 ** returns 0 if element was changed successfully. 
1071 ** returns 1 if  list remained unchanged.
1072 */
1073 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*    server)
1074 {
1075     cm_serverRef_t  **current=list;
1076     cm_serverRef_t      *element=0;
1077
1078     /* if there is max of one element in the list, nothing to sort */
1079     if ( (!*current) || !((*current)->next)  )
1080         return 1;               /* list unchanged: return success */
1081
1082     lock_ObtainWrite(&cm_serverLock);
1083     /* if the server is on the list, delete it from list */
1084     while ( *current )
1085     {
1086         if ( (*current)->server == server)
1087         {
1088             element = (*current);
1089             *current = (*current)->next; /* delete it */
1090             break;
1091         }
1092         current = & ( (*current)->next);        
1093     }
1094     lock_ReleaseWrite(&cm_serverLock);
1095
1096     /* if this volume is not replicated on this server  */
1097     if (!element)
1098         return 1;       /* server is not on list */
1099
1100     /* re-insert deleted element into the list with modified rank*/
1101     cm_InsertServerList(list, element);
1102
1103     /* reduce refCount which was increased by cm_InsertServerList */
1104     lock_ObtainWrite(&cm_serverLock);
1105     element->refCount--;
1106     lock_ReleaseWrite(&cm_serverLock);
1107     return 0;
1108 }
1109 /*
1110 ** If there are more than one server on the list and the first n servers on 
1111 ** the list have the same rank( n>1), then randomise among the first n servers.
1112 */
1113 void cm_RandomizeServer(cm_serverRef_t** list)
1114 {
1115     int                 count, picked;
1116     cm_serverRef_t*     tsrp = *list, *lastTsrp;
1117     unsigned short      lowestRank;
1118
1119     /* an empty list or a list with only one element */
1120     if ( !tsrp || ! tsrp->next )
1121         return ; 
1122
1123     lock_ObtainWrite(&cm_serverLock);
1124
1125     /* count the number of servers with the lowest rank */
1126     lowestRank = tsrp->server->ipRank;
1127     for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
1128     {
1129         if ( tsrp->server->ipRank != lowestRank)
1130             break;
1131         else
1132             count++;
1133     }           
1134
1135     /* if there is only one server with the lowest rank, we are done */
1136     if ( count <= 1 ) {
1137         lock_ReleaseWrite(&cm_serverLock);
1138         return ;
1139     }   
1140
1141     picked = rand() % count;
1142     if ( !picked ) {
1143         lock_ReleaseWrite(&cm_serverLock);
1144         return ;
1145     }   
1146
1147     tsrp = *list;
1148     while (--picked >= 0)
1149     {
1150         lastTsrp = tsrp;
1151         tsrp = tsrp->next;
1152     }
1153     lastTsrp->next = tsrp->next;  /* delete random element from list*/
1154     tsrp->next     = *list; /* insert element at the beginning of list */
1155     *list          = tsrp;
1156     lock_ReleaseWrite(&cm_serverLock);
1157 }       
1158
1159 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1160 void cm_FreeServer(cm_server_t* serverp)
1161 {
1162     cm_server_vols_t * tsrvp, *nextp;
1163
1164     cm_PutServerNoLock(serverp);
1165     if (serverp->refCount == 0)
1166     {
1167         /* we need to check to ensure that all of the connections
1168          * for this server have a 0 refCount; otherwise, they will
1169          * not be garbage collected 
1170          */
1171         cm_GCConnections(serverp);  /* connsp */
1172
1173         if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1174             switch (serverp->type) {
1175             case CM_SERVER_VLDB:
1176                 cm_numVldbServers--;
1177                 break;      
1178             case CM_SERVER_FILE:
1179                 cm_numFileServers--;
1180                 break;
1181             }
1182
1183             lock_FinalizeMutex(&serverp->mx);
1184             if ( cm_allServersp == serverp )
1185                 cm_allServersp = serverp->allNextp;
1186             else {
1187                 cm_server_t *tsp;
1188
1189                 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1190                     if ( tsp->allNextp == serverp ) {
1191                         tsp->allNextp = serverp->allNextp;
1192                         break;
1193                     }
1194                 }
1195             }
1196
1197             /* free the volid list */
1198             for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1199                 nextp = tsrvp->nextp;
1200                 free(tsrvp);
1201             }
1202
1203             free(serverp);
1204         }
1205     }
1206 }
1207
1208 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1209 {
1210     cm_server_vols_t * tsrvp;
1211     int i;
1212
1213     if (volID == 0)
1214         return;
1215
1216     for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1217         for (i=0; i<NUM_SERVER_VOLS; i++) {
1218             if (tsrvp->ids[i] == volID) {
1219                 tsrvp->ids[i] = 0;;
1220                 break;
1221             }
1222         }
1223     }
1224 }
1225
1226 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1227 {
1228     cm_serverRef_t  **current = list;
1229     cm_serverRef_t  **nextp = 0;
1230     cm_serverRef_t  * next = 0;
1231
1232     lock_ObtainWrite(&cm_serverLock);
1233
1234     while (*current)
1235     {
1236         nextp = &(*current)->next;
1237         if (--((*current)->refCount) == 0) {
1238             next = *nextp;
1239
1240             if ((*current)->volID)
1241                 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1242             cm_FreeServer((*current)->server);
1243             free(*current);
1244             *current = next;
1245         } else {
1246             if (flags & CM_FREESERVERLIST_DELETE) {
1247                 (*current)->status = srv_deleted;
1248                 if ((*current)->volID)
1249                     cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1250             }
1251             current = nextp;
1252         }
1253     }
1254   
1255     lock_ReleaseWrite(&cm_serverLock);
1256 }