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 cm_ServerClearRPCStats(void) {
58 lock_ObtainRead(&cm_serverLock);
59 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
63 rx_ClearPeerRPCStats(opcode_VL_ProbeServer>>32, tsp->addr.sin_addr.s_addr, port);
67 rx_ClearPeerRPCStats(opcode_RXAFS_GetCapabilities>>32, tsp->addr.sin_addr.s_addr, port);
68 rx_ClearPeerRPCStats(opcode_RXAFS_GetTime>>32, tsp->addr.sin_addr.s_addr, port);
72 lock_ReleaseRead(&cm_serverLock);
76 * lock_ObtainMutex must be held prior to calling
80 cm_RankServer(cm_server_t * tsp)
82 afs_int32 code = 0; /* start with "success" */
83 struct rx_debugPeer tpeer;
84 struct rx_peer * rxPeer;
87 afs_uint64 perfRank = 0;
91 int isDown = (tsp->flags & CM_SERVERFLAG_DOWN);
92 void *peerRpcStats = NULL;
93 afs_uint64 opcode = 0;
98 opcode = opcode_VL_ProbeServer;
102 opcode = opcode_RXAFS_GetCapabilities;
108 cm_SetServerIPRank(tsp);
114 * There are three potential components to the ranking:
115 * 1. Any administrative set preference whether it be
116 * via "fs setserverprefs", registry or dns.
118 * 2. Network subnet mask comparison.
120 * 3. Performance data.
122 * If there is an administrative rank, that is the
123 * the primary factor. If not the primary factor
124 * is the network ranking.
127 code = rx_GetLocalPeers(tsp->addr.sin_addr.s_addr, port, &tpeer);
129 peerRpcStats = rx_CopyPeerRPCStats(opcode, tsp->addr.sin_addr.s_addr, port);
130 if (peerRpcStats == NULL && tsp->type == CM_SERVER_FILE)
131 peerRpcStats = rx_CopyPeerRPCStats(opcode_RXAFS_GetTime, tsp->addr.sin_addr.s_addr, port);
133 afs_uint64 execTimeSum = _8THMSEC(RPCOpStat_ExecTimeSum(peerRpcStats));
134 afs_uint64 queueTimeSum = _8THMSEC(RPCOpStat_QTimeSum(peerRpcStats));
135 afs_uint64 numCalls = RPCOpStat_NumCalls(peerRpcStats);
138 rtt = (execTimeSum - queueTimeSum) / numCalls;
140 rx_ReleaseRPCStats(peerRpcStats);
143 if (rtt == 0 && tpeer.rtt) {
150 perfRank += (6000 * log_rtt / 5000) * 5000;
152 if (tsp->type == CM_SERVER_FILE) {
153 /* give an edge to servers with high congestion windows */
154 perfRank -= (tpeer.cwind - 1)* 15;
159 if (tsp->adminRank) {
160 newRank = tsp->adminRank * 0.8;
161 newRank += tsp->ipRank * 0.2;
163 newRank = tsp->ipRank;
167 newRank += perfRank * 0.1;
169 newRank += (rand() & 0x000f); /* randomize */
171 if (newRank > 0xFFFF)
172 osi_Log1(afsd_logp, "new server rank %I64u exceeds 0xFFFF", newRank);
175 * If the ranking changes by more than the randomization
176 * factor, update the server reference lists.
178 if (abs(newRank - tsp->activeRank) > 0xf) {
179 tsp->activeRank = newRank;
181 lock_ReleaseMutex(&tsp->mx);
185 * find volumes which might have RO copy
186 * on server and change the ordering of
189 cm_ChangeRankVolume(tsp);
192 /* set preferences for an existing vlserver */
193 cm_ChangeRankCellVLServer(tsp);
196 lock_ObtainMutex(&tsp->mx);
204 cm_PingServer(cm_server_t *tsp)
209 struct rx_connection * rxconnp;
210 Capabilities caps = {0, 0};
214 lock_ObtainMutex(&tsp->mx);
215 if (tsp->flags & CM_SERVERFLAG_PINGING) {
217 osi_SleepM((LONG_PTR)tsp, &tsp->mx);
218 lock_ObtainMutex(&tsp->mx);
220 if (tsp->waitCount == 0)
221 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
223 osi_Wakeup((LONG_PTR)tsp);
224 lock_ReleaseMutex(&tsp->mx);
227 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
228 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
229 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
230 lock_ReleaseMutex(&tsp->mx);
232 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &connp);
234 /* now call the appropriate ping call. Drop the timeout if
235 * the server is known to be down, so that we don't waste a
236 * lot of time retiming out down servers.
239 osi_Log4(afsd_logp, "cm_PingServer server %s (%s) was %s with caps 0x%x",
240 osi_LogSaveString(afsd_logp, hoststr),
241 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
242 wasDown ? "down" : "up",
245 rxconnp = cm_GetRxConn(connp);
247 rx_SetConnDeadTime(rxconnp, 10);
248 if (tsp->type == CM_SERVER_VLDB) {
249 code = VL_ProbeServer(rxconnp);
253 code = RXAFS_GetCapabilities(rxconnp, &caps);
256 rx_SetConnDeadTime(rxconnp, ConnDeadtimeout);
257 rx_PutConnection(rxconnp);
259 } /* got an unauthenticated connection to this server */
261 lock_ObtainMutex(&tsp->mx);
262 if (code >= 0 || code == RXGEN_OPCODE || code == RX_CALL_BUSY) {
263 /* mark server as up */
264 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
267 /* we currently handle 32-bits of capabilities */
268 if (code != RXGEN_OPCODE && code != RX_CALL_BUSY &&
269 caps.Capabilities_len > 0) {
270 tsp->capabilities = caps.Capabilities_val[0];
271 xdr_free((xdrproc_t) xdr_Capabilities, &caps);
272 caps.Capabilities_len = 0;
273 caps.Capabilities_val = 0;
275 tsp->capabilities = 0;
278 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is up with caps 0x%x",
279 osi_LogSaveString(afsd_logp, hoststr),
280 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
283 /* Now update the volume status if necessary */
285 cm_server_vols_t * tsrvp;
289 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
290 for (i=0; i<NUM_SERVER_VOLS; i++) {
291 if (tsrvp->ids[i] != 0) {
294 lock_ReleaseMutex(&tsp->mx);
295 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
296 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
297 lock_ObtainMutex(&tsp->mx);
299 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
307 /* mark server as down */
308 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
309 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
310 tsp->downTime = time(NULL);
312 if (code != VRESTARTING) {
313 lock_ReleaseMutex(&tsp->mx);
314 cm_ForceNewConnections(tsp);
315 lock_ObtainMutex(&tsp->mx);
317 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
318 osi_LogSaveString(afsd_logp, hoststr),
319 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
322 /* Now update the volume status if necessary */
324 cm_server_vols_t * tsrvp;
328 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
329 for (i=0; i<NUM_SERVER_VOLS; i++) {
330 if (tsrvp->ids[i] != 0) {
333 lock_ReleaseMutex(&tsp->mx);
334 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
335 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
336 lock_ObtainMutex(&tsp->mx);
338 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
347 if (tsp->waitCount == 0)
348 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
350 osi_Wakeup((LONG_PTR)tsp);
351 lock_ReleaseMutex(&tsp->mx);
359 lock_ObtainRead(&cm_serverLock);
360 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
361 cm_GetServerNoLock(tsp);
362 lock_ReleaseRead(&cm_serverLock);
364 lock_ObtainMutex(&tsp->mx);
366 /* if the server is not down, rank the server */
367 if(!(tsp->flags & CM_SERVERFLAG_DOWN))
370 lock_ReleaseMutex(&tsp->mx);
372 lock_ObtainRead(&cm_serverLock);
373 cm_PutServerNoLock(tsp);
375 lock_ReleaseRead(&cm_serverLock);
378 static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
380 /* ping all file servers, up or down, with unauthenticated connection,
381 * to find out whether we have all our callbacks from the server still.
382 * Also, ping down VLDBs.
390 lock_ObtainRead(&cm_serverLock);
391 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
392 cm_GetServerNoLock(tsp);
393 lock_ReleaseRead(&cm_serverLock);
395 /* now process the server */
396 lock_ObtainMutex(&tsp->mx);
399 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
400 isFS = tsp->type == CM_SERVER_FILE;
401 isVLDB = tsp->type == CM_SERVER_VLDB;
403 /* only do the ping if the cell matches the requested cell, or we're
404 * matching all cells (cellp == NULL), and if we've requested to ping
405 * this type of {up, down} servers.
407 if ((cellp == NULL || cellp == tsp->cellp) &&
408 ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
409 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
410 ((!(flags & CM_FLAG_CHECKVLDBSERVERS) ||
411 isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
412 (!(flags & CM_FLAG_CHECKFILESERVERS) ||
413 isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
415 } /* we're supposed to check this up/down server */
416 lock_ReleaseMutex(&tsp->mx);
418 /* at this point, we've adjusted the server state, so do the ping and
424 /* also, run the GC function for connections on all of the
425 * server's connections.
427 cm_GCConnections(tsp);
429 lock_ObtainRead(&cm_serverLock);
430 cm_PutServerNoLock(tsp);
432 lock_ReleaseRead(&cm_serverLock);
435 static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
438 * The goal of this function is to probe simultaneously
439 * probe all of the up/down servers (vldb/file) as
440 * specified by flags in the minimum number of RPCs.
441 * Effectively that means use one multi_RXAFS_GetCapabilities()
442 * followed by possibly one multi_RXAFS_GetTime() and
443 * one multi_VL_ProbeServer().
445 * To make this work we must construct the list of vldb
446 * and file servers that are to be probed as well as the
447 * associated data structures.
450 int srvAddrCount = 0;
451 struct srvAddr **addrs = NULL;
452 cm_conn_t **conns = NULL;
453 struct rx_connection **rxconns = NULL;
455 afs_int32 i, nconns = 0, maxconns;
456 afs_int32 *conntimer, *results;
457 Capabilities *caps = NULL;
458 cm_server_t ** serversp, *tsp;
459 afs_uint32 isDown, wasDown;
465 maxconns = max(cm_numFileServers,cm_numVldbServers);
469 conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
470 rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
471 conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
472 results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
473 serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
474 caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
476 memset(caps, 0, maxconns * sizeof(Capabilities));
478 if ((flags & CM_FLAG_CHECKFILESERVERS) ||
479 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
481 lock_ObtainRead(&cm_serverLock);
482 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
483 if (tsp->type != CM_SERVER_FILE ||
484 tsp->cellp == NULL || /* SetPref only */
485 cellp && cellp != tsp->cellp)
488 cm_GetServerNoLock(tsp);
489 lock_ReleaseRead(&cm_serverLock);
491 lock_ObtainMutex(&tsp->mx);
492 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
494 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
495 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
496 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
497 lock_ReleaseMutex(&tsp->mx);
498 lock_ObtainRead(&cm_serverLock);
499 cm_PutServerNoLock(tsp);
503 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
504 lock_ReleaseMutex(&tsp->mx);
506 serversp[nconns] = tsp;
507 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &conns[nconns]);
509 lock_ObtainRead(&cm_serverLock);
510 cm_PutServerNoLock(tsp);
513 lock_ObtainRead(&cm_serverLock);
514 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
515 if (conntimer[nconns] = (isDown ? 1 : 0))
516 rx_SetConnDeadTime(rxconns[nconns], 10);
520 lock_ReleaseRead(&cm_serverLock);
523 /* Perform the multi call */
525 multi_Rx(rxconns,nconns)
527 multi_RXAFS_GetCapabilities(&caps[multi_i]);
528 results[multi_i]=multi_error;
532 /* Process results of servers that support RXAFS_GetCapabilities */
533 for (i=0; i<nconns; i++) {
535 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
536 rx_PutConnection(rxconns[i]);
537 cm_PutConn(conns[i]);
540 cm_GCConnections(tsp);
542 lock_ObtainMutex(&tsp->mx);
543 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
545 if (results[i] >= 0 || results[i] == RXGEN_OPCODE ||
546 results[i] == RX_CALL_BUSY) {
547 /* mark server as up */
548 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
551 /* we currently handle 32-bits of capabilities */
552 if (results[i] != RXGEN_OPCODE && results[i] != RX_CALL_BUSY &&
553 caps[i].Capabilities_len > 0) {
554 tsp->capabilities = caps[i].Capabilities_val[0];
555 xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
556 caps[i].Capabilities_len = 0;
557 caps[i].Capabilities_val = 0;
559 tsp->capabilities = 0;
562 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
563 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
564 osi_LogSaveString(afsd_logp, hoststr),
565 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
568 /* Now update the volume status if necessary */
570 cm_server_vols_t * tsrvp;
574 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
575 for (i=0; i<NUM_SERVER_VOLS; i++) {
576 if (tsrvp->ids[i] != 0) {
579 lock_ReleaseMutex(&tsp->mx);
580 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
581 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
582 lock_ObtainMutex(&tsp->mx);
584 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
592 /* mark server as down */
593 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
594 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
595 tsp->downTime = time(NULL);
597 if (code != VRESTARTING) {
598 lock_ReleaseMutex(&tsp->mx);
599 cm_ForceNewConnections(tsp);
600 lock_ObtainMutex(&tsp->mx);
602 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
603 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
604 osi_LogSaveString(afsd_logp, hoststr),
605 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
608 /* Now update the volume status if necessary */
610 cm_server_vols_t * tsrvp;
614 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
615 for (i=0; i<NUM_SERVER_VOLS; i++) {
616 if (tsrvp->ids[i] != 0) {
619 lock_ReleaseMutex(&tsp->mx);
620 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
621 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
622 lock_ObtainMutex(&tsp->mx);
624 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
633 if (tsp->waitCount == 0)
634 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
636 osi_Wakeup((LONG_PTR)tsp);
638 lock_ReleaseMutex(&tsp->mx);
644 if ((flags & CM_FLAG_CHECKVLDBSERVERS) ||
645 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
647 lock_ObtainRead(&cm_serverLock);
648 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
649 if (tsp->type != CM_SERVER_VLDB ||
650 tsp->cellp == NULL || /* SetPref only */
651 cellp && cellp != tsp->cellp)
654 cm_GetServerNoLock(tsp);
655 lock_ReleaseRead(&cm_serverLock);
657 lock_ObtainMutex(&tsp->mx);
658 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
660 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
661 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
662 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
663 lock_ReleaseMutex(&tsp->mx);
664 lock_ObtainRead(&cm_serverLock);
665 cm_PutServerNoLock(tsp);
669 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
670 lock_ReleaseMutex(&tsp->mx);
672 serversp[nconns] = tsp;
673 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &conns[nconns]);
675 lock_ObtainRead(&cm_serverLock);
676 cm_PutServerNoLock(tsp);
679 lock_ObtainRead(&cm_serverLock);
680 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
681 conntimer[nconns] = (isDown ? 1 : 0);
683 rx_SetConnDeadTime(rxconns[nconns], 10);
687 lock_ReleaseRead(&cm_serverLock);
690 /* Perform the multi call */
692 multi_Rx(rxconns,nconns)
694 multi_VL_ProbeServer();
695 results[multi_i]=multi_error;
699 /* Process results of servers that support VL_ProbeServer */
700 for (i=0; i<nconns; i++) {
702 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
703 rx_PutConnection(rxconns[i]);
704 cm_PutConn(conns[i]);
707 cm_GCConnections(tsp);
709 lock_ObtainMutex(&tsp->mx);
710 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
712 if (results[i] >= 0 || results[i] == RX_CALL_BUSY) {
713 /* mark server as up */
714 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
716 tsp->capabilities = 0;
718 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
719 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
720 osi_LogSaveString(afsd_logp, hoststr),
721 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
724 /* mark server as down */
725 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
726 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
727 tsp->downTime = time(NULL);
729 if (code != VRESTARTING) {
730 lock_ReleaseMutex(&tsp->mx);
731 cm_ForceNewConnections(tsp);
732 lock_ObtainMutex(&tsp->mx);
734 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
735 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
736 osi_LogSaveString(afsd_logp, hoststr),
737 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
741 if (tsp->waitCount == 0)
742 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
744 osi_Wakeup((LONG_PTR)tsp);
746 lock_ReleaseMutex(&tsp->mx);
760 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
767 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
768 0, KEY_QUERY_VALUE, &parmKey);
769 if (code == ERROR_SUCCESS) {
770 dummyLen = sizeof(multi);
771 code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
772 (BYTE *) &multi, &dummyLen);
773 RegCloseKey (parmKey);
777 cm_CheckServersMulti(flags, cellp);
779 cm_CheckServersSingular(flags, cellp);
782 void cm_InitServer(void)
784 static osi_once_t once;
786 if (osi_Once(&once)) {
787 lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
788 lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
793 /* Protected by cm_syscfgLock (rw) */
794 int cm_noIPAddr; /* number of client network interfaces */
795 int cm_IPAddr[CM_MAXINTERFACE_ADDR]; /* client's IP address in host order */
796 int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
797 int cm_NetMtu[CM_MAXINTERFACE_ADDR]; /* client's MTU sizes */
798 int cm_NetFlags[CM_MAXINTERFACE_ADDR]; /* network flags */
799 int cm_LanAdapterChangeDetected = 1;
801 void cm_SetLanAdapterChangeDetected(void)
803 lock_ObtainWrite(&cm_syscfgLock);
804 cm_LanAdapterChangeDetected = 1;
805 lock_ReleaseWrite(&cm_syscfgLock);
808 void cm_GetServer(cm_server_t *serverp)
810 lock_ObtainRead(&cm_serverLock);
811 InterlockedIncrement(&serverp->refCount);
812 lock_ReleaseRead(&cm_serverLock);
815 void cm_GetServerNoLock(cm_server_t *serverp)
817 InterlockedIncrement(&serverp->refCount);
820 void cm_PutServer(cm_server_t *serverp)
823 lock_ObtainRead(&cm_serverLock);
824 refCount = InterlockedDecrement(&serverp->refCount);
825 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
826 lock_ReleaseRead(&cm_serverLock);
829 void cm_PutServerNoLock(cm_server_t *serverp)
831 afs_int32 refCount = InterlockedDecrement(&serverp->refCount);
832 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
835 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
837 lock_ObtainMutex(&serverp->mx);
839 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NO64BIT);
841 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NO64BIT);
842 lock_ReleaseMutex(&serverp->mx);
845 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
847 lock_ObtainMutex(&serverp->mx);
849 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NOINLINEBULK);
851 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NOINLINEBULK);
852 lock_ReleaseMutex(&serverp->mx);
855 void cm_SetServerIPRank(cm_server_t * serverp)
857 unsigned long serverAddr; /* in host byte order */
858 unsigned long myAddr, myNet, mySubnet;/* in host byte order */
859 unsigned long netMask;
863 lock_ObtainRead(&cm_syscfgLock);
864 if (cm_LanAdapterChangeDetected) {
865 lock_ConvertRToW(&cm_syscfgLock);
866 if (cm_LanAdapterChangeDetected) {
867 /* get network related info */
868 cm_noIPAddr = CM_MAXINTERFACE_ADDR;
869 code = syscfg_GetIFInfo(&cm_noIPAddr,
870 cm_IPAddr, cm_SubnetMask,
871 cm_NetMtu, cm_NetFlags);
872 cm_LanAdapterChangeDetected = 0;
874 lock_ConvertWToR(&cm_syscfgLock);
877 serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
878 serverp->ipRank = CM_IPRANK_LOW; /* default settings */
880 for ( i=0; i < cm_noIPAddr; i++)
882 /* loop through all the client's IP address and compare
883 ** each of them against the server's IP address */
885 myAddr = cm_IPAddr[i];
886 if ( IN_CLASSA(myAddr) )
887 netMask = IN_CLASSA_NET;
888 else if ( IN_CLASSB(myAddr) )
889 netMask = IN_CLASSB_NET;
890 else if ( IN_CLASSC(myAddr) )
891 netMask = IN_CLASSC_NET;
895 myNet = myAddr & netMask;
896 mySubnet = myAddr & cm_SubnetMask[i];
898 if ( (serverAddr & netMask) == myNet )
900 if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
902 if ( serverAddr == myAddr ) {
903 serverp->ipRank = min(serverp->ipRank,
904 CM_IPRANK_TOP);/* same machine */
906 serverp->ipRank = min(serverp->ipRank,
907 CM_IPRANK_HI); /* same subnet */
910 serverp->ipRank = min(serverp->ipRank, CM_IPRANK_MED); /* same net */
913 } /* and of for loop */
914 lock_ReleaseRead(&cm_syscfgLock);
917 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afsUUID *uuidp, afs_uint32 flags) {
920 osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
922 lock_ObtainWrite(&cm_serverLock); /* get server lock */
923 tsp = cm_FindServer(socketp, type, TRUE);
925 /* we might have found a server created by set server prefs */
926 if (uuidp && !afs_uuid_is_nil(uuidp) &&
927 !(tsp->flags & CM_SERVERFLAG_UUID))
930 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
932 lock_ReleaseWrite(&cm_serverLock);
936 tsp = malloc(sizeof(*tsp));
938 memset(tsp, 0, sizeof(*tsp));
941 if (uuidp && !afs_uuid_is_nil(uuidp)) {
943 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
946 lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
947 tsp->addr = *socketp;
949 cm_SetServerIPRank(tsp);
951 tsp->allNextp = cm_allServersp;
952 cm_allServersp = tsp;
963 lock_ReleaseWrite(&cm_serverLock); /* release server lock */
965 if (!(flags & CM_FLAG_NOPROBE) && tsp) {
966 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN); /* assume down; ping will mark up if available */
967 cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
974 cm_FindServerByIP(afs_uint32 ipaddr, unsigned short port, int type, int locked)
979 lock_ObtainRead(&cm_serverLock);
981 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
982 if (tsp->type == type &&
983 tsp->addr.sin_addr.S_un.S_addr == ipaddr &&
984 (tsp->addr.sin_port == port || tsp->addr.sin_port == 0))
988 /* bump ref count if we found the server */
990 cm_GetServerNoLock(tsp);
993 lock_ReleaseRead(&cm_serverLock);
999 cm_FindServerByUuid(afsUUID *serverUuid, int type, int locked)
1004 lock_ObtainRead(&cm_serverLock);
1006 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
1007 if (tsp->type == type && !afs_uuid_equal(&tsp->uuid, serverUuid))
1011 /* bump ref count if we found the server */
1013 cm_GetServerNoLock(tsp);
1016 lock_ReleaseRead(&cm_serverLock);
1021 /* find a server based on its properties */
1022 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type, int locked)
1024 osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
1026 return cm_FindServerByIP(addrp->sin_addr.s_addr, addrp->sin_port, type, locked);
1029 cm_server_vols_t *cm_NewServerVols(void) {
1030 cm_server_vols_t *tsvp;
1032 tsvp = malloc(sizeof(*tsvp));
1034 memset(tsvp, 0, sizeof(*tsvp));
1040 * cm_NewServerRef() returns with the allocated cm_serverRef_t
1041 * with a refCount of 1.
1043 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
1045 cm_serverRef_t *tsrp;
1046 cm_server_vols_t **tsrvpp = NULL;
1047 afs_uint32 *slotp = NULL;
1050 cm_GetServer(serverp);
1051 tsrp = malloc(sizeof(*tsrp));
1052 tsrp->server = serverp;
1053 tsrp->status = srv_not_busy;
1055 tsrp->volID = volID;
1058 /* if we have a non-zero volID, we need to add it to the list
1059 * of volumes maintained by the server. There are two phases:
1060 * (1) see if the volID is already in the list and (2) insert
1061 * it into the first empty slot if it is not.
1064 lock_ObtainMutex(&serverp->mx);
1066 tsrvpp = &serverp->vols;
1070 for (i=0; i<NUM_SERVER_VOLS; i++) {
1071 if ((*tsrvpp)->ids[i] == volID) {
1074 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
1075 slotp = &(*tsrvpp)->ids[i];
1082 tsrvpp = &(*tsrvpp)->nextp;
1089 /* if we didn't find an empty slot in a current
1090 * page we must need a new page */
1091 *tsrvpp = cm_NewServerVols();
1093 (*tsrvpp)->ids[0] = volID;
1097 lock_ReleaseMutex(&serverp->mx);
1103 void cm_GetServerRef(cm_serverRef_t *tsrp, int locked)
1108 lock_ObtainRead(&cm_serverLock);
1109 refCount = InterlockedIncrement(&tsrp->refCount);
1111 lock_ReleaseRead(&cm_serverLock);
1114 afs_int32 cm_PutServerRef(cm_serverRef_t *tsrp, int locked)
1119 lock_ObtainRead(&cm_serverLock);
1120 refCount = InterlockedDecrement(&tsrp->refCount);
1121 osi_assertx(refCount >= 0, "cm_serverRef_t refCount underflow");
1124 lock_ReleaseRead(&cm_serverLock);
1130 cm_ServerListSize(cm_serverRef_t* serversp)
1132 afs_uint32 count = 0;
1133 cm_serverRef_t *tsrp;
1135 lock_ObtainRead(&cm_serverLock);
1136 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1137 if (tsrp->status == srv_deleted)
1141 lock_ReleaseRead(&cm_serverLock);
1145 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1149 cm_serverRef_t *tsrp;
1151 lock_ObtainRead(&cm_serverLock);
1152 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1153 if (tsrp->status == srv_deleted)
1159 sum ^= (LONG_PTR) tsrp->server;
1162 lock_ReleaseRead(&cm_serverLock);
1167 ** Insert a server into the server list keeping the list sorted in
1168 ** ascending order of ipRank.
1170 ** The refCount of the cm_serverRef_t is not altered.
1172 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1174 cm_serverRef_t *current;
1175 unsigned short rank;
1177 lock_ObtainWrite(&cm_serverLock);
1179 * Since we are grabbing the serverLock exclusively remove any
1180 * deleted serverRef objects with a zero refcount before
1181 * inserting the new item.
1184 cm_serverRef_t **currentp = list;
1185 cm_serverRef_t **nextp = NULL;
1186 cm_serverRef_t * next = NULL;
1188 for (currentp = list; *currentp; currentp = nextp)
1190 nextp = &(*currentp)->next;
1191 if ((*currentp)->refCount == 0 &&
1192 (*currentp)->status == srv_deleted) {
1195 if ((*currentp)->volID)
1196 cm_RemoveVolumeFromServer((*currentp)->server, (*currentp)->volID);
1197 cm_FreeServer((*currentp)->server);
1204 /* insertion into empty list or at the beginning of the list */
1207 element->next = NULL;
1213 * Now that deleted entries have been removed and we know that the
1214 * list was not empty, look for duplicates. If the element we are
1215 * inserting already exists, discard it.
1217 for ( current = *list; current; current = current->next)
1219 cm_server_t * server1 = current->server;
1220 cm_server_t * server2 = element->server;
1222 if (current->status == srv_deleted)
1225 if (server1->type != server2->type)
1228 if (server1->addr.sin_addr.s_addr != server2->addr.sin_addr.s_addr)
1231 if ((server1->flags & CM_SERVERFLAG_UUID) != (server2->flags & CM_SERVERFLAG_UUID))
1234 if ((server1->flags & CM_SERVERFLAG_UUID) &&
1235 !afs_uuid_equal(&server1->uuid, &server2->uuid))
1238 /* we must have a match, discard the new element */
1243 rank = element->server->activeRank;
1245 /* insertion at the beginning of the list */
1246 if ((*list)->server->activeRank > rank)
1248 element->next = *list;
1253 /* find appropriate place to insert */
1254 for ( current = *list; current->next; current = current->next)
1256 if ( current->next->server->activeRank > rank )
1259 element->next = current->next;
1260 current->next = element;
1263 lock_ReleaseWrite(&cm_serverLock);
1266 ** Re-sort the server list with the modified rank
1267 ** returns 0 if element was changed successfully.
1268 ** returns 1 if list remained unchanged.
1270 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t* server)
1272 cm_serverRef_t **current;
1273 cm_serverRef_t *element;
1275 lock_ObtainWrite(&cm_serverLock);
1279 /* if there is max of one element in the list, nothing to sort */
1280 if ( (!*current) || !((*current)->next) ) {
1281 lock_ReleaseWrite(&cm_serverLock);
1282 return 1; /* list unchanged: return success */
1285 /* if the server is on the list, delete it from list */
1288 if ( (*current)->server == server)
1290 element = (*current);
1291 *current = element->next; /* delete it */
1294 current = & ( (*current)->next);
1296 lock_ReleaseWrite(&cm_serverLock);
1298 /* if this volume is not replicated on this server */
1300 return 1; /* server is not on list */
1302 /* re-insert deleted element into the list with modified rank*/
1303 cm_InsertServerList(list, element);
1308 ** If there are more than one server on the list and the first n servers on
1309 ** the list have the same rank( n>1), then randomise among the first n servers.
1311 void cm_RandomizeServer(cm_serverRef_t** list)
1314 cm_serverRef_t* tsrp, *lastTsrp;
1315 unsigned short lowestRank;
1317 lock_ObtainWrite(&cm_serverLock);
1320 /* an empty list or a list with only one element */
1321 if ( !tsrp || ! tsrp->next ) {
1322 lock_ReleaseWrite(&cm_serverLock);
1326 /* count the number of servers with the lowest rank */
1327 lowestRank = tsrp->server->activeRank;
1328 for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
1330 if ( tsrp->server->activeRank != lowestRank)
1336 /* if there is only one server with the lowest rank, we are done */
1338 lock_ReleaseWrite(&cm_serverLock);
1342 picked = rand() % count;
1344 lock_ReleaseWrite(&cm_serverLock);
1349 while (--picked >= 0)
1354 lastTsrp->next = tsrp->next; /* delete random element from list*/
1355 tsrp->next = *list; /* insert element at the beginning of list */
1357 lock_ReleaseWrite(&cm_serverLock);
1360 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1361 void cm_FreeServer(cm_server_t* serverp)
1363 cm_server_vols_t * tsrvp, *nextp;
1366 cm_PutServerNoLock(serverp);
1367 if (serverp->refCount == 0)
1370 * we need to check to ensure that all of the connections
1371 * for this server have a 0 refCount; otherwise, they will
1372 * not be garbage collected
1374 * must drop the cm_serverLock because cm_GCConnections
1375 * obtains the cm_connLock and that comes first in the
1378 lock_ReleaseWrite(&cm_serverLock);
1379 cm_GCConnections(serverp); /* connsp */
1380 lock_ObtainWrite(&cm_serverLock);
1385 * Once we have the cm_serverLock locked check to make
1386 * sure the refCount is still zero before removing the
1389 if (serverp->refCount == 0) {
1390 if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1391 switch (serverp->type) {
1392 case CM_SERVER_VLDB:
1393 cm_numVldbServers--;
1395 case CM_SERVER_FILE:
1396 cm_numFileServers--;
1400 lock_FinalizeMutex(&serverp->mx);
1401 if ( cm_allServersp == serverp )
1402 cm_allServersp = serverp->allNextp;
1406 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1407 if ( tsp->allNextp == serverp ) {
1408 tsp->allNextp = serverp->allNextp;
1414 /* free the volid list */
1415 for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1416 nextp = tsrvp->nextp;
1425 /* Called with cm_serverLock write locked */
1426 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1428 cm_server_vols_t * tsrvp;
1434 for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1435 for (i=0; i<NUM_SERVER_VOLS; i++) {
1436 if (tsrvp->ids[i] == volID) {
1444 int cm_IsServerListEmpty(cm_serverRef_t *serversp)
1446 cm_serverRef_t *tsrp;
1449 if (serversp == NULL)
1450 return CM_ERROR_EMPTY;
1452 lock_ObtainRead(&cm_serverLock);
1453 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1454 if (tsrp->status == srv_deleted)
1459 lock_ReleaseRead(&cm_serverLock);
1461 return ( allDeleted ? CM_ERROR_EMPTY : 0 );
1464 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1466 cm_serverRef_t **current;
1467 cm_serverRef_t **nextp;
1468 cm_serverRef_t * next;
1471 lock_ObtainWrite(&cm_serverLock);
1481 nextp = &(*current)->next;
1482 refCount = cm_PutServerRef(*current, TRUE);
1483 if (refCount == 0) {
1486 if ((*current)->volID)
1487 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1488 cm_FreeServer((*current)->server);
1492 if (flags & CM_FREESERVERLIST_DELETE) {
1493 (*current)->status = srv_deleted;
1494 if ((*current)->volID)
1495 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1503 lock_ReleaseWrite(&cm_serverLock);
1506 /* dump all servers to a file.
1507 * cookie is used to identify this batch for easy parsing,
1508 * and it a string provided by a caller
1510 int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
1519 lock_ObtainRead(&cm_serverLock);
1522 "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n",
1523 cookie, cm_numFileServers, cm_numVldbServers);
1524 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1526 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
1531 switch (tsp->type) {
1532 case CM_SERVER_VLDB:
1535 case CM_SERVER_FILE:
1542 afsUUID_to_string(&tsp->uuid, uuidstr, sizeof(uuidstr));
1543 afs_inet_ntoa_r(tsp->addr.sin_addr.s_addr, hoststr);
1544 down = ctime(&tsp->downTime);
1545 down[strlen(down)-1] = '\0';
1548 "%s - tsp=0x%p cell=%s addr=%-15s port=%u uuid=%s type=%s caps=0x%x "
1549 "flags=0x%x waitCount=%u rank=%u downTime=\"%s\" refCount=%u\r\n",
1550 cookie, tsp, tsp->cellp ? tsp->cellp->name : "", hoststr,
1551 ntohs(tsp->addr.sin_port), uuidstr, type,
1552 tsp->capabilities, tsp->flags, tsp->waitCount, tsp->activeRank,
1553 (tsp->flags & CM_SERVERFLAG_DOWN) ? down : "up",
1555 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1557 sprintf(output, "%s - Done dumping servers.\r\n", cookie);
1558 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1561 lock_ReleaseRead(&cm_serverLock);
1567 * Determine if two servers are in fact the same.
1569 * Returns 1 if they match, 0 if they do not
1571 int cm_ServerEqual(cm_server_t *srv1, cm_server_t *srv2)
1575 if (srv1 == NULL || srv2 == NULL)
1581 if (srv1->flags & CM_SERVERFLAG_UUID) {
1582 if (!(srv2->flags & CM_SERVERFLAG_UUID))
1585 /* Both support UUID */
1586 if (UuidEqual((UUID *)&srv1->uuid, (UUID *)&srv2->uuid, &status))
1589 if (srv1->flags & CM_SERVERFLAG_UUID)
1592 /* Neither support UUID so perform an addr/port comparison */
1593 if ( srv1->addr.sin_family == srv2->addr.sin_family &&
1594 srv1->addr.sin_addr.s_addr == srv2->addr.sin_addr.s_addr &&
1595 srv1->addr.sin_port == srv2->addr.sin_port )