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