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]);
308 /* mark server as down */
309 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
310 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
311 tsp->downTime = time(NULL);
313 if (code != VRESTARTING) {
314 lock_ReleaseMutex(&tsp->mx);
315 cm_ForceNewConnections(tsp);
316 lock_ObtainMutex(&tsp->mx);
318 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
319 osi_LogSaveString(afsd_logp, hoststr),
320 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
323 /* Now update the volume status if necessary */
325 cm_server_vols_t * tsrvp;
329 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
330 for (i=0; i<NUM_SERVER_VOLS; i++) {
331 if (tsrvp->ids[i] != 0) {
334 lock_ReleaseMutex(&tsp->mx);
335 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
336 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
337 lock_ObtainMutex(&tsp->mx);
339 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
349 if (tsp->waitCount == 0)
350 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
352 osi_Wakeup((LONG_PTR)tsp);
353 lock_ReleaseMutex(&tsp->mx);
361 lock_ObtainRead(&cm_serverLock);
362 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
363 cm_GetServerNoLock(tsp);
364 lock_ReleaseRead(&cm_serverLock);
366 lock_ObtainMutex(&tsp->mx);
368 /* if the server is not down, rank the server */
369 if(!(tsp->flags & CM_SERVERFLAG_DOWN))
372 lock_ReleaseMutex(&tsp->mx);
374 lock_ObtainRead(&cm_serverLock);
375 cm_PutServerNoLock(tsp);
377 lock_ReleaseRead(&cm_serverLock);
380 static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
382 /* ping all file servers, up or down, with unauthenticated connection,
383 * to find out whether we have all our callbacks from the server still.
384 * Also, ping down VLDBs.
392 lock_ObtainRead(&cm_serverLock);
393 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
394 cm_GetServerNoLock(tsp);
395 lock_ReleaseRead(&cm_serverLock);
397 /* now process the server */
398 lock_ObtainMutex(&tsp->mx);
401 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
402 isFS = tsp->type == CM_SERVER_FILE;
403 isVLDB = tsp->type == CM_SERVER_VLDB;
405 /* only do the ping if the cell matches the requested cell, or we're
406 * matching all cells (cellp == NULL), and if we've requested to ping
407 * this type of {up, down} servers.
409 if ((cellp == NULL || cellp == tsp->cellp) &&
410 ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
411 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
412 ((!(flags & CM_FLAG_CHECKVLDBSERVERS) ||
413 isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
414 (!(flags & CM_FLAG_CHECKFILESERVERS) ||
415 isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
417 } /* we're supposed to check this up/down server */
418 lock_ReleaseMutex(&tsp->mx);
420 /* at this point, we've adjusted the server state, so do the ping and
426 /* also, run the GC function for connections on all of the
427 * server's connections.
429 cm_GCConnections(tsp);
431 lock_ObtainRead(&cm_serverLock);
432 cm_PutServerNoLock(tsp);
434 lock_ReleaseRead(&cm_serverLock);
437 static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
440 * The goal of this function is to probe simultaneously
441 * probe all of the up/down servers (vldb/file) as
442 * specified by flags in the minimum number of RPCs.
443 * Effectively that means use one multi_RXAFS_GetCapabilities()
444 * followed by possibly one multi_RXAFS_GetTime() and
445 * one multi_VL_ProbeServer().
447 * To make this work we must construct the list of vldb
448 * and file servers that are to be probed as well as the
449 * associated data structures.
452 int srvAddrCount = 0;
453 struct srvAddr **addrs = NULL;
454 cm_conn_t **conns = NULL;
455 struct rx_connection **rxconns = NULL;
457 afs_int32 i, nconns = 0, maxconns;
458 afs_int32 *conntimer, *results;
459 Capabilities *caps = NULL;
460 cm_server_t ** serversp, *tsp;
461 afs_uint32 isDown, wasDown;
467 maxconns = max(cm_numFileServers,cm_numVldbServers);
471 conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
472 rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
473 conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
474 results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
475 serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
476 caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
478 memset(caps, 0, maxconns * sizeof(Capabilities));
480 if ((flags & CM_FLAG_CHECKFILESERVERS) ||
481 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
483 lock_ObtainRead(&cm_serverLock);
484 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
485 if (tsp->type != CM_SERVER_FILE ||
486 tsp->cellp == NULL || /* SetPref only */
487 cellp && cellp != tsp->cellp)
490 cm_GetServerNoLock(tsp);
491 lock_ReleaseRead(&cm_serverLock);
493 lock_ObtainMutex(&tsp->mx);
494 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
496 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
497 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
498 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
499 lock_ReleaseMutex(&tsp->mx);
500 lock_ObtainRead(&cm_serverLock);
501 cm_PutServerNoLock(tsp);
505 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
506 lock_ReleaseMutex(&tsp->mx);
508 serversp[nconns] = tsp;
509 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &conns[nconns]);
511 lock_ObtainRead(&cm_serverLock);
512 cm_PutServerNoLock(tsp);
515 lock_ObtainRead(&cm_serverLock);
516 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
517 if (conntimer[nconns] = (isDown ? 1 : 0))
518 rx_SetConnDeadTime(rxconns[nconns], 10);
522 lock_ReleaseRead(&cm_serverLock);
525 /* Perform the multi call */
527 multi_Rx(rxconns,nconns)
529 multi_RXAFS_GetCapabilities(&caps[multi_i]);
530 results[multi_i]=multi_error;
534 /* Process results of servers that support RXAFS_GetCapabilities */
535 for (i=0; i<nconns; i++) {
537 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
538 rx_PutConnection(rxconns[i]);
539 cm_PutConn(conns[i]);
542 cm_GCConnections(tsp);
544 lock_ObtainMutex(&tsp->mx);
545 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
547 if (results[i] >= 0 || results[i] == RXGEN_OPCODE ||
548 results[i] == RX_CALL_BUSY) {
549 /* mark server as up */
550 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
553 /* we currently handle 32-bits of capabilities */
554 if (results[i] != RXGEN_OPCODE && results[i] != RX_CALL_BUSY &&
555 caps[i].Capabilities_len > 0) {
556 tsp->capabilities = caps[i].Capabilities_val[0];
557 xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
558 caps[i].Capabilities_len = 0;
559 caps[i].Capabilities_val = 0;
561 tsp->capabilities = 0;
564 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
565 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
566 osi_LogSaveString(afsd_logp, hoststr),
567 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
570 /* Now update the volume status if necessary */
572 cm_server_vols_t * tsrvp;
576 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
577 for (i=0; i<NUM_SERVER_VOLS; i++) {
578 if (tsrvp->ids[i] != 0) {
581 lock_ReleaseMutex(&tsp->mx);
582 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
583 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
584 lock_ObtainMutex(&tsp->mx);
586 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
595 /* mark server as down */
596 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
597 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
598 tsp->downTime = time(NULL);
600 if (code != VRESTARTING) {
601 lock_ReleaseMutex(&tsp->mx);
602 cm_ForceNewConnections(tsp);
603 lock_ObtainMutex(&tsp->mx);
605 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
606 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
607 osi_LogSaveString(afsd_logp, hoststr),
608 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
611 /* Now update the volume status if necessary */
613 cm_server_vols_t * tsrvp;
617 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
618 for (i=0; i<NUM_SERVER_VOLS; i++) {
619 if (tsrvp->ids[i] != 0) {
622 lock_ReleaseMutex(&tsp->mx);
623 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
624 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
625 lock_ObtainMutex(&tsp->mx);
627 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
637 if (tsp->waitCount == 0)
638 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
640 osi_Wakeup((LONG_PTR)tsp);
642 lock_ReleaseMutex(&tsp->mx);
648 if ((flags & CM_FLAG_CHECKVLDBSERVERS) ||
649 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
651 lock_ObtainRead(&cm_serverLock);
652 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
653 if (tsp->type != CM_SERVER_VLDB ||
654 tsp->cellp == NULL || /* SetPref only */
655 cellp && cellp != tsp->cellp)
658 cm_GetServerNoLock(tsp);
659 lock_ReleaseRead(&cm_serverLock);
661 lock_ObtainMutex(&tsp->mx);
662 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
664 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
665 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
666 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
667 lock_ReleaseMutex(&tsp->mx);
668 lock_ObtainRead(&cm_serverLock);
669 cm_PutServerNoLock(tsp);
673 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
674 lock_ReleaseMutex(&tsp->mx);
676 serversp[nconns] = tsp;
677 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &conns[nconns]);
679 lock_ObtainRead(&cm_serverLock);
680 cm_PutServerNoLock(tsp);
683 lock_ObtainRead(&cm_serverLock);
684 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
685 conntimer[nconns] = (isDown ? 1 : 0);
687 rx_SetConnDeadTime(rxconns[nconns], 10);
691 lock_ReleaseRead(&cm_serverLock);
694 /* Perform the multi call */
696 multi_Rx(rxconns,nconns)
698 multi_VL_ProbeServer();
699 results[multi_i]=multi_error;
703 /* Process results of servers that support VL_ProbeServer */
704 for (i=0; i<nconns; i++) {
706 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
707 rx_PutConnection(rxconns[i]);
708 cm_PutConn(conns[i]);
711 cm_GCConnections(tsp);
713 lock_ObtainMutex(&tsp->mx);
714 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
716 if (results[i] >= 0 || results[i] == RX_CALL_BUSY) {
717 /* mark server as up */
718 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
720 tsp->capabilities = 0;
722 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
723 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
724 osi_LogSaveString(afsd_logp, hoststr),
725 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
730 /* mark server as down */
731 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
732 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
733 tsp->downTime = time(NULL);
735 if (code != VRESTARTING) {
736 lock_ReleaseMutex(&tsp->mx);
737 cm_ForceNewConnections(tsp);
738 lock_ObtainMutex(&tsp->mx);
740 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
741 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
742 osi_LogSaveString(afsd_logp, hoststr),
743 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
749 if (tsp->waitCount == 0)
750 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
752 osi_Wakeup((LONG_PTR)tsp);
754 lock_ReleaseMutex(&tsp->mx);
768 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
775 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
776 0, KEY_QUERY_VALUE, &parmKey);
777 if (code == ERROR_SUCCESS) {
778 dummyLen = sizeof(multi);
779 code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
780 (BYTE *) &multi, &dummyLen);
781 RegCloseKey (parmKey);
785 cm_CheckServersMulti(flags, cellp);
787 cm_CheckServersSingular(flags, cellp);
790 void cm_InitServer(void)
792 static osi_once_t once;
794 if (osi_Once(&once)) {
795 lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
796 lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
801 /* Protected by cm_syscfgLock (rw) */
802 int cm_noIPAddr; /* number of client network interfaces */
803 int cm_IPAddr[CM_MAXINTERFACE_ADDR]; /* client's IP address in host order */
804 int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
805 int cm_NetMtu[CM_MAXINTERFACE_ADDR]; /* client's MTU sizes */
806 int cm_NetFlags[CM_MAXINTERFACE_ADDR]; /* network flags */
807 int cm_LanAdapterChangeDetected = 1;
809 void cm_SetLanAdapterChangeDetected(void)
811 lock_ObtainWrite(&cm_syscfgLock);
812 cm_LanAdapterChangeDetected = 1;
813 lock_ReleaseWrite(&cm_syscfgLock);
816 void cm_GetServer(cm_server_t *serverp)
818 lock_ObtainRead(&cm_serverLock);
819 InterlockedIncrement(&serverp->refCount);
820 lock_ReleaseRead(&cm_serverLock);
823 void cm_GetServerNoLock(cm_server_t *serverp)
825 InterlockedIncrement(&serverp->refCount);
828 void cm_PutServer(cm_server_t *serverp)
831 lock_ObtainRead(&cm_serverLock);
832 refCount = InterlockedDecrement(&serverp->refCount);
833 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
834 lock_ReleaseRead(&cm_serverLock);
837 void cm_PutServerNoLock(cm_server_t *serverp)
839 afs_int32 refCount = InterlockedDecrement(&serverp->refCount);
840 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
843 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
845 lock_ObtainMutex(&serverp->mx);
847 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NO64BIT);
849 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NO64BIT);
850 lock_ReleaseMutex(&serverp->mx);
853 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
855 lock_ObtainMutex(&serverp->mx);
857 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NOINLINEBULK);
859 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NOINLINEBULK);
860 lock_ReleaseMutex(&serverp->mx);
863 void cm_SetServerIPRank(cm_server_t * serverp)
865 unsigned long serverAddr; /* in host byte order */
866 unsigned long myAddr, myNet, mySubnet;/* in host byte order */
867 unsigned long netMask;
871 lock_ObtainRead(&cm_syscfgLock);
872 if (cm_LanAdapterChangeDetected) {
873 lock_ConvertRToW(&cm_syscfgLock);
874 if (cm_LanAdapterChangeDetected) {
875 /* get network related info */
876 cm_noIPAddr = CM_MAXINTERFACE_ADDR;
877 code = syscfg_GetIFInfo(&cm_noIPAddr,
878 cm_IPAddr, cm_SubnetMask,
879 cm_NetMtu, cm_NetFlags);
880 cm_LanAdapterChangeDetected = 0;
882 lock_ConvertWToR(&cm_syscfgLock);
885 serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
886 serverp->ipRank = CM_IPRANK_LOW; /* default settings */
888 for ( i=0; i < cm_noIPAddr; i++)
890 /* loop through all the client's IP address and compare
891 ** each of them against the server's IP address */
893 myAddr = cm_IPAddr[i];
894 if ( IN_CLASSA(myAddr) )
895 netMask = IN_CLASSA_NET;
896 else if ( IN_CLASSB(myAddr) )
897 netMask = IN_CLASSB_NET;
898 else if ( IN_CLASSC(myAddr) )
899 netMask = IN_CLASSC_NET;
903 myNet = myAddr & netMask;
904 mySubnet = myAddr & cm_SubnetMask[i];
906 if ( (serverAddr & netMask) == myNet )
908 if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
910 if ( serverAddr == myAddr ) {
911 serverp->ipRank = min(serverp->ipRank,
912 CM_IPRANK_TOP);/* same machine */
914 serverp->ipRank = min(serverp->ipRank,
915 CM_IPRANK_HI); /* same subnet */
918 serverp->ipRank = min(serverp->ipRank, CM_IPRANK_MED); /* same net */
921 } /* and of for loop */
922 lock_ReleaseRead(&cm_syscfgLock);
925 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afsUUID *uuidp, afs_uint32 flags) {
928 osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
930 lock_ObtainWrite(&cm_serverLock); /* get server lock */
931 tsp = cm_FindServer(socketp, type, TRUE);
933 /* we might have found a server created by set server prefs */
934 if (uuidp && !afs_uuid_is_nil(uuidp) &&
935 !(tsp->flags & CM_SERVERFLAG_UUID))
938 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
940 lock_ReleaseWrite(&cm_serverLock);
944 tsp = malloc(sizeof(*tsp));
946 memset(tsp, 0, sizeof(*tsp));
949 if (uuidp && !afs_uuid_is_nil(uuidp)) {
951 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
954 lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
955 tsp->addr = *socketp;
957 cm_SetServerIPRank(tsp);
959 tsp->allNextp = cm_allServersp;
960 cm_allServersp = tsp;
971 lock_ReleaseWrite(&cm_serverLock); /* release server lock */
973 if (!(flags & CM_FLAG_NOPROBE) && tsp) {
974 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN); /* assume down; ping will mark up if available */
975 cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
982 cm_FindServerByIP(afs_uint32 ipaddr, unsigned short port, int type, int locked)
987 lock_ObtainRead(&cm_serverLock);
989 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
990 if (tsp->type == type &&
991 tsp->addr.sin_addr.S_un.S_addr == ipaddr &&
992 (tsp->addr.sin_port == port || tsp->addr.sin_port == 0))
996 /* bump ref count if we found the server */
998 cm_GetServerNoLock(tsp);
1001 lock_ReleaseRead(&cm_serverLock);
1007 cm_FindServerByUuid(afsUUID *serverUuid, int type, int locked)
1012 lock_ObtainRead(&cm_serverLock);
1014 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
1015 if (tsp->type == type && !afs_uuid_equal(&tsp->uuid, serverUuid))
1019 /* bump ref count if we found the server */
1021 cm_GetServerNoLock(tsp);
1024 lock_ReleaseRead(&cm_serverLock);
1029 /* find a server based on its properties */
1030 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type, int locked)
1032 osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
1034 return cm_FindServerByIP(addrp->sin_addr.s_addr, addrp->sin_port, type, locked);
1037 cm_server_vols_t *cm_NewServerVols(void) {
1038 cm_server_vols_t *tsvp;
1040 tsvp = malloc(sizeof(*tsvp));
1042 memset(tsvp, 0, sizeof(*tsvp));
1048 * cm_NewServerRef() returns with the allocated cm_serverRef_t
1049 * with a refCount of 1.
1051 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
1053 cm_serverRef_t *tsrp;
1054 cm_server_vols_t **tsrvpp = NULL;
1055 afs_uint32 *slotp = NULL;
1058 cm_GetServer(serverp);
1059 tsrp = malloc(sizeof(*tsrp));
1060 tsrp->server = serverp;
1061 tsrp->status = srv_not_busy;
1063 tsrp->volID = volID;
1066 /* if we have a non-zero volID, we need to add it to the list
1067 * of volumes maintained by the server. There are two phases:
1068 * (1) see if the volID is already in the list and (2) insert
1069 * it into the first empty slot if it is not.
1072 lock_ObtainMutex(&serverp->mx);
1074 tsrvpp = &serverp->vols;
1078 for (i=0; i<NUM_SERVER_VOLS; i++) {
1079 if ((*tsrvpp)->ids[i] == volID) {
1082 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
1083 slotp = &(*tsrvpp)->ids[i];
1090 tsrvpp = &(*tsrvpp)->nextp;
1097 /* if we didn't find an empty slot in a current
1098 * page we must need a new page */
1099 *tsrvpp = cm_NewServerVols();
1101 (*tsrvpp)->ids[0] = volID;
1105 lock_ReleaseMutex(&serverp->mx);
1111 void cm_GetServerRef(cm_serverRef_t *tsrp, int locked)
1116 lock_ObtainRead(&cm_serverLock);
1117 refCount = InterlockedIncrement(&tsrp->refCount);
1119 lock_ReleaseRead(&cm_serverLock);
1122 afs_int32 cm_PutServerRef(cm_serverRef_t *tsrp, int locked)
1127 lock_ObtainRead(&cm_serverLock);
1128 refCount = InterlockedDecrement(&tsrp->refCount);
1129 osi_assertx(refCount >= 0, "cm_serverRef_t refCount underflow");
1132 lock_ReleaseRead(&cm_serverLock);
1138 cm_ServerListSize(cm_serverRef_t* serversp)
1140 afs_uint32 count = 0;
1141 cm_serverRef_t *tsrp;
1143 lock_ObtainRead(&cm_serverLock);
1144 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1145 if (tsrp->status == srv_deleted)
1149 lock_ReleaseRead(&cm_serverLock);
1153 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1157 cm_serverRef_t *tsrp;
1159 lock_ObtainRead(&cm_serverLock);
1160 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1161 if (tsrp->status == srv_deleted)
1167 sum ^= (LONG_PTR) tsrp->server;
1170 lock_ReleaseRead(&cm_serverLock);
1175 ** Insert a server into the server list keeping the list sorted in
1176 ** ascending order of ipRank.
1178 ** The refCount of the cm_serverRef_t is not altered.
1180 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1182 cm_serverRef_t *current;
1183 unsigned short rank;
1185 lock_ObtainWrite(&cm_serverLock);
1187 * Since we are grabbing the serverLock exclusively remove any
1188 * deleted serverRef objects with a zero refcount before
1189 * inserting the new item.
1192 cm_serverRef_t **currentp = list;
1193 cm_serverRef_t **nextp = NULL;
1194 cm_serverRef_t * next = NULL;
1196 for (currentp = list; *currentp; currentp = nextp)
1198 nextp = &(*currentp)->next;
1199 if ((*currentp)->refCount == 0 &&
1200 (*currentp)->status == srv_deleted) {
1203 if ((*currentp)->volID)
1204 cm_RemoveVolumeFromServer((*currentp)->server, (*currentp)->volID);
1205 cm_FreeServer((*currentp)->server);
1212 /* insertion into empty list or at the beginning of the list */
1215 element->next = NULL;
1221 * Now that deleted entries have been removed and we know that the
1222 * list was not empty, look for duplicates. If the element we are
1223 * inserting already exists, discard it.
1225 for ( current = *list; current; current = current->next)
1227 cm_server_t * server1 = current->server;
1228 cm_server_t * server2 = element->server;
1230 if (current->status == srv_deleted)
1233 if (server1->type != server2->type)
1236 if (server1->addr.sin_addr.s_addr != server2->addr.sin_addr.s_addr)
1239 if ((server1->flags & CM_SERVERFLAG_UUID) != (server2->flags & CM_SERVERFLAG_UUID))
1242 if ((server1->flags & CM_SERVERFLAG_UUID) &&
1243 !afs_uuid_equal(&server1->uuid, &server2->uuid))
1246 /* we must have a match, discard the new element */
1251 rank = element->server->activeRank;
1253 /* insertion at the beginning of the list */
1254 if ((*list)->server->activeRank > rank)
1256 element->next = *list;
1261 /* find appropriate place to insert */
1262 for ( current = *list; current->next; current = current->next)
1264 if ( current->next->server->activeRank > rank )
1267 element->next = current->next;
1268 current->next = element;
1271 lock_ReleaseWrite(&cm_serverLock);
1274 ** Re-sort the server list with the modified rank
1275 ** returns 0 if element was changed successfully.
1276 ** returns 1 if list remained unchanged.
1278 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t* server)
1280 cm_serverRef_t **current;
1281 cm_serverRef_t *element;
1283 lock_ObtainWrite(&cm_serverLock);
1287 /* if there is max of one element in the list, nothing to sort */
1288 if ( (!*current) || !((*current)->next) ) {
1289 lock_ReleaseWrite(&cm_serverLock);
1290 return 1; /* list unchanged: return success */
1293 /* if the server is on the list, delete it from list */
1296 if ( (*current)->server == server)
1298 element = (*current);
1299 *current = element->next; /* delete it */
1302 current = & ( (*current)->next);
1304 lock_ReleaseWrite(&cm_serverLock);
1306 /* if this volume is not replicated on this server */
1308 return 1; /* server is not on list */
1310 /* re-insert deleted element into the list with modified rank*/
1311 cm_InsertServerList(list, element);
1316 ** If there are more than one server on the list and the first n servers on
1317 ** the list have the same rank( n>1), then randomise among the first n servers.
1319 void cm_RandomizeServer(cm_serverRef_t** list)
1322 cm_serverRef_t* tsrp, *lastTsrp;
1323 unsigned short lowestRank;
1325 lock_ObtainWrite(&cm_serverLock);
1328 /* an empty list or a list with only one element */
1329 if ( !tsrp || ! tsrp->next ) {
1330 lock_ReleaseWrite(&cm_serverLock);
1334 /* count the number of servers with the lowest rank */
1335 lowestRank = tsrp->server->activeRank;
1336 for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
1338 if ( tsrp->server->activeRank != lowestRank)
1344 /* if there is only one server with the lowest rank, we are done */
1346 lock_ReleaseWrite(&cm_serverLock);
1350 picked = rand() % count;
1352 lock_ReleaseWrite(&cm_serverLock);
1357 while (--picked >= 0)
1362 lastTsrp->next = tsrp->next; /* delete random element from list*/
1363 tsrp->next = *list; /* insert element at the beginning of list */
1365 lock_ReleaseWrite(&cm_serverLock);
1368 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1369 void cm_FreeServer(cm_server_t* serverp)
1371 cm_server_vols_t * tsrvp, *nextp;
1374 cm_PutServerNoLock(serverp);
1375 if (serverp->refCount == 0)
1378 * we need to check to ensure that all of the connections
1379 * for this server have a 0 refCount; otherwise, they will
1380 * not be garbage collected
1382 * must drop the cm_serverLock because cm_GCConnections
1383 * obtains the cm_connLock and that comes first in the
1386 lock_ReleaseWrite(&cm_serverLock);
1387 cm_GCConnections(serverp); /* connsp */
1388 lock_ObtainWrite(&cm_serverLock);
1393 * Once we have the cm_serverLock locked check to make
1394 * sure the refCount is still zero before removing the
1397 if (serverp->refCount == 0) {
1398 if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1399 switch (serverp->type) {
1400 case CM_SERVER_VLDB:
1401 cm_numVldbServers--;
1403 case CM_SERVER_FILE:
1404 cm_numFileServers--;
1408 lock_FinalizeMutex(&serverp->mx);
1409 if ( cm_allServersp == serverp )
1410 cm_allServersp = serverp->allNextp;
1414 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1415 if ( tsp->allNextp == serverp ) {
1416 tsp->allNextp = serverp->allNextp;
1422 /* free the volid list */
1423 for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1424 nextp = tsrvp->nextp;
1433 /* Called with cm_serverLock write locked */
1434 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1436 cm_server_vols_t * tsrvp;
1442 for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1443 for (i=0; i<NUM_SERVER_VOLS; i++) {
1444 if (tsrvp->ids[i] == volID) {
1452 int cm_IsServerListEmpty(cm_serverRef_t *serversp)
1454 cm_serverRef_t *tsrp;
1457 if (serversp == NULL)
1458 return CM_ERROR_EMPTY;
1460 lock_ObtainRead(&cm_serverLock);
1461 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1462 if (tsrp->status == srv_deleted)
1467 lock_ReleaseRead(&cm_serverLock);
1469 return ( allDeleted ? CM_ERROR_EMPTY : 0 );
1472 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1474 cm_serverRef_t **current;
1475 cm_serverRef_t **nextp;
1476 cm_serverRef_t * next;
1479 lock_ObtainWrite(&cm_serverLock);
1489 nextp = &(*current)->next;
1490 refCount = cm_PutServerRef(*current, TRUE);
1491 if (refCount == 0) {
1494 if ((*current)->volID)
1495 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1496 cm_FreeServer((*current)->server);
1500 if (flags & CM_FREESERVERLIST_DELETE) {
1501 (*current)->status = srv_deleted;
1502 if ((*current)->volID)
1503 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1511 lock_ReleaseWrite(&cm_serverLock);
1514 /* dump all servers to a file.
1515 * cookie is used to identify this batch for easy parsing,
1516 * and it a string provided by a caller
1518 int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
1527 lock_ObtainRead(&cm_serverLock);
1530 "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n",
1531 cookie, cm_numFileServers, cm_numVldbServers);
1532 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1534 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
1539 switch (tsp->type) {
1540 case CM_SERVER_VLDB:
1543 case CM_SERVER_FILE:
1550 afsUUID_to_string(&tsp->uuid, uuidstr, sizeof(uuidstr));
1551 afs_inet_ntoa_r(tsp->addr.sin_addr.s_addr, hoststr);
1552 down = ctime(&tsp->downTime);
1553 down[strlen(down)-1] = '\0';
1556 "%s - tsp=0x%p cell=%s addr=%-15s port=%u uuid=%s type=%s caps=0x%x "
1557 "flags=0x%x waitCount=%u rank=%u downTime=\"%s\" refCount=%u\r\n",
1558 cookie, tsp, tsp->cellp ? tsp->cellp->name : "", hoststr,
1559 ntohs(tsp->addr.sin_port), uuidstr, type,
1560 tsp->capabilities, tsp->flags, tsp->waitCount, tsp->activeRank,
1561 (tsp->flags & CM_SERVERFLAG_DOWN) ? down : "up",
1563 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1565 sprintf(output, "%s - Done dumping servers.\r\n", cookie);
1566 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1569 lock_ReleaseRead(&cm_serverLock);
1575 * Determine if two servers are in fact the same.
1577 * Returns 1 if they match, 0 if they do not
1579 int cm_ServerEqual(cm_server_t *srv1, cm_server_t *srv2)
1583 if (srv1 == NULL || srv2 == NULL)
1589 if (srv1->flags & CM_SERVERFLAG_UUID) {
1590 if (!(srv2->flags & CM_SERVERFLAG_UUID))
1593 /* Both support UUID */
1594 if (UuidEqual((UUID *)&srv1->uuid, (UUID *)&srv2->uuid, &status))
1597 if (srv1->flags & CM_SERVERFLAG_UUID)
1600 /* Neither support UUID so perform an addr/port comparison */
1601 if ( srv1->addr.sin_family == srv2->addr.sin_family &&
1602 srv1->addr.sin_addr.s_addr == srv2->addr.sin_addr.s_addr &&
1603 srv1->addr.sin_port == srv2->addr.sin_port )