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;
64 afs_uint64 perfRank = 0;
67 int isDown = (tsp->flags & CM_SERVERFLAG_DOWN);
80 cm_SetServerIPRank(tsp);
86 * There are three potential components to the ranking:
87 * 1. Any administrative set preference whether it be
88 * via "fs setserverprefs", registry or dns.
90 * 2. Network subnet mask comparison.
92 * 3. Performance data.
94 * If there is an administrative rank, that is the
95 * the primary factor. If not the primary factor
96 * is the network ranking.
99 code = rx_GetLocalPeers(tsp->addr.sin_addr.s_addr, port, &tpeer);
104 log_rtt = log(tpeer.rtt);
105 perfRank += (6000 * log_rtt / 5000) * 5000;
107 if (tsp->type == CM_SERVER_FILE) {
108 /* give an edge to servers with high congestion windows */
109 perfRank -= (tpeer.cwind - 1)* 15;
114 if (tsp->adminRank) {
115 newRank = tsp->adminRank * 0.8;
116 newRank += tsp->ipRank * 0.2;
118 newRank = tsp->ipRank;
122 newRank += perfRank * 0.1;
124 newRank += (rand() & 0x000f); /* randomize */
126 if (newRank > 0xFFFF)
127 osi_Log1(afsd_logp, "new server rank %I64u exceeds 0xFFFF", newRank);
130 * If the ranking changes by more than the randomization
131 * factor, update the server reference lists.
133 if (abs(newRank - tsp->activeRank) > 0xf) {
134 tsp->activeRank = newRank;
136 lock_ReleaseMutex(&tsp->mx);
140 * find volumes which might have RO copy
141 * on server and change the ordering of
144 cm_ChangeRankVolume(tsp);
147 /* set preferences for an existing vlserver */
148 cm_ChangeRankCellVLServer(tsp);
151 lock_ObtainMutex(&tsp->mx);
159 cm_PingServer(cm_server_t *tsp)
164 struct rx_connection * rxconnp;
165 Capabilities caps = {0, 0};
169 lock_ObtainMutex(&tsp->mx);
170 if (tsp->flags & CM_SERVERFLAG_PINGING) {
172 osi_SleepM((LONG_PTR)tsp, &tsp->mx);
173 lock_ObtainMutex(&tsp->mx);
175 if (tsp->waitCount == 0)
176 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
178 osi_Wakeup((LONG_PTR)tsp);
179 lock_ReleaseMutex(&tsp->mx);
182 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
183 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
184 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
185 lock_ReleaseMutex(&tsp->mx);
187 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &connp);
189 /* now call the appropriate ping call. Drop the timeout if
190 * the server is known to be down, so that we don't waste a
191 * lot of time retiming out down servers.
194 osi_Log4(afsd_logp, "cm_PingServer server %s (%s) was %s with caps 0x%x",
195 osi_LogSaveString(afsd_logp, hoststr),
196 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
197 wasDown ? "down" : "up",
200 rxconnp = cm_GetRxConn(connp);
202 rx_SetConnDeadTime(rxconnp, 10);
203 if (tsp->type == CM_SERVER_VLDB) {
204 code = VL_ProbeServer(rxconnp);
208 code = RXAFS_GetCapabilities(rxconnp, &caps);
211 rx_SetConnDeadTime(rxconnp, ConnDeadtimeout);
212 rx_PutConnection(rxconnp);
214 } /* got an unauthenticated connection to this server */
216 lock_ObtainMutex(&tsp->mx);
217 if (code >= 0 || code == RXGEN_OPCODE || code == RX_CALL_BUSY) {
218 /* mark server as up */
219 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
222 /* we currently handle 32-bits of capabilities */
223 if (code != RXGEN_OPCODE && code != RX_CALL_BUSY &&
224 caps.Capabilities_len > 0) {
225 tsp->capabilities = caps.Capabilities_val[0];
226 xdr_free((xdrproc_t) xdr_Capabilities, &caps);
227 caps.Capabilities_len = 0;
228 caps.Capabilities_val = 0;
230 tsp->capabilities = 0;
233 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is up with caps 0x%x",
234 osi_LogSaveString(afsd_logp, hoststr),
235 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
238 /* Now update the volume status if necessary */
240 cm_server_vols_t * tsrvp;
244 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
245 for (i=0; i<NUM_SERVER_VOLS; i++) {
246 if (tsrvp->ids[i] != 0) {
249 lock_ReleaseMutex(&tsp->mx);
250 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
251 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
252 lock_ObtainMutex(&tsp->mx);
254 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
262 /* mark server as down */
263 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
264 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
265 tsp->downTime = time(NULL);
267 if (code != VRESTARTING) {
268 lock_ReleaseMutex(&tsp->mx);
269 cm_ForceNewConnections(tsp);
270 lock_ObtainMutex(&tsp->mx);
272 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
273 osi_LogSaveString(afsd_logp, hoststr),
274 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
277 /* Now update the volume status if necessary */
279 cm_server_vols_t * tsrvp;
283 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
284 for (i=0; i<NUM_SERVER_VOLS; i++) {
285 if (tsrvp->ids[i] != 0) {
288 lock_ReleaseMutex(&tsp->mx);
289 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
290 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
291 lock_ObtainMutex(&tsp->mx);
293 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
302 if (tsp->waitCount == 0)
303 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
305 osi_Wakeup((LONG_PTR)tsp);
306 lock_ReleaseMutex(&tsp->mx);
314 lock_ObtainRead(&cm_serverLock);
315 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
316 cm_GetServerNoLock(tsp);
317 lock_ReleaseRead(&cm_serverLock);
319 lock_ObtainMutex(&tsp->mx);
321 /* if the server is not down, rank the server */
322 if(!(tsp->flags & CM_SERVERFLAG_DOWN))
325 lock_ReleaseMutex(&tsp->mx);
327 lock_ObtainRead(&cm_serverLock);
328 cm_PutServerNoLock(tsp);
330 lock_ReleaseRead(&cm_serverLock);
333 static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
335 /* ping all file servers, up or down, with unauthenticated connection,
336 * to find out whether we have all our callbacks from the server still.
337 * Also, ping down VLDBs.
345 lock_ObtainRead(&cm_serverLock);
346 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
347 cm_GetServerNoLock(tsp);
348 lock_ReleaseRead(&cm_serverLock);
350 /* now process the server */
351 lock_ObtainMutex(&tsp->mx);
354 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
355 isFS = tsp->type == CM_SERVER_FILE;
356 isVLDB = tsp->type == CM_SERVER_VLDB;
358 /* only do the ping if the cell matches the requested cell, or we're
359 * matching all cells (cellp == NULL), and if we've requested to ping
360 * this type of {up, down} servers.
362 if ((cellp == NULL || cellp == tsp->cellp) &&
363 ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
364 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
365 ((!(flags & CM_FLAG_CHECKVLDBSERVERS) ||
366 isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
367 (!(flags & CM_FLAG_CHECKFILESERVERS) ||
368 isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
370 } /* we're supposed to check this up/down server */
371 lock_ReleaseMutex(&tsp->mx);
373 /* at this point, we've adjusted the server state, so do the ping and
379 /* also, run the GC function for connections on all of the
380 * server's connections.
382 cm_GCConnections(tsp);
384 lock_ObtainRead(&cm_serverLock);
385 cm_PutServerNoLock(tsp);
387 lock_ReleaseRead(&cm_serverLock);
390 static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
393 * The goal of this function is to probe simultaneously
394 * probe all of the up/down servers (vldb/file) as
395 * specified by flags in the minimum number of RPCs.
396 * Effectively that means use one multi_RXAFS_GetCapabilities()
397 * followed by possibly one multi_RXAFS_GetTime() and
398 * one multi_VL_ProbeServer().
400 * To make this work we must construct the list of vldb
401 * and file servers that are to be probed as well as the
402 * associated data structures.
405 int srvAddrCount = 0;
406 struct srvAddr **addrs = NULL;
407 cm_conn_t **conns = NULL;
408 struct rx_connection **rxconns = NULL;
410 afs_int32 i, nconns = 0, maxconns;
411 afs_int32 *conntimer, *results;
412 Capabilities *caps = NULL;
413 cm_server_t ** serversp, *tsp;
414 afs_uint32 isDown, wasDown;
420 maxconns = max(cm_numFileServers,cm_numVldbServers);
424 conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
425 rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
426 conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
427 results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
428 serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
429 caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
431 memset(caps, 0, maxconns * sizeof(Capabilities));
433 if ((flags & CM_FLAG_CHECKFILESERVERS) ||
434 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
436 lock_ObtainRead(&cm_serverLock);
437 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
438 if (tsp->type != CM_SERVER_FILE ||
439 tsp->cellp == NULL || /* SetPref only */
440 cellp && cellp != tsp->cellp)
443 cm_GetServerNoLock(tsp);
444 lock_ReleaseRead(&cm_serverLock);
446 lock_ObtainMutex(&tsp->mx);
447 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
449 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
450 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
451 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
452 lock_ReleaseMutex(&tsp->mx);
453 lock_ObtainRead(&cm_serverLock);
454 cm_PutServerNoLock(tsp);
458 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
459 lock_ReleaseMutex(&tsp->mx);
461 serversp[nconns] = tsp;
462 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &conns[nconns]);
464 lock_ObtainRead(&cm_serverLock);
465 cm_PutServerNoLock(tsp);
468 lock_ObtainRead(&cm_serverLock);
469 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
470 if (conntimer[nconns] = (isDown ? 1 : 0))
471 rx_SetConnDeadTime(rxconns[nconns], 10);
475 lock_ReleaseRead(&cm_serverLock);
478 /* Perform the multi call */
480 multi_Rx(rxconns,nconns)
482 multi_RXAFS_GetCapabilities(&caps[multi_i]);
483 results[multi_i]=multi_error;
487 /* Process results of servers that support RXAFS_GetCapabilities */
488 for (i=0; i<nconns; i++) {
490 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
491 rx_PutConnection(rxconns[i]);
492 cm_PutConn(conns[i]);
495 cm_GCConnections(tsp);
497 lock_ObtainMutex(&tsp->mx);
498 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
500 if (results[i] >= 0 || results[i] == RXGEN_OPCODE ||
501 results[i] == RX_CALL_BUSY) {
502 /* mark server as up */
503 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
506 /* we currently handle 32-bits of capabilities */
507 if (results[i] != RXGEN_OPCODE && results[i] != RX_CALL_BUSY &&
508 caps[i].Capabilities_len > 0) {
509 tsp->capabilities = caps[i].Capabilities_val[0];
510 xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
511 caps[i].Capabilities_len = 0;
512 caps[i].Capabilities_val = 0;
514 tsp->capabilities = 0;
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 up 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]);
547 /* mark server as down */
548 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
549 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
550 tsp->downTime = time(NULL);
552 if (code != VRESTARTING) {
553 lock_ReleaseMutex(&tsp->mx);
554 cm_ForceNewConnections(tsp);
555 lock_ObtainMutex(&tsp->mx);
557 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
558 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
559 osi_LogSaveString(afsd_logp, hoststr),
560 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
563 /* Now update the volume status if necessary */
565 cm_server_vols_t * tsrvp;
569 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
570 for (i=0; i<NUM_SERVER_VOLS; i++) {
571 if (tsrvp->ids[i] != 0) {
574 lock_ReleaseMutex(&tsp->mx);
575 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
576 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
577 lock_ObtainMutex(&tsp->mx);
579 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
588 if (tsp->waitCount == 0)
589 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
591 osi_Wakeup((LONG_PTR)tsp);
593 lock_ReleaseMutex(&tsp->mx);
599 if ((flags & CM_FLAG_CHECKVLDBSERVERS) ||
600 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
602 lock_ObtainRead(&cm_serverLock);
603 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
604 if (tsp->type != CM_SERVER_VLDB ||
605 tsp->cellp == NULL || /* SetPref only */
606 cellp && cellp != tsp->cellp)
609 cm_GetServerNoLock(tsp);
610 lock_ReleaseRead(&cm_serverLock);
612 lock_ObtainMutex(&tsp->mx);
613 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
615 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
616 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
617 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
618 lock_ReleaseMutex(&tsp->mx);
619 lock_ObtainRead(&cm_serverLock);
620 cm_PutServerNoLock(tsp);
624 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
625 lock_ReleaseMutex(&tsp->mx);
627 serversp[nconns] = tsp;
628 code = cm_ConnByServer(tsp, cm_rootUserp, FALSE, &conns[nconns]);
630 lock_ObtainRead(&cm_serverLock);
631 cm_PutServerNoLock(tsp);
634 lock_ObtainRead(&cm_serverLock);
635 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
636 conntimer[nconns] = (isDown ? 1 : 0);
638 rx_SetConnDeadTime(rxconns[nconns], 10);
642 lock_ReleaseRead(&cm_serverLock);
645 /* Perform the multi call */
647 multi_Rx(rxconns,nconns)
649 multi_VL_ProbeServer();
650 results[multi_i]=multi_error;
654 /* Process results of servers that support VL_ProbeServer */
655 for (i=0; i<nconns; i++) {
657 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
658 rx_PutConnection(rxconns[i]);
659 cm_PutConn(conns[i]);
662 cm_GCConnections(tsp);
664 lock_ObtainMutex(&tsp->mx);
665 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
667 if (results[i] >= 0 || results[i] == RX_CALL_BUSY) {
668 /* mark server as up */
669 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
671 tsp->capabilities = 0;
673 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
674 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
675 osi_LogSaveString(afsd_logp, hoststr),
676 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
679 /* mark server as down */
680 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
681 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
682 tsp->downTime = time(NULL);
684 if (code != VRESTARTING) {
685 lock_ReleaseMutex(&tsp->mx);
686 cm_ForceNewConnections(tsp);
687 lock_ObtainMutex(&tsp->mx);
689 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
690 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
691 osi_LogSaveString(afsd_logp, hoststr),
692 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
696 if (tsp->waitCount == 0)
697 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
699 osi_Wakeup((LONG_PTR)tsp);
701 lock_ReleaseMutex(&tsp->mx);
715 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
722 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
723 0, KEY_QUERY_VALUE, &parmKey);
724 if (code == ERROR_SUCCESS) {
725 dummyLen = sizeof(multi);
726 code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
727 (BYTE *) &multi, &dummyLen);
728 RegCloseKey (parmKey);
732 cm_CheckServersMulti(flags, cellp);
734 cm_CheckServersSingular(flags, cellp);
737 void cm_InitServer(void)
739 static osi_once_t once;
741 if (osi_Once(&once)) {
742 lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
743 lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
748 /* Protected by cm_syscfgLock (rw) */
749 int cm_noIPAddr; /* number of client network interfaces */
750 int cm_IPAddr[CM_MAXINTERFACE_ADDR]; /* client's IP address in host order */
751 int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
752 int cm_NetMtu[CM_MAXINTERFACE_ADDR]; /* client's MTU sizes */
753 int cm_NetFlags[CM_MAXINTERFACE_ADDR]; /* network flags */
754 int cm_LanAdapterChangeDetected = 1;
756 void cm_SetLanAdapterChangeDetected(void)
758 lock_ObtainWrite(&cm_syscfgLock);
759 cm_LanAdapterChangeDetected = 1;
760 lock_ReleaseWrite(&cm_syscfgLock);
763 void cm_GetServer(cm_server_t *serverp)
765 lock_ObtainRead(&cm_serverLock);
766 InterlockedIncrement(&serverp->refCount);
767 lock_ReleaseRead(&cm_serverLock);
770 void cm_GetServerNoLock(cm_server_t *serverp)
772 InterlockedIncrement(&serverp->refCount);
775 void cm_PutServer(cm_server_t *serverp)
778 lock_ObtainRead(&cm_serverLock);
779 refCount = InterlockedDecrement(&serverp->refCount);
780 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
781 lock_ReleaseRead(&cm_serverLock);
784 void cm_PutServerNoLock(cm_server_t *serverp)
786 afs_int32 refCount = InterlockedDecrement(&serverp->refCount);
787 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
790 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
792 lock_ObtainMutex(&serverp->mx);
794 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NO64BIT);
796 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NO64BIT);
797 lock_ReleaseMutex(&serverp->mx);
800 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
802 lock_ObtainMutex(&serverp->mx);
804 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NOINLINEBULK);
806 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NOINLINEBULK);
807 lock_ReleaseMutex(&serverp->mx);
810 void cm_SetServerIPRank(cm_server_t * serverp)
812 unsigned long serverAddr; /* in host byte order */
813 unsigned long myAddr, myNet, mySubnet;/* in host byte order */
814 unsigned long netMask;
818 lock_ObtainRead(&cm_syscfgLock);
819 if (cm_LanAdapterChangeDetected) {
820 lock_ConvertRToW(&cm_syscfgLock);
821 if (cm_LanAdapterChangeDetected) {
822 /* get network related info */
823 cm_noIPAddr = CM_MAXINTERFACE_ADDR;
824 code = syscfg_GetIFInfo(&cm_noIPAddr,
825 cm_IPAddr, cm_SubnetMask,
826 cm_NetMtu, cm_NetFlags);
827 cm_LanAdapterChangeDetected = 0;
829 lock_ConvertWToR(&cm_syscfgLock);
832 serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
833 serverp->ipRank = CM_IPRANK_LOW; /* default settings */
835 for ( i=0; i < cm_noIPAddr; i++)
837 /* loop through all the client's IP address and compare
838 ** each of them against the server's IP address */
840 myAddr = cm_IPAddr[i];
841 if ( IN_CLASSA(myAddr) )
842 netMask = IN_CLASSA_NET;
843 else if ( IN_CLASSB(myAddr) )
844 netMask = IN_CLASSB_NET;
845 else if ( IN_CLASSC(myAddr) )
846 netMask = IN_CLASSC_NET;
850 myNet = myAddr & netMask;
851 mySubnet = myAddr & cm_SubnetMask[i];
853 if ( (serverAddr & netMask) == myNet )
855 if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
857 if ( serverAddr == myAddr ) {
858 serverp->ipRank = min(serverp->ipRank,
859 CM_IPRANK_TOP);/* same machine */
861 serverp->ipRank = min(serverp->ipRank,
862 CM_IPRANK_HI); /* same subnet */
865 serverp->ipRank = min(serverp->ipRank, CM_IPRANK_MED); /* same net */
868 } /* and of for loop */
869 lock_ReleaseRead(&cm_syscfgLock);
872 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afsUUID *uuidp, afs_uint32 flags) {
875 osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
877 lock_ObtainWrite(&cm_serverLock); /* get server lock */
878 tsp = cm_FindServer(socketp, type, TRUE);
880 /* we might have found a server created by set server prefs */
881 if (uuidp && !afs_uuid_is_nil(uuidp) &&
882 !(tsp->flags & CM_SERVERFLAG_UUID))
885 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
887 lock_ReleaseWrite(&cm_serverLock);
891 tsp = malloc(sizeof(*tsp));
893 memset(tsp, 0, sizeof(*tsp));
896 if (uuidp && !afs_uuid_is_nil(uuidp)) {
898 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
901 lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
902 tsp->addr = *socketp;
904 cm_SetServerIPRank(tsp);
906 tsp->allNextp = cm_allServersp;
907 cm_allServersp = tsp;
918 lock_ReleaseWrite(&cm_serverLock); /* release server lock */
920 if (!(flags & CM_FLAG_NOPROBE) && tsp) {
921 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN); /* assume down; ping will mark up if available */
922 cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
929 cm_FindServerByIP(afs_uint32 ipaddr, unsigned short port, int type, int locked)
934 lock_ObtainRead(&cm_serverLock);
936 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
937 if (tsp->type == type &&
938 tsp->addr.sin_addr.S_un.S_addr == ipaddr &&
939 (tsp->addr.sin_port == port || tsp->addr.sin_port == 0))
943 /* bump ref count if we found the server */
945 cm_GetServerNoLock(tsp);
948 lock_ReleaseRead(&cm_serverLock);
954 cm_FindServerByUuid(afsUUID *serverUuid, int type, int locked)
959 lock_ObtainRead(&cm_serverLock);
961 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
962 if (tsp->type == type && !afs_uuid_equal(&tsp->uuid, serverUuid))
966 /* bump ref count if we found the server */
968 cm_GetServerNoLock(tsp);
971 lock_ReleaseRead(&cm_serverLock);
976 /* find a server based on its properties */
977 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type, int locked)
979 osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
981 return cm_FindServerByIP(addrp->sin_addr.s_addr, addrp->sin_port, type, locked);
984 cm_server_vols_t *cm_NewServerVols(void) {
985 cm_server_vols_t *tsvp;
987 tsvp = malloc(sizeof(*tsvp));
989 memset(tsvp, 0, sizeof(*tsvp));
995 * cm_NewServerRef() returns with the allocated cm_serverRef_t
996 * with a refCount of 1.
998 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
1000 cm_serverRef_t *tsrp;
1001 cm_server_vols_t **tsrvpp = NULL;
1002 afs_uint32 *slotp = NULL;
1005 cm_GetServer(serverp);
1006 tsrp = malloc(sizeof(*tsrp));
1007 tsrp->server = serverp;
1008 tsrp->status = srv_not_busy;
1010 tsrp->volID = volID;
1013 /* if we have a non-zero volID, we need to add it to the list
1014 * of volumes maintained by the server. There are two phases:
1015 * (1) see if the volID is already in the list and (2) insert
1016 * it into the first empty slot if it is not.
1019 lock_ObtainMutex(&serverp->mx);
1021 tsrvpp = &serverp->vols;
1025 for (i=0; i<NUM_SERVER_VOLS; i++) {
1026 if ((*tsrvpp)->ids[i] == volID) {
1029 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
1030 slotp = &(*tsrvpp)->ids[i];
1037 tsrvpp = &(*tsrvpp)->nextp;
1044 /* if we didn't find an empty slot in a current
1045 * page we must need a new page */
1046 *tsrvpp = cm_NewServerVols();
1048 (*tsrvpp)->ids[0] = volID;
1052 lock_ReleaseMutex(&serverp->mx);
1058 void cm_GetServerRef(cm_serverRef_t *tsrp, int locked)
1063 lock_ObtainRead(&cm_serverLock);
1064 refCount = InterlockedIncrement(&tsrp->refCount);
1066 lock_ReleaseRead(&cm_serverLock);
1069 afs_int32 cm_PutServerRef(cm_serverRef_t *tsrp, int locked)
1074 lock_ObtainRead(&cm_serverLock);
1075 refCount = InterlockedDecrement(&tsrp->refCount);
1076 osi_assertx(refCount >= 0, "cm_serverRef_t refCount underflow");
1079 lock_ReleaseRead(&cm_serverLock);
1085 cm_ServerListSize(cm_serverRef_t* serversp)
1087 afs_uint32 count = 0;
1088 cm_serverRef_t *tsrp;
1090 lock_ObtainRead(&cm_serverLock);
1091 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1092 if (tsrp->status == srv_deleted)
1096 lock_ReleaseRead(&cm_serverLock);
1100 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1104 cm_serverRef_t *tsrp;
1106 lock_ObtainRead(&cm_serverLock);
1107 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1108 if (tsrp->status == srv_deleted)
1114 sum ^= (LONG_PTR) tsrp->server;
1117 lock_ReleaseRead(&cm_serverLock);
1122 ** Insert a server into the server list keeping the list sorted in
1123 ** ascending order of ipRank.
1125 ** The refCount of the cm_serverRef_t is not altered.
1127 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1129 cm_serverRef_t *current;
1130 unsigned short rank;
1132 lock_ObtainWrite(&cm_serverLock);
1134 * Since we are grabbing the serverLock exclusively remove any
1135 * deleted serverRef objects with a zero refcount before
1136 * inserting the new item.
1139 cm_serverRef_t **currentp = list;
1140 cm_serverRef_t **nextp = NULL;
1141 cm_serverRef_t * next = NULL;
1143 for (currentp = list; *currentp; currentp = nextp)
1145 nextp = &(*currentp)->next;
1146 if ((*currentp)->refCount == 0 &&
1147 (*currentp)->status == srv_deleted) {
1150 if ((*currentp)->volID)
1151 cm_RemoveVolumeFromServer((*currentp)->server, (*currentp)->volID);
1152 cm_FreeServer((*currentp)->server);
1159 /* insertion into empty list or at the beginning of the list */
1162 element->next = NULL;
1168 * Now that deleted entries have been removed and we know that the
1169 * list was not empty, look for duplicates. If the element we are
1170 * inserting already exists, discard it.
1172 for ( current = *list; current; current = current->next)
1174 cm_server_t * server1 = current->server;
1175 cm_server_t * server2 = element->server;
1177 if (current->status == srv_deleted)
1180 if (server1->type != server2->type)
1183 if (server1->addr.sin_addr.s_addr != server2->addr.sin_addr.s_addr)
1186 if ((server1->flags & CM_SERVERFLAG_UUID) != (server2->flags & CM_SERVERFLAG_UUID))
1189 if ((server1->flags & CM_SERVERFLAG_UUID) &&
1190 !afs_uuid_equal(&server1->uuid, &server2->uuid))
1193 /* we must have a match, discard the new element */
1198 rank = element->server->activeRank;
1200 /* insertion at the beginning of the list */
1201 if ((*list)->server->activeRank > rank)
1203 element->next = *list;
1208 /* find appropriate place to insert */
1209 for ( current = *list; current->next; current = current->next)
1211 if ( current->next->server->activeRank > rank )
1214 element->next = current->next;
1215 current->next = element;
1218 lock_ReleaseWrite(&cm_serverLock);
1221 ** Re-sort the server list with the modified rank
1222 ** returns 0 if element was changed successfully.
1223 ** returns 1 if list remained unchanged.
1225 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t* server)
1227 cm_serverRef_t **current;
1228 cm_serverRef_t *element;
1230 lock_ObtainWrite(&cm_serverLock);
1234 /* if there is max of one element in the list, nothing to sort */
1235 if ( (!*current) || !((*current)->next) ) {
1236 lock_ReleaseWrite(&cm_serverLock);
1237 return 1; /* list unchanged: return success */
1240 /* if the server is on the list, delete it from list */
1243 if ( (*current)->server == server)
1245 element = (*current);
1246 *current = element->next; /* delete it */
1249 current = & ( (*current)->next);
1251 lock_ReleaseWrite(&cm_serverLock);
1253 /* if this volume is not replicated on this server */
1255 return 1; /* server is not on list */
1257 /* re-insert deleted element into the list with modified rank*/
1258 cm_InsertServerList(list, element);
1263 ** If there are more than one server on the list and the first n servers on
1264 ** the list have the same rank( n>1), then randomise among the first n servers.
1266 void cm_RandomizeServer(cm_serverRef_t** list)
1269 cm_serverRef_t* tsrp, *lastTsrp;
1270 unsigned short lowestRank;
1272 lock_ObtainWrite(&cm_serverLock);
1275 /* an empty list or a list with only one element */
1276 if ( !tsrp || ! tsrp->next ) {
1277 lock_ReleaseWrite(&cm_serverLock);
1281 /* count the number of servers with the lowest rank */
1282 lowestRank = tsrp->server->activeRank;
1283 for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
1285 if ( tsrp->server->activeRank != lowestRank)
1291 /* if there is only one server with the lowest rank, we are done */
1293 lock_ReleaseWrite(&cm_serverLock);
1297 picked = rand() % count;
1299 lock_ReleaseWrite(&cm_serverLock);
1304 while (--picked >= 0)
1309 lastTsrp->next = tsrp->next; /* delete random element from list*/
1310 tsrp->next = *list; /* insert element at the beginning of list */
1312 lock_ReleaseWrite(&cm_serverLock);
1315 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1316 void cm_FreeServer(cm_server_t* serverp)
1318 cm_server_vols_t * tsrvp, *nextp;
1321 cm_PutServerNoLock(serverp);
1322 if (serverp->refCount == 0)
1325 * we need to check to ensure that all of the connections
1326 * for this server have a 0 refCount; otherwise, they will
1327 * not be garbage collected
1329 * must drop the cm_serverLock because cm_GCConnections
1330 * obtains the cm_connLock and that comes first in the
1333 lock_ReleaseWrite(&cm_serverLock);
1334 cm_GCConnections(serverp); /* connsp */
1335 lock_ObtainWrite(&cm_serverLock);
1340 * Once we have the cm_serverLock locked check to make
1341 * sure the refCount is still zero before removing the
1344 if (serverp->refCount == 0) {
1345 if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1346 switch (serverp->type) {
1347 case CM_SERVER_VLDB:
1348 cm_numVldbServers--;
1350 case CM_SERVER_FILE:
1351 cm_numFileServers--;
1355 lock_FinalizeMutex(&serverp->mx);
1356 if ( cm_allServersp == serverp )
1357 cm_allServersp = serverp->allNextp;
1361 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1362 if ( tsp->allNextp == serverp ) {
1363 tsp->allNextp = serverp->allNextp;
1369 /* free the volid list */
1370 for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1371 nextp = tsrvp->nextp;
1380 /* Called with cm_serverLock write locked */
1381 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1383 cm_server_vols_t * tsrvp;
1389 for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1390 for (i=0; i<NUM_SERVER_VOLS; i++) {
1391 if (tsrvp->ids[i] == volID) {
1399 int cm_IsServerListEmpty(cm_serverRef_t *serversp)
1401 cm_serverRef_t *tsrp;
1404 if (serversp == NULL)
1405 return CM_ERROR_EMPTY;
1407 lock_ObtainRead(&cm_serverLock);
1408 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1409 if (tsrp->status == srv_deleted)
1414 lock_ReleaseRead(&cm_serverLock);
1416 return ( allDeleted ? CM_ERROR_EMPTY : 0 );
1419 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1421 cm_serverRef_t **current;
1422 cm_serverRef_t **nextp;
1423 cm_serverRef_t * next;
1426 lock_ObtainWrite(&cm_serverLock);
1436 nextp = &(*current)->next;
1437 refCount = cm_PutServerRef(*current, TRUE);
1438 if (refCount == 0) {
1441 if ((*current)->volID)
1442 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1443 cm_FreeServer((*current)->server);
1447 if (flags & CM_FREESERVERLIST_DELETE) {
1448 (*current)->status = srv_deleted;
1449 if ((*current)->volID)
1450 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1458 lock_ReleaseWrite(&cm_serverLock);
1461 /* dump all servers to a file.
1462 * cookie is used to identify this batch for easy parsing,
1463 * and it a string provided by a caller
1465 int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
1474 lock_ObtainRead(&cm_serverLock);
1477 "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n",
1478 cookie, cm_numFileServers, cm_numVldbServers);
1479 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1481 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
1486 switch (tsp->type) {
1487 case CM_SERVER_VLDB:
1490 case CM_SERVER_FILE:
1497 afsUUID_to_string(&tsp->uuid, uuidstr, sizeof(uuidstr));
1498 afs_inet_ntoa_r(tsp->addr.sin_addr.s_addr, hoststr);
1499 down = ctime(&tsp->downTime);
1500 down[strlen(down)-1] = '\0';
1503 "%s - tsp=0x%p cell=%s addr=%-15s port=%u uuid=%s type=%s caps=0x%x "
1504 "flags=0x%x waitCount=%u rank=%u downTime=\"%s\" refCount=%u\r\n",
1505 cookie, tsp, tsp->cellp ? tsp->cellp->name : "", hoststr,
1506 ntohs(tsp->addr.sin_port), uuidstr, type,
1507 tsp->capabilities, tsp->flags, tsp->waitCount, tsp->activeRank,
1508 (tsp->flags & CM_SERVERFLAG_DOWN) ? down : "up",
1510 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1512 sprintf(output, "%s - Done dumping servers.\r\n", cookie);
1513 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1516 lock_ReleaseRead(&cm_serverLock);
1522 * Determine if two servers are in fact the same.
1524 * Returns 1 if they match, 0 if they do not
1526 int cm_ServerEqual(cm_server_t *srv1, cm_server_t *srv2)
1530 if (srv1 == NULL || srv2 == NULL)
1536 if (srv1->flags & CM_SERVERFLAG_UUID) {
1537 if (!(srv2->flags & CM_SERVERFLAG_UUID))
1540 /* Both support UUID */
1541 if (UuidEqual((UUID *)&srv1->uuid, (UUID *)&srv2->uuid, &status))
1544 if (srv1->flags & CM_SERVERFLAG_UUID)
1547 /* Neither support UUID so perform an addr/port comparison */
1548 if ( srv1->addr.sin_family == srv2->addr.sin_family &&
1549 srv1->addr.sin_addr.s_addr == srv2->addr.sin_addr.s_addr &&
1550 srv1->addr.sin_port == srv2->addr.sin_port )