2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
24 #include <WINNT\syscfg.h>
25 #include <WINNT/afsreg.h>
30 osi_rwlock_t cm_serverLock;
31 osi_rwlock_t cm_syscfgLock;
33 cm_server_t *cm_allServersp;
34 afs_uint32 cm_numFileServers = 0;
35 afs_uint32 cm_numVldbServers = 0;
38 cm_ForceNewConnectionsAllServers(void)
42 lock_ObtainRead(&cm_serverLock);
43 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
44 cm_GetServerNoLock(tsp);
45 lock_ReleaseRead(&cm_serverLock);
46 cm_ForceNewConnections(tsp);
47 lock_ObtainRead(&cm_serverLock);
48 cm_PutServerNoLock(tsp);
50 lock_ReleaseRead(&cm_serverLock);
54 * lock_ObtainMutex must be held prior to calling
58 cm_RankServer(cm_server_t * tsp)
60 afs_int32 code = 0; /* start with "success" */
61 struct rx_debugPeer tpeer;
76 code = rx_GetLocalPeers(tsp->addr.sin_addr.s_addr, port, &tpeer);
78 /*check if rx_GetLocalPeers succeeded and if there is data for tsp */
79 if(code == 0 && (tpeer.rtt == 0 && tpeer.rtt_dev == 0))
83 if((tsp->flags & CM_SERVERFLAG_PREF_SET))
84 newRank = tsp->adminRank +
85 ((int)(623 * log(tpeer.rtt) / 10) * 10 + 5);
86 else /* rank has not been set by admin, derive rank from rtt */
87 newRank = (int)(7200 * log(tpeer.rtt) / 5000) * 5000 + 5000;
89 newRank += (rand() & 0x000f); /* randomize */
91 if (abs(newRank - tsp->ipRank) > 0xf) {
92 tsp->ipRank = newRank;
94 lock_ReleaseMutex(&tsp->mx);
98 * find volumes which might have RO copy
99 * on server and change the ordering of
102 cm_ChangeRankVolume(tsp);
105 /* set preferences for an existing vlserver */
106 cm_ChangeRankCellVLServer(tsp);
109 lock_ObtainMutex(&tsp->mx);
117 cm_PingServer(cm_server_t *tsp)
122 struct rx_connection * rxconnp;
125 Capabilities caps = {0, 0};
129 lock_ObtainMutex(&tsp->mx);
130 if (tsp->flags & CM_SERVERFLAG_PINGING) {
132 osi_SleepM((LONG_PTR)tsp, &tsp->mx);
133 lock_ObtainMutex(&tsp->mx);
135 if (tsp->waitCount == 0)
136 tsp->flags &= ~CM_SERVERFLAG_PINGING;
138 osi_Wakeup((LONG_PTR)tsp);
139 lock_ReleaseMutex(&tsp->mx);
142 tsp->flags |= CM_SERVERFLAG_PINGING;
143 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
144 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
145 lock_ReleaseMutex(&tsp->mx);
147 code = cm_ConnByServer(tsp, cm_rootUserp, &connp);
149 /* now call the appropriate ping call. Drop the timeout if
150 * the server is known to be down, so that we don't waste a
151 * lot of time retiming out down servers.
154 osi_Log4(afsd_logp, "cm_PingServer server %s (%s) was %s with caps 0x%x",
155 osi_LogSaveString(afsd_logp, hoststr),
156 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
157 wasDown ? "down" : "up",
160 rxconnp = cm_GetRxConn(connp);
162 rx_SetConnDeadTime(rxconnp, 10);
163 if (tsp->type == CM_SERVER_VLDB) {
164 code = VL_ProbeServer(rxconnp);
168 code = RXAFS_GetCapabilities(rxconnp, &caps);
171 rx_SetConnDeadTime(rxconnp, ConnDeadtimeout);
172 rx_PutConnection(rxconnp);
174 } /* got an unauthenticated connection to this server */
176 lock_ObtainMutex(&tsp->mx);
177 if (code >= 0 || code == RXGEN_OPCODE) {
178 /* mark server as up */
179 tsp->flags &= ~CM_SERVERFLAG_DOWN;
182 /* we currently handle 32-bits of capabilities */
183 if (code != RXGEN_OPCODE && caps.Capabilities_len > 0) {
184 tsp->capabilities = caps.Capabilities_val[0];
185 xdr_free((xdrproc_t) xdr_Capabilities, &caps);
186 caps.Capabilities_len = 0;
187 caps.Capabilities_val = 0;
189 tsp->capabilities = 0;
192 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is up with caps 0x%x",
193 osi_LogSaveString(afsd_logp, hoststr),
194 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
197 /* Now update the volume status if necessary */
199 cm_server_vols_t * tsrvp;
203 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
204 for (i=0; i<NUM_SERVER_VOLS; i++) {
205 if (tsrvp->ids[i] != 0) {
208 lock_ReleaseMutex(&tsp->mx);
209 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
210 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
211 lock_ObtainMutex(&tsp->mx);
213 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
221 /* mark server as down */
222 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
223 tsp->flags |= CM_SERVERFLAG_DOWN;
224 tsp->downTime = time(NULL);
226 if (code != VRESTARTING) {
227 lock_ReleaseMutex(&tsp->mx);
228 cm_ForceNewConnections(tsp);
229 lock_ObtainMutex(&tsp->mx);
231 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
232 osi_LogSaveString(afsd_logp, hoststr),
233 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
236 /* Now update the volume status if necessary */
238 cm_server_vols_t * tsrvp;
242 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
243 for (i=0; i<NUM_SERVER_VOLS; i++) {
244 if (tsrvp->ids[i] != 0) {
247 lock_ReleaseMutex(&tsp->mx);
248 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
249 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
250 lock_ObtainMutex(&tsp->mx);
252 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
261 if (tsp->waitCount == 0)
262 tsp->flags &= ~CM_SERVERFLAG_PINGING;
264 osi_Wakeup((LONG_PTR)tsp);
265 lock_ReleaseMutex(&tsp->mx);
273 lock_ObtainRead(&cm_serverLock);
274 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
275 cm_GetServerNoLock(tsp);
276 lock_ReleaseRead(&cm_serverLock);
278 lock_ObtainMutex(&tsp->mx);
280 /* if the server is not down, rank the server */
281 if(!(tsp->flags & CM_SERVERFLAG_DOWN))
284 lock_ReleaseMutex(&tsp->mx);
286 lock_ObtainRead(&cm_serverLock);
287 cm_PutServerNoLock(tsp);
289 lock_ReleaseRead(&cm_serverLock);
292 static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
294 /* ping all file servers, up or down, with unauthenticated connection,
295 * to find out whether we have all our callbacks from the server still.
296 * Also, ping down VLDBs.
304 lock_ObtainRead(&cm_serverLock);
305 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
306 cm_GetServerNoLock(tsp);
307 lock_ReleaseRead(&cm_serverLock);
309 /* now process the server */
310 lock_ObtainMutex(&tsp->mx);
313 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
314 isFS = tsp->type == CM_SERVER_FILE;
315 isVLDB = tsp->type == CM_SERVER_VLDB;
317 /* only do the ping if the cell matches the requested cell, or we're
318 * matching all cells (cellp == NULL), and if we've requested to ping
319 * this type of {up, down} servers.
321 if ((cellp == NULL || cellp == tsp->cellp) &&
322 ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
323 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
324 ((!(flags & CM_FLAG_CHECKVLDBSERVERS) ||
325 isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
326 (!(flags & CM_FLAG_CHECKFILESERVERS) ||
327 isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
329 } /* we're supposed to check this up/down server */
330 lock_ReleaseMutex(&tsp->mx);
332 /* at this point, we've adjusted the server state, so do the ping and
338 /* also, run the GC function for connections on all of the
339 * server's connections.
341 cm_GCConnections(tsp);
343 lock_ObtainRead(&cm_serverLock);
344 cm_PutServerNoLock(tsp);
346 lock_ReleaseRead(&cm_serverLock);
349 static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
352 * The goal of this function is to probe simultaneously
353 * probe all of the up/down servers (vldb/file) as
354 * specified by flags in the minimum number of RPCs.
355 * Effectively that means use one multi_RXAFS_GetCapabilities()
356 * followed by possibly one multi_RXAFS_GetTime() and
357 * one multi_VL_ProbeServer().
359 * To make this work we must construct the list of vldb
360 * and file servers that are to be probed as well as the
361 * associated data structures.
364 int srvAddrCount = 0;
365 struct srvAddr **addrs = NULL;
366 cm_conn_t **conns = NULL;
367 struct rx_connection **rxconns = NULL;
369 afs_int32 i, j, nconns = 0, maxconns;
370 afs_int32 *conntimer, *results;
371 Capabilities *caps = NULL;
372 cm_server_t ** serversp, *tsp;
373 afs_uint32 isDown, wasDown;
375 time_t start, end, *deltas;
381 maxconns = max(cm_numFileServers,cm_numVldbServers);
385 conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
386 rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
387 conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
388 deltas = (time_t *)malloc(maxconns * sizeof (time_t));
389 results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
390 serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
391 caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
393 memset(caps, 0, maxconns * sizeof(Capabilities));
395 if ((flags & CM_FLAG_CHECKFILESERVERS) ||
396 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
398 lock_ObtainRead(&cm_serverLock);
399 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
400 if (tsp->type != CM_SERVER_FILE ||
401 tsp->cellp == NULL || /* SetPref only */
402 cellp && cellp != tsp->cellp)
405 cm_GetServerNoLock(tsp);
406 lock_ReleaseRead(&cm_serverLock);
408 lock_ObtainMutex(&tsp->mx);
409 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
411 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
412 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
413 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
414 lock_ReleaseMutex(&tsp->mx);
415 lock_ObtainRead(&cm_serverLock);
416 cm_PutServerNoLock(tsp);
420 tsp->flags |= CM_SERVERFLAG_PINGING;
421 lock_ReleaseMutex(&tsp->mx);
423 serversp[nconns] = tsp;
424 code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
426 lock_ObtainRead(&cm_serverLock);
427 cm_PutServerNoLock(tsp);
430 lock_ObtainRead(&cm_serverLock);
431 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
432 if (conntimer[nconns] = (isDown ? 1 : 0))
433 rx_SetConnDeadTime(rxconns[nconns], 10);
437 lock_ReleaseRead(&cm_serverLock);
440 /* Perform the multi call */
442 multi_Rx(rxconns,nconns)
444 multi_RXAFS_GetCapabilities(&caps[multi_i]);
445 results[multi_i]=multi_error;
449 /* Process results of servers that support RXAFS_GetCapabilities */
450 for (i=0; i<nconns; i++) {
452 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
453 rx_PutConnection(rxconns[i]);
454 cm_PutConn(conns[i]);
457 cm_GCConnections(tsp);
459 lock_ObtainMutex(&tsp->mx);
460 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
462 if (results[i] >= 0 || results[i] == RXGEN_OPCODE) {
463 /* mark server as up */
464 tsp->flags &= ~CM_SERVERFLAG_DOWN;
467 /* we currently handle 32-bits of capabilities */
468 if (results[i] != RXGEN_OPCODE && caps[i].Capabilities_len > 0) {
469 tsp->capabilities = caps[i].Capabilities_val[0];
470 xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
471 caps[i].Capabilities_len = 0;
472 caps[i].Capabilities_val = 0;
474 tsp->capabilities = 0;
477 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
478 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
479 osi_LogSaveString(afsd_logp, hoststr),
480 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
483 /* Now update the volume status if necessary */
485 cm_server_vols_t * tsrvp;
489 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
490 for (i=0; i<NUM_SERVER_VOLS; i++) {
491 if (tsrvp->ids[i] != 0) {
494 lock_ReleaseMutex(&tsp->mx);
495 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
496 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
497 lock_ObtainMutex(&tsp->mx);
499 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
507 /* mark server as down */
508 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
509 tsp->flags |= CM_SERVERFLAG_DOWN;
510 tsp->downTime = time(NULL);
512 if (code != VRESTARTING) {
513 lock_ReleaseMutex(&tsp->mx);
514 cm_ForceNewConnections(tsp);
515 lock_ObtainMutex(&tsp->mx);
517 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
518 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
519 osi_LogSaveString(afsd_logp, hoststr),
520 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
523 /* Now update the volume status if necessary */
525 cm_server_vols_t * tsrvp;
529 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
530 for (i=0; i<NUM_SERVER_VOLS; i++) {
531 if (tsrvp->ids[i] != 0) {
534 lock_ReleaseMutex(&tsp->mx);
535 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
536 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
537 lock_ObtainMutex(&tsp->mx);
539 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
548 if (tsp->waitCount == 0)
549 tsp->flags &= ~CM_SERVERFLAG_PINGING;
551 osi_Wakeup((LONG_PTR)tsp);
553 lock_ReleaseMutex(&tsp->mx);
559 if ((flags & CM_FLAG_CHECKVLDBSERVERS) ||
560 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
562 lock_ObtainRead(&cm_serverLock);
563 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
564 if (tsp->type != CM_SERVER_VLDB ||
565 tsp->cellp == NULL || /* SetPref only */
566 cellp && cellp != tsp->cellp)
569 cm_GetServerNoLock(tsp);
570 lock_ReleaseRead(&cm_serverLock);
572 lock_ObtainMutex(&tsp->mx);
573 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
575 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
576 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
577 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
578 lock_ReleaseMutex(&tsp->mx);
579 lock_ObtainRead(&cm_serverLock);
580 cm_PutServerNoLock(tsp);
584 tsp->flags |= CM_SERVERFLAG_PINGING;
585 lock_ReleaseMutex(&tsp->mx);
587 serversp[nconns] = tsp;
588 code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
590 lock_ObtainRead(&cm_serverLock);
591 cm_PutServerNoLock(tsp);
594 lock_ObtainRead(&cm_serverLock);
595 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
596 conntimer[nconns] = (isDown ? 1 : 0);
598 rx_SetConnDeadTime(rxconns[nconns], 10);
602 lock_ReleaseRead(&cm_serverLock);
605 /* Perform the multi call */
607 multi_Rx(rxconns,nconns)
609 multi_VL_ProbeServer();
610 results[multi_i]=multi_error;
614 /* Process results of servers that support VL_ProbeServer */
615 for (i=0; i<nconns; i++) {
617 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
618 rx_PutConnection(rxconns[i]);
619 cm_PutConn(conns[i]);
622 cm_GCConnections(tsp);
624 lock_ObtainMutex(&tsp->mx);
625 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
627 if (results[i] >= 0) {
628 /* mark server as up */
629 tsp->flags &= ~CM_SERVERFLAG_DOWN;
631 tsp->capabilities = 0;
633 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
634 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
635 osi_LogSaveString(afsd_logp, hoststr),
636 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
639 /* mark server as down */
640 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
641 tsp->flags |= CM_SERVERFLAG_DOWN;
642 tsp->downTime = time(NULL);
644 if (code != VRESTARTING) {
645 lock_ReleaseMutex(&tsp->mx);
646 cm_ForceNewConnections(tsp);
647 lock_ObtainMutex(&tsp->mx);
649 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
650 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
651 osi_LogSaveString(afsd_logp, hoststr),
652 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
656 if (tsp->waitCount == 0)
657 tsp->flags &= ~CM_SERVERFLAG_PINGING;
659 osi_Wakeup((LONG_PTR)tsp);
661 lock_ReleaseMutex(&tsp->mx);
676 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
683 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
684 0, KEY_QUERY_VALUE, &parmKey);
685 if (code == ERROR_SUCCESS) {
686 dummyLen = sizeof(multi);
687 code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
688 (BYTE *) &multi, &dummyLen);
689 RegCloseKey (parmKey);
693 cm_CheckServersMulti(flags, cellp);
695 cm_CheckServersSingular(flags, cellp);
698 void cm_InitServer(void)
700 static osi_once_t once;
702 if (osi_Once(&once)) {
703 lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
704 lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
709 /* Protected by cm_syscfgLock (rw) */
710 int cm_noIPAddr; /* number of client network interfaces */
711 int cm_IPAddr[CM_MAXINTERFACE_ADDR]; /* client's IP address in host order */
712 int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
713 int cm_NetMtu[CM_MAXINTERFACE_ADDR]; /* client's MTU sizes */
714 int cm_NetFlags[CM_MAXINTERFACE_ADDR]; /* network flags */
715 int cm_LanAdapterChangeDetected = 1;
717 void cm_SetLanAdapterChangeDetected(void)
719 lock_ObtainWrite(&cm_syscfgLock);
720 cm_LanAdapterChangeDetected = 1;
721 lock_ReleaseWrite(&cm_syscfgLock);
724 void cm_GetServer(cm_server_t *serverp)
726 lock_ObtainRead(&cm_serverLock);
727 InterlockedIncrement(&serverp->refCount);
728 lock_ReleaseRead(&cm_serverLock);
731 void cm_GetServerNoLock(cm_server_t *serverp)
733 InterlockedIncrement(&serverp->refCount);
736 void cm_PutServer(cm_server_t *serverp)
739 lock_ObtainRead(&cm_serverLock);
740 refCount = InterlockedDecrement(&serverp->refCount);
741 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
742 lock_ReleaseRead(&cm_serverLock);
745 void cm_PutServerNoLock(cm_server_t *serverp)
747 afs_int32 refCount = InterlockedDecrement(&serverp->refCount);
748 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
751 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
753 lock_ObtainMutex(&serverp->mx);
755 serverp->flags |= CM_SERVERFLAG_NO64BIT;
757 serverp->flags &= ~CM_SERVERFLAG_NO64BIT;
758 lock_ReleaseMutex(&serverp->mx);
761 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
763 lock_ObtainMutex(&serverp->mx);
765 serverp->flags |= CM_SERVERFLAG_NOINLINEBULK;
767 serverp->flags &= ~CM_SERVERFLAG_NOINLINEBULK;
768 lock_ReleaseMutex(&serverp->mx);
771 void cm_SetServerPrefs(cm_server_t * serverp)
773 unsigned long serverAddr; /* in host byte order */
774 unsigned long myAddr, myNet, mySubnet;/* in host byte order */
775 unsigned long netMask;
780 lock_ObtainRead(&cm_syscfgLock);
781 if (cm_LanAdapterChangeDetected) {
782 lock_ConvertRToW(&cm_syscfgLock);
784 if (cm_LanAdapterChangeDetected) {
785 /* get network related info */
786 cm_noIPAddr = CM_MAXINTERFACE_ADDR;
787 code = syscfg_GetIFInfo(&cm_noIPAddr,
788 cm_IPAddr, cm_SubnetMask,
789 cm_NetMtu, cm_NetFlags);
790 cm_LanAdapterChangeDetected = 0;
792 lock_ConvertWToR(&cm_syscfgLock);
795 serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
796 serverp->ipRank = CM_IPRANK_LOW; /* default settings */
798 for ( i=0; i < cm_noIPAddr; i++)
800 /* loop through all the client's IP address and compare
801 ** each of them against the server's IP address */
803 myAddr = cm_IPAddr[i];
804 if ( IN_CLASSA(myAddr) )
805 netMask = IN_CLASSA_NET;
806 else if ( IN_CLASSB(myAddr) )
807 netMask = IN_CLASSB_NET;
808 else if ( IN_CLASSC(myAddr) )
809 netMask = IN_CLASSC_NET;
813 myNet = myAddr & netMask;
814 mySubnet = myAddr & cm_SubnetMask[i];
816 if ( (serverAddr & netMask) == myNet )
818 if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
820 if ( serverAddr == myAddr )
821 serverp->ipRank = min(serverp->ipRank,
822 CM_IPRANK_TOP);/* same machine */
823 else serverp->ipRank = min(serverp->ipRank,
824 CM_IPRANK_HI); /* same subnet */
826 else serverp->ipRank = min(serverp->ipRank,CM_IPRANK_MED);
829 } /* and of for loop */
831 /* random between 0..15*/
832 serverp->ipRank += (rand() % 0x000f);
833 lock_ReleaseRead(&cm_syscfgLock);
836 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afsUUID *uuidp, afs_uint32 flags) {
839 osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
841 tsp = malloc(sizeof(*tsp));
843 memset(tsp, 0, sizeof(*tsp));
846 if (uuidp && !afs_uuid_is_nil(uuidp)) {
848 tsp->flags |= CM_SERVERFLAG_UUID;
851 lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
852 tsp->addr = *socketp;
854 cm_SetServerPrefs(tsp);
856 lock_ObtainWrite(&cm_serverLock); /* get server lock */
857 tsp->allNextp = cm_allServersp;
858 cm_allServersp = tsp;
869 lock_ReleaseWrite(&cm_serverLock); /* release server lock */
871 if ( !(flags & CM_FLAG_NOPROBE) ) {
872 tsp->flags |= CM_SERVERFLAG_DOWN; /* assume down; ping will mark up if available */
873 cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
880 cm_FindServerByIP(afs_uint32 ipaddr, unsigned short port, int type)
884 lock_ObtainRead(&cm_serverLock);
885 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
886 if (tsp->type == type &&
887 tsp->addr.sin_addr.S_un.S_addr == ipaddr &&
888 (tsp->addr.sin_port == port || tsp->addr.sin_port == 0))
892 /* bump ref count if we found the server */
894 cm_GetServerNoLock(tsp);
896 lock_ReleaseRead(&cm_serverLock);
902 cm_FindServerByUuid(afsUUID *serverUuid, int type)
906 lock_ObtainRead(&cm_serverLock);
907 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
908 if (tsp->type == type && !afs_uuid_equal(&tsp->uuid, serverUuid))
912 /* bump ref count if we found the server */
914 cm_GetServerNoLock(tsp);
916 lock_ReleaseRead(&cm_serverLock);
921 /* find a server based on its properties */
922 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type)
926 osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
928 lock_ObtainRead(&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 (tsp->addr.sin_port == addrp->sin_port || tsp->addr.sin_port == 0))
936 /* bump ref count if we found the server */
938 cm_GetServerNoLock(tsp);
940 /* drop big table lock */
941 lock_ReleaseRead(&cm_serverLock);
943 /* return what we found */
947 cm_server_vols_t *cm_NewServerVols(void) {
948 cm_server_vols_t *tsvp;
950 tsvp = malloc(sizeof(*tsvp));
952 memset(tsvp, 0, sizeof(*tsvp));
957 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
959 cm_serverRef_t *tsrp;
960 cm_server_vols_t **tsrvpp = NULL;
961 afs_uint32 *slotp = NULL;
964 cm_GetServer(serverp);
965 tsrp = malloc(sizeof(*tsrp));
966 tsrp->server = serverp;
967 tsrp->status = srv_not_busy;
972 /* if we have a non-zero volID, we need to add it to the list
973 * of volumes maintained by the server. There are two phases:
974 * (1) see if the volID is already in the list and (2) insert
975 * it into the first empty slot if it is not.
978 lock_ObtainMutex(&serverp->mx);
980 tsrvpp = &serverp->vols;
984 for (i=0; i<NUM_SERVER_VOLS; i++) {
985 if ((*tsrvpp)->ids[i] == volID) {
988 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
989 slotp = &(*tsrvpp)->ids[i];
996 tsrvpp = &(*tsrvpp)->nextp;
1003 /* if we didn't find an empty slot in a current
1004 * page we must need a new page */
1005 *tsrvpp = cm_NewServerVols();
1007 (*tsrvpp)->ids[0] = volID;
1011 lock_ReleaseMutex(&serverp->mx);
1017 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1021 cm_serverRef_t *tsrp;
1023 lock_ObtainRead(&cm_serverLock);
1024 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1025 if (tsrp->status == srv_deleted)
1031 sum ^= (LONG_PTR) tsrp->server;
1034 lock_ReleaseRead(&cm_serverLock);
1039 ** Insert a server into the server list keeping the list sorted in
1040 ** ascending order of ipRank.
1042 ** The refCount of the cm_serverRef_t is increased
1044 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1046 cm_serverRef_t *current=*list;
1047 unsigned short ipRank = element->server->ipRank;
1049 lock_ObtainWrite(&cm_serverLock);
1050 element->refCount++; /* increase refCount */
1052 /* insertion into empty list or at the beginning of the list */
1053 if ( !current || (current->server->ipRank > ipRank) )
1055 element->next = *list;
1057 lock_ReleaseWrite(&cm_serverLock);
1061 while ( current->next ) /* find appropriate place to insert */
1063 if ( current->next->server->ipRank > ipRank )
1065 else current = current->next;
1067 element->next = current->next;
1068 current->next = element;
1069 lock_ReleaseWrite(&cm_serverLock);
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.
1076 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t* server)
1078 cm_serverRef_t **current=list;
1079 cm_serverRef_t *element=0;
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 */
1085 lock_ObtainWrite(&cm_serverLock);
1086 /* if the server is on the list, delete it from list */
1089 if ( (*current)->server == server)
1091 element = (*current);
1092 *current = (*current)->next; /* delete it */
1095 current = & ( (*current)->next);
1097 lock_ReleaseWrite(&cm_serverLock);
1099 /* if this volume is not replicated on this server */
1101 return 1; /* server is not on list */
1103 /* re-insert deleted element into the list with modified rank*/
1104 cm_InsertServerList(list, element);
1106 /* reduce refCount which was increased by cm_InsertServerList */
1107 lock_ObtainWrite(&cm_serverLock);
1108 element->refCount--;
1109 lock_ReleaseWrite(&cm_serverLock);
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.
1116 void cm_RandomizeServer(cm_serverRef_t** list)
1119 cm_serverRef_t* tsrp = *list, *lastTsrp;
1120 unsigned short lowestRank;
1122 /* an empty list or a list with only one element */
1123 if ( !tsrp || ! tsrp->next )
1126 lock_ObtainWrite(&cm_serverLock);
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)
1132 if ( tsrp->server->ipRank != lowestRank)
1138 /* if there is only one server with the lowest rank, we are done */
1140 lock_ReleaseWrite(&cm_serverLock);
1144 picked = rand() % count;
1146 lock_ReleaseWrite(&cm_serverLock);
1151 while (--picked >= 0)
1156 lastTsrp->next = tsrp->next; /* delete random element from list*/
1157 tsrp->next = *list; /* insert element at the beginning of list */
1159 lock_ReleaseWrite(&cm_serverLock);
1162 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1163 void cm_FreeServer(cm_server_t* serverp)
1165 cm_server_vols_t * tsrvp, *nextp;
1168 cm_PutServerNoLock(serverp);
1169 if (serverp->refCount == 0)
1172 * we need to check to ensure that all of the connections
1173 * for this server have a 0 refCount; otherwise, they will
1174 * not be garbage collected
1176 * must drop the cm_serverLock because cm_GCConnections
1177 * obtains the cm_connLock and that comes first in the
1180 lock_ReleaseWrite(&cm_serverLock);
1181 cm_GCConnections(serverp); /* connsp */
1182 lock_ObtainWrite(&cm_serverLock);
1187 * Once we have the cm_serverLock locked check to make
1188 * sure the refCount is still zero before removing the
1191 if (serverp->refCount == 0) {
1192 if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1193 switch (serverp->type) {
1194 case CM_SERVER_VLDB:
1195 cm_numVldbServers--;
1197 case CM_SERVER_FILE:
1198 cm_numFileServers--;
1202 lock_FinalizeMutex(&serverp->mx);
1203 if ( cm_allServersp == serverp )
1204 cm_allServersp = serverp->allNextp;
1208 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1209 if ( tsp->allNextp == serverp ) {
1210 tsp->allNextp = serverp->allNextp;
1216 /* free the volid list */
1217 for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1218 nextp = tsrvp->nextp;
1227 /* Called with cm_serverLock write locked */
1228 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1230 cm_server_vols_t * tsrvp;
1236 for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1237 for (i=0; i<NUM_SERVER_VOLS; i++) {
1238 if (tsrvp->ids[i] == volID) {
1246 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1248 cm_serverRef_t **current = list;
1249 cm_serverRef_t **nextp = 0;
1250 cm_serverRef_t * next = 0;
1252 lock_ObtainWrite(&cm_serverLock);
1259 nextp = &(*current)->next;
1260 if (--((*current)->refCount) == 0) {
1263 if ((*current)->volID)
1264 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1265 cm_FreeServer((*current)->server);
1269 if (flags & CM_FREESERVERLIST_DELETE) {
1270 (*current)->status = srv_deleted;
1271 if ((*current)->volID)
1272 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1280 lock_ReleaseWrite(&cm_serverLock);
1283 /* dump all servers to a file.
1284 * cookie is used to identify this batch for easy parsing,
1285 * and it a string provided by a caller
1287 int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
1296 lock_ObtainRead(&cm_serverLock);
1299 "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n",
1300 cookie, cm_numFileServers, cm_numVldbServers);
1301 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1303 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
1308 switch (tsp->type) {
1309 case CM_SERVER_VLDB:
1312 case CM_SERVER_FILE:
1319 afsUUID_to_string(&tsp->uuid, uuidstr, sizeof(uuidstr));
1320 afs_inet_ntoa_r(tsp->addr.sin_addr.s_addr, hoststr);
1321 down = ctime(&tsp->downTime);
1322 down[strlen(down)-1] = '\0';
1325 "%s - tsp=0x%p cell=%s addr=%-15s port=%u uuid=%s type=%s caps=0x%x "
1326 "flags=0x%x waitCount=%u rank=%u downTime=\"%s\" refCount=%u\r\n",
1327 cookie, tsp, tsp->cellp ? tsp->cellp->name : "", hoststr,
1328 ntohs(tsp->addr.sin_port), uuidstr, type,
1329 tsp->capabilities, tsp->flags, tsp->waitCount, tsp->ipRank,
1330 (tsp->flags & CM_SERVERFLAG_DOWN) ? down : "up",
1332 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1334 sprintf(output, "%s - Done dumping servers.\r\n", cookie);
1335 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1338 lock_ReleaseRead(&cm_serverLock);
1344 * Determine if two servers are in fact the same.
1346 * Returns 1 if they match, 0 if they do not
1348 int cm_ServerEqual(cm_server_t *srv1, cm_server_t *srv2)
1352 if (srv1 == NULL || srv2 == NULL)
1358 if (srv1->flags & CM_SERVERFLAG_UUID) {
1359 if (!(srv2->flags & CM_SERVERFLAG_UUID))
1362 /* Both support UUID */
1363 if (UuidEqual((UUID *)&srv1->uuid, (UUID *)&srv2->uuid, &status))