2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
24 #include <WINNT\syscfg.h>
25 #include <WINNT/afsreg.h>
30 osi_rwlock_t cm_serverLock;
31 osi_rwlock_t cm_syscfgLock;
33 cm_server_t *cm_allServersp;
34 afs_uint32 cm_numFileServers = 0;
35 afs_uint32 cm_numVldbServers = 0;
38 cm_ForceNewConnectionsAllServers(void)
42 lock_ObtainRead(&cm_serverLock);
43 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
44 cm_GetServerNoLock(tsp);
45 lock_ReleaseRead(&cm_serverLock);
46 cm_ForceNewConnections(tsp);
47 lock_ObtainRead(&cm_serverLock);
48 cm_PutServerNoLock(tsp);
50 lock_ReleaseRead(&cm_serverLock);
54 * lock_ObtainMutex must be held prior to calling
58 cm_RankServer(cm_server_t * tsp)
60 afs_int32 code = 0; /* start with "success" */
61 struct rx_debugPeer tpeer;
76 code = rx_GetLocalPeers(tsp->addr.sin_addr.s_addr, port, &tpeer);
78 /*check if rx_GetLocalPeers succeeded and if there is data for tsp */
79 if(code == 0 && (tpeer.rtt == 0 && tpeer.rtt_dev == 0))
83 if((tsp->flags & CM_SERVERFLAG_PREF_SET))
84 newRank = tsp->adminRank +
85 ((int)(623 * log(tpeer.rtt) / 10) * 10 + 5);
86 else /* rank has not been set by admin, derive rank from rtt */
87 newRank = (int)(7200 * log(tpeer.rtt) / 5000) * 5000 + 5000;
89 newRank += (rand() & 0x000f); /* randomize */
91 if (abs(newRank - tsp->ipRank) > 0xf) {
92 tsp->ipRank = newRank;
94 lock_ReleaseMutex(&tsp->mx);
98 * find volumes which might have RO copy
99 * on server and change the ordering of
102 cm_ChangeRankVolume(tsp);
105 /* set preferences for an existing vlserver */
106 cm_ChangeRankCellVLServer(tsp);
109 lock_ObtainMutex(&tsp->mx);
117 cm_PingServer(cm_server_t *tsp)
122 struct rx_connection * rxconnp;
123 Capabilities caps = {0, 0};
127 lock_ObtainMutex(&tsp->mx);
128 if (tsp->flags & CM_SERVERFLAG_PINGING) {
130 osi_SleepM((LONG_PTR)tsp, &tsp->mx);
131 lock_ObtainMutex(&tsp->mx);
133 if (tsp->waitCount == 0)
134 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
136 osi_Wakeup((LONG_PTR)tsp);
137 lock_ReleaseMutex(&tsp->mx);
140 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
141 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
142 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
143 lock_ReleaseMutex(&tsp->mx);
145 code = cm_ConnByServer(tsp, cm_rootUserp, &connp);
147 /* now call the appropriate ping call. Drop the timeout if
148 * the server is known to be down, so that we don't waste a
149 * lot of time retiming out down servers.
152 osi_Log4(afsd_logp, "cm_PingServer server %s (%s) was %s with caps 0x%x",
153 osi_LogSaveString(afsd_logp, hoststr),
154 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
155 wasDown ? "down" : "up",
158 rxconnp = cm_GetRxConn(connp);
160 rx_SetConnDeadTime(rxconnp, 10);
161 if (tsp->type == CM_SERVER_VLDB) {
162 code = VL_ProbeServer(rxconnp);
166 code = RXAFS_GetCapabilities(rxconnp, &caps);
169 rx_SetConnDeadTime(rxconnp, ConnDeadtimeout);
170 rx_PutConnection(rxconnp);
172 } /* got an unauthenticated connection to this server */
174 lock_ObtainMutex(&tsp->mx);
175 if (code >= 0 || code == RXGEN_OPCODE) {
176 /* mark server as up */
177 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
180 /* we currently handle 32-bits of capabilities */
181 if (code != RXGEN_OPCODE && caps.Capabilities_len > 0) {
182 tsp->capabilities = caps.Capabilities_val[0];
183 xdr_free((xdrproc_t) xdr_Capabilities, &caps);
184 caps.Capabilities_len = 0;
185 caps.Capabilities_val = 0;
187 tsp->capabilities = 0;
190 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is up with caps 0x%x",
191 osi_LogSaveString(afsd_logp, hoststr),
192 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
195 /* Now update the volume status if necessary */
197 cm_server_vols_t * tsrvp;
201 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
202 for (i=0; i<NUM_SERVER_VOLS; i++) {
203 if (tsrvp->ids[i] != 0) {
206 lock_ReleaseMutex(&tsp->mx);
207 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
208 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
209 lock_ObtainMutex(&tsp->mx);
211 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
219 /* mark server as down */
220 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
221 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
222 tsp->downTime = time(NULL);
224 if (code != VRESTARTING) {
225 lock_ReleaseMutex(&tsp->mx);
226 cm_ForceNewConnections(tsp);
227 lock_ObtainMutex(&tsp->mx);
229 osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
230 osi_LogSaveString(afsd_logp, hoststr),
231 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
234 /* Now update the volume status if necessary */
236 cm_server_vols_t * tsrvp;
240 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
241 for (i=0; i<NUM_SERVER_VOLS; i++) {
242 if (tsrvp->ids[i] != 0) {
245 lock_ReleaseMutex(&tsp->mx);
246 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
247 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
248 lock_ObtainMutex(&tsp->mx);
250 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
259 if (tsp->waitCount == 0)
260 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
262 osi_Wakeup((LONG_PTR)tsp);
263 lock_ReleaseMutex(&tsp->mx);
271 lock_ObtainRead(&cm_serverLock);
272 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
273 cm_GetServerNoLock(tsp);
274 lock_ReleaseRead(&cm_serverLock);
276 lock_ObtainMutex(&tsp->mx);
278 /* if the server is not down, rank the server */
279 if(!(tsp->flags & CM_SERVERFLAG_DOWN))
282 lock_ReleaseMutex(&tsp->mx);
284 lock_ObtainRead(&cm_serverLock);
285 cm_PutServerNoLock(tsp);
287 lock_ReleaseRead(&cm_serverLock);
290 static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
292 /* ping all file servers, up or down, with unauthenticated connection,
293 * to find out whether we have all our callbacks from the server still.
294 * Also, ping down VLDBs.
302 lock_ObtainRead(&cm_serverLock);
303 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
304 cm_GetServerNoLock(tsp);
305 lock_ReleaseRead(&cm_serverLock);
307 /* now process the server */
308 lock_ObtainMutex(&tsp->mx);
311 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
312 isFS = tsp->type == CM_SERVER_FILE;
313 isVLDB = tsp->type == CM_SERVER_VLDB;
315 /* only do the ping if the cell matches the requested cell, or we're
316 * matching all cells (cellp == NULL), and if we've requested to ping
317 * this type of {up, down} servers.
319 if ((cellp == NULL || cellp == tsp->cellp) &&
320 ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
321 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
322 ((!(flags & CM_FLAG_CHECKVLDBSERVERS) ||
323 isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
324 (!(flags & CM_FLAG_CHECKFILESERVERS) ||
325 isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
327 } /* we're supposed to check this up/down server */
328 lock_ReleaseMutex(&tsp->mx);
330 /* at this point, we've adjusted the server state, so do the ping and
336 /* also, run the GC function for connections on all of the
337 * server's connections.
339 cm_GCConnections(tsp);
341 lock_ObtainRead(&cm_serverLock);
342 cm_PutServerNoLock(tsp);
344 lock_ReleaseRead(&cm_serverLock);
347 static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
350 * The goal of this function is to probe simultaneously
351 * probe all of the up/down servers (vldb/file) as
352 * specified by flags in the minimum number of RPCs.
353 * Effectively that means use one multi_RXAFS_GetCapabilities()
354 * followed by possibly one multi_RXAFS_GetTime() and
355 * one multi_VL_ProbeServer().
357 * To make this work we must construct the list of vldb
358 * and file servers that are to be probed as well as the
359 * associated data structures.
362 int srvAddrCount = 0;
363 struct srvAddr **addrs = NULL;
364 cm_conn_t **conns = NULL;
365 struct rx_connection **rxconns = NULL;
367 afs_int32 i, nconns = 0, maxconns;
368 afs_int32 *conntimer, *results;
369 Capabilities *caps = NULL;
370 cm_server_t ** serversp, *tsp;
371 afs_uint32 isDown, wasDown;
373 time_t start, *deltas;
377 maxconns = max(cm_numFileServers,cm_numVldbServers);
381 conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
382 rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
383 conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
384 deltas = (time_t *)malloc(maxconns * sizeof (time_t));
385 results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
386 serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
387 caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
389 memset(caps, 0, maxconns * sizeof(Capabilities));
391 if ((flags & CM_FLAG_CHECKFILESERVERS) ||
392 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
394 lock_ObtainRead(&cm_serverLock);
395 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
396 if (tsp->type != CM_SERVER_FILE ||
397 tsp->cellp == NULL || /* SetPref only */
398 cellp && cellp != tsp->cellp)
401 cm_GetServerNoLock(tsp);
402 lock_ReleaseRead(&cm_serverLock);
404 lock_ObtainMutex(&tsp->mx);
405 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
407 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
408 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
409 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
410 lock_ReleaseMutex(&tsp->mx);
411 lock_ObtainRead(&cm_serverLock);
412 cm_PutServerNoLock(tsp);
416 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
417 lock_ReleaseMutex(&tsp->mx);
419 serversp[nconns] = tsp;
420 code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
422 lock_ObtainRead(&cm_serverLock);
423 cm_PutServerNoLock(tsp);
426 lock_ObtainRead(&cm_serverLock);
427 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
428 if (conntimer[nconns] = (isDown ? 1 : 0))
429 rx_SetConnDeadTime(rxconns[nconns], 10);
433 lock_ReleaseRead(&cm_serverLock);
436 /* Perform the multi call */
438 multi_Rx(rxconns,nconns)
440 multi_RXAFS_GetCapabilities(&caps[multi_i]);
441 results[multi_i]=multi_error;
445 /* Process results of servers that support RXAFS_GetCapabilities */
446 for (i=0; i<nconns; i++) {
448 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
449 rx_PutConnection(rxconns[i]);
450 cm_PutConn(conns[i]);
453 cm_GCConnections(tsp);
455 lock_ObtainMutex(&tsp->mx);
456 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
458 if (results[i] >= 0 || results[i] == RXGEN_OPCODE) {
459 /* mark server as up */
460 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
463 /* we currently handle 32-bits of capabilities */
464 if (results[i] != RXGEN_OPCODE && caps[i].Capabilities_len > 0) {
465 tsp->capabilities = caps[i].Capabilities_val[0];
466 xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
467 caps[i].Capabilities_len = 0;
468 caps[i].Capabilities_val = 0;
470 tsp->capabilities = 0;
473 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
474 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
475 osi_LogSaveString(afsd_logp, hoststr),
476 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
479 /* Now update the volume status if necessary */
481 cm_server_vols_t * tsrvp;
485 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
486 for (i=0; i<NUM_SERVER_VOLS; i++) {
487 if (tsrvp->ids[i] != 0) {
490 lock_ReleaseMutex(&tsp->mx);
491 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
492 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
493 lock_ObtainMutex(&tsp->mx);
495 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
503 /* mark server as down */
504 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
505 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
506 tsp->downTime = time(NULL);
508 if (code != VRESTARTING) {
509 lock_ReleaseMutex(&tsp->mx);
510 cm_ForceNewConnections(tsp);
511 lock_ObtainMutex(&tsp->mx);
513 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
514 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
515 osi_LogSaveString(afsd_logp, hoststr),
516 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
519 /* Now update the volume status if necessary */
521 cm_server_vols_t * tsrvp;
525 for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
526 for (i=0; i<NUM_SERVER_VOLS; i++) {
527 if (tsrvp->ids[i] != 0) {
530 lock_ReleaseMutex(&tsp->mx);
531 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
532 &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
533 lock_ObtainMutex(&tsp->mx);
535 cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
544 if (tsp->waitCount == 0)
545 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
547 osi_Wakeup((LONG_PTR)tsp);
549 lock_ReleaseMutex(&tsp->mx);
555 if ((flags & CM_FLAG_CHECKVLDBSERVERS) ||
556 !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
558 lock_ObtainRead(&cm_serverLock);
559 for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
560 if (tsp->type != CM_SERVER_VLDB ||
561 tsp->cellp == NULL || /* SetPref only */
562 cellp && cellp != tsp->cellp)
565 cm_GetServerNoLock(tsp);
566 lock_ReleaseRead(&cm_serverLock);
568 lock_ObtainMutex(&tsp->mx);
569 isDown = tsp->flags & CM_SERVERFLAG_DOWN;
571 if ((tsp->flags & CM_SERVERFLAG_PINGING) ||
572 !((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
573 (!isDown && (flags & CM_FLAG_CHECKUPSERVERS)))) {
574 lock_ReleaseMutex(&tsp->mx);
575 lock_ObtainRead(&cm_serverLock);
576 cm_PutServerNoLock(tsp);
580 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PINGING);
581 lock_ReleaseMutex(&tsp->mx);
583 serversp[nconns] = tsp;
584 code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
586 lock_ObtainRead(&cm_serverLock);
587 cm_PutServerNoLock(tsp);
590 lock_ObtainRead(&cm_serverLock);
591 rxconns[nconns] = cm_GetRxConn(conns[nconns]);
592 conntimer[nconns] = (isDown ? 1 : 0);
594 rx_SetConnDeadTime(rxconns[nconns], 10);
598 lock_ReleaseRead(&cm_serverLock);
601 /* Perform the multi call */
603 multi_Rx(rxconns,nconns)
605 multi_VL_ProbeServer();
606 results[multi_i]=multi_error;
610 /* Process results of servers that support VL_ProbeServer */
611 for (i=0; i<nconns; i++) {
613 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
614 rx_PutConnection(rxconns[i]);
615 cm_PutConn(conns[i]);
618 cm_GCConnections(tsp);
620 lock_ObtainMutex(&tsp->mx);
621 wasDown = tsp->flags & CM_SERVERFLAG_DOWN;
623 if (results[i] >= 0) {
624 /* mark server as up */
625 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_DOWN);
627 tsp->capabilities = 0;
629 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
630 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is up with caps 0x%x",
631 osi_LogSaveString(afsd_logp, hoststr),
632 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
635 /* mark server as down */
636 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
637 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN);
638 tsp->downTime = time(NULL);
640 if (code != VRESTARTING) {
641 lock_ReleaseMutex(&tsp->mx);
642 cm_ForceNewConnections(tsp);
643 lock_ObtainMutex(&tsp->mx);
645 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
646 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
647 osi_LogSaveString(afsd_logp, hoststr),
648 tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
652 if (tsp->waitCount == 0)
653 _InterlockedAnd(&tsp->flags, ~CM_SERVERFLAG_PINGING);
655 osi_Wakeup((LONG_PTR)tsp);
657 lock_ReleaseMutex(&tsp->mx);
672 void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
679 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
680 0, KEY_QUERY_VALUE, &parmKey);
681 if (code == ERROR_SUCCESS) {
682 dummyLen = sizeof(multi);
683 code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
684 (BYTE *) &multi, &dummyLen);
685 RegCloseKey (parmKey);
689 cm_CheckServersMulti(flags, cellp);
691 cm_CheckServersSingular(flags, cellp);
694 void cm_InitServer(void)
696 static osi_once_t once;
698 if (osi_Once(&once)) {
699 lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
700 lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
705 /* Protected by cm_syscfgLock (rw) */
706 int cm_noIPAddr; /* number of client network interfaces */
707 int cm_IPAddr[CM_MAXINTERFACE_ADDR]; /* client's IP address in host order */
708 int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
709 int cm_NetMtu[CM_MAXINTERFACE_ADDR]; /* client's MTU sizes */
710 int cm_NetFlags[CM_MAXINTERFACE_ADDR]; /* network flags */
711 int cm_LanAdapterChangeDetected = 1;
713 void cm_SetLanAdapterChangeDetected(void)
715 lock_ObtainWrite(&cm_syscfgLock);
716 cm_LanAdapterChangeDetected = 1;
717 lock_ReleaseWrite(&cm_syscfgLock);
720 void cm_GetServer(cm_server_t *serverp)
722 lock_ObtainRead(&cm_serverLock);
723 InterlockedIncrement(&serverp->refCount);
724 lock_ReleaseRead(&cm_serverLock);
727 void cm_GetServerNoLock(cm_server_t *serverp)
729 InterlockedIncrement(&serverp->refCount);
732 void cm_PutServer(cm_server_t *serverp)
735 lock_ObtainRead(&cm_serverLock);
736 refCount = InterlockedDecrement(&serverp->refCount);
737 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
738 lock_ReleaseRead(&cm_serverLock);
741 void cm_PutServerNoLock(cm_server_t *serverp)
743 afs_int32 refCount = InterlockedDecrement(&serverp->refCount);
744 osi_assertx(refCount >= 0, "cm_server_t refCount underflow");
747 void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit)
749 lock_ObtainMutex(&serverp->mx);
751 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NO64BIT);
753 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NO64BIT);
754 lock_ReleaseMutex(&serverp->mx);
757 void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no)
759 lock_ObtainMutex(&serverp->mx);
761 _InterlockedOr(&serverp->flags, CM_SERVERFLAG_NOINLINEBULK);
763 _InterlockedAnd(&serverp->flags, ~CM_SERVERFLAG_NOINLINEBULK);
764 lock_ReleaseMutex(&serverp->mx);
767 void cm_SetServerPrefs(cm_server_t * serverp)
769 unsigned long serverAddr; /* in host byte order */
770 unsigned long myAddr, myNet, mySubnet;/* in host byte order */
771 unsigned long netMask;
776 lock_ObtainRead(&cm_syscfgLock);
777 if (cm_LanAdapterChangeDetected) {
778 lock_ConvertRToW(&cm_syscfgLock);
780 if (cm_LanAdapterChangeDetected) {
781 /* get network related info */
782 cm_noIPAddr = CM_MAXINTERFACE_ADDR;
783 code = syscfg_GetIFInfo(&cm_noIPAddr,
784 cm_IPAddr, cm_SubnetMask,
785 cm_NetMtu, cm_NetFlags);
786 cm_LanAdapterChangeDetected = 0;
788 lock_ConvertWToR(&cm_syscfgLock);
791 serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
792 serverp->ipRank = CM_IPRANK_LOW; /* default settings */
794 for ( i=0; i < cm_noIPAddr; i++)
796 /* loop through all the client's IP address and compare
797 ** each of them against the server's IP address */
799 myAddr = cm_IPAddr[i];
800 if ( IN_CLASSA(myAddr) )
801 netMask = IN_CLASSA_NET;
802 else if ( IN_CLASSB(myAddr) )
803 netMask = IN_CLASSB_NET;
804 else if ( IN_CLASSC(myAddr) )
805 netMask = IN_CLASSC_NET;
809 myNet = myAddr & netMask;
810 mySubnet = myAddr & cm_SubnetMask[i];
812 if ( (serverAddr & netMask) == myNet )
814 if ( (serverAddr & cm_SubnetMask[i]) == mySubnet)
816 if ( serverAddr == myAddr )
817 serverp->ipRank = min(serverp->ipRank,
818 CM_IPRANK_TOP);/* same machine */
819 else serverp->ipRank = min(serverp->ipRank,
820 CM_IPRANK_HI); /* same subnet */
822 else serverp->ipRank = min(serverp->ipRank,CM_IPRANK_MED);
825 } /* and of for loop */
827 /* random between 0..15*/
828 serverp->ipRank += (rand() % 0x000f);
829 lock_ReleaseRead(&cm_syscfgLock);
832 cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afsUUID *uuidp, afs_uint32 flags) {
835 osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
837 lock_ObtainWrite(&cm_serverLock); /* get server lock */
838 tsp = cm_FindServer(socketp, type, TRUE);
840 /* we might have found a server created by set server prefs */
841 if (uuidp && !afs_uuid_is_nil(uuidp) &&
842 !(tsp->flags & CM_SERVERFLAG_UUID))
845 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
847 lock_ReleaseWrite(&cm_serverLock);
851 tsp = malloc(sizeof(*tsp));
853 memset(tsp, 0, sizeof(*tsp));
856 if (uuidp && !afs_uuid_is_nil(uuidp)) {
858 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_UUID);
861 lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
862 tsp->addr = *socketp;
864 cm_SetServerPrefs(tsp);
866 tsp->allNextp = cm_allServersp;
867 cm_allServersp = tsp;
878 lock_ReleaseWrite(&cm_serverLock); /* release server lock */
880 if (!(flags & CM_FLAG_NOPROBE) && tsp) {
881 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_DOWN); /* assume down; ping will mark up if available */
882 cm_PingServer(tsp); /* Obtain Capabilities and check up/down state */
889 cm_FindServerByIP(afs_uint32 ipaddr, unsigned short port, int type, int locked)
894 lock_ObtainRead(&cm_serverLock);
896 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
897 if (tsp->type == type &&
898 tsp->addr.sin_addr.S_un.S_addr == ipaddr &&
899 (tsp->addr.sin_port == port || tsp->addr.sin_port == 0))
903 /* bump ref count if we found the server */
905 cm_GetServerNoLock(tsp);
908 lock_ReleaseRead(&cm_serverLock);
914 cm_FindServerByUuid(afsUUID *serverUuid, int type, int locked)
919 lock_ObtainRead(&cm_serverLock);
921 for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
922 if (tsp->type == type && !afs_uuid_equal(&tsp->uuid, serverUuid))
926 /* bump ref count if we found the server */
928 cm_GetServerNoLock(tsp);
931 lock_ReleaseRead(&cm_serverLock);
936 /* find a server based on its properties */
937 cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type, int locked)
939 osi_assertx(addrp->sin_family == AF_INET, "unexpected socket value");
941 return cm_FindServerByIP(addrp->sin_addr.s_addr, addrp->sin_port, type, locked);
944 cm_server_vols_t *cm_NewServerVols(void) {
945 cm_server_vols_t *tsvp;
947 tsvp = malloc(sizeof(*tsvp));
949 memset(tsvp, 0, sizeof(*tsvp));
955 * cm_NewServerRef() returns with the allocated cm_serverRef_t
956 * with a refCount of 1.
958 cm_serverRef_t *cm_NewServerRef(cm_server_t *serverp, afs_uint32 volID)
960 cm_serverRef_t *tsrp;
961 cm_server_vols_t **tsrvpp = NULL;
962 afs_uint32 *slotp = NULL;
965 cm_GetServer(serverp);
966 tsrp = malloc(sizeof(*tsrp));
967 tsrp->server = serverp;
968 tsrp->status = srv_not_busy;
973 /* if we have a non-zero volID, we need to add it to the list
974 * of volumes maintained by the server. There are two phases:
975 * (1) see if the volID is already in the list and (2) insert
976 * it into the first empty slot if it is not.
979 lock_ObtainMutex(&serverp->mx);
981 tsrvpp = &serverp->vols;
985 for (i=0; i<NUM_SERVER_VOLS; i++) {
986 if ((*tsrvpp)->ids[i] == volID) {
989 } else if (!slotp && (*tsrvpp)->ids[i] == 0) {
990 slotp = &(*tsrvpp)->ids[i];
997 tsrvpp = &(*tsrvpp)->nextp;
1004 /* if we didn't find an empty slot in a current
1005 * page we must need a new page */
1006 *tsrvpp = cm_NewServerVols();
1008 (*tsrvpp)->ids[0] = volID;
1012 lock_ReleaseMutex(&serverp->mx);
1018 void cm_GetServerRef(cm_serverRef_t *tsrp, int locked)
1023 lock_ObtainRead(&cm_serverLock);
1024 refCount = InterlockedIncrement(&tsrp->refCount);
1026 lock_ReleaseRead(&cm_serverLock);
1029 afs_int32 cm_PutServerRef(cm_serverRef_t *tsrp, int locked)
1034 lock_ObtainRead(&cm_serverLock);
1035 refCount = InterlockedDecrement(&tsrp->refCount);
1036 osi_assertx(refCount >= 0, "cm_serverRef_t refCount underflow");
1039 lock_ReleaseRead(&cm_serverLock);
1046 LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
1050 cm_serverRef_t *tsrp;
1052 lock_ObtainRead(&cm_serverLock);
1053 for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
1054 if (tsrp->status == srv_deleted)
1060 sum ^= (LONG_PTR) tsrp->server;
1063 lock_ReleaseRead(&cm_serverLock);
1068 ** Insert a server into the server list keeping the list sorted in
1069 ** ascending order of ipRank.
1071 ** The refCount of the cm_serverRef_t is not altered.
1073 void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
1075 cm_serverRef_t *current;
1076 unsigned short ipRank;
1078 lock_ObtainWrite(&cm_serverLock);
1080 * Since we are grabbing the serverLock exclusively remove any
1081 * deleted serverRef objects with a zero refcount before
1082 * inserting the new item.
1085 cm_serverRef_t **currentp = list;
1086 cm_serverRef_t **nextp = NULL;
1087 cm_serverRef_t * next = NULL;
1089 for (currentp = list; *currentp; currentp = nextp)
1091 nextp = &(*currentp)->next;
1092 if ((*currentp)->refCount == 0 &&
1093 (*currentp)->status == srv_deleted) {
1096 if ((*currentp)->volID)
1097 cm_RemoveVolumeFromServer((*currentp)->server, (*currentp)->volID);
1098 cm_FreeServer((*currentp)->server);
1105 /* insertion into empty list or at the beginning of the list */
1108 element->next = NULL;
1114 * Now that deleted entries have been removed and we know that the
1115 * list was not empty, look for duplicates. If the element we are
1116 * inserting already exists, discard it.
1118 for ( current = *list; current; current = current->next)
1120 cm_server_t * server1 = current->server;
1121 cm_server_t * server2 = element->server;
1123 if (current->status == srv_deleted)
1126 if (server1->type != server2->type)
1129 if (server1->addr.sin_addr.s_addr != server2->addr.sin_addr.s_addr)
1132 if ((server1->flags & CM_SERVERFLAG_UUID) != (server2->flags & CM_SERVERFLAG_UUID))
1135 if ((server1->flags & CM_SERVERFLAG_UUID) &&
1136 !afs_uuid_equal(&server1->uuid, &server2->uuid))
1139 /* we must have a match, discard the new element */
1144 ipRank = element->server->ipRank;
1146 /* insertion at the beginning of the list */
1147 if ((*list)->server->ipRank > ipRank)
1149 element->next = *list;
1154 /* find appropriate place to insert */
1155 for ( current = *list; current->next; current = current->next)
1157 if ( current->next->server->ipRank > ipRank )
1160 element->next = current->next;
1161 current->next = element;
1164 lock_ReleaseWrite(&cm_serverLock);
1167 ** Re-sort the server list with the modified rank
1168 ** returns 0 if element was changed successfully.
1169 ** returns 1 if list remained unchanged.
1171 long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t* server)
1173 cm_serverRef_t **current;
1174 cm_serverRef_t *element;
1176 lock_ObtainWrite(&cm_serverLock);
1180 /* if there is max of one element in the list, nothing to sort */
1181 if ( (!*current) || !((*current)->next) ) {
1182 lock_ReleaseWrite(&cm_serverLock);
1183 return 1; /* list unchanged: return success */
1186 /* if the server is on the list, delete it from list */
1189 if ( (*current)->server == server)
1191 element = (*current);
1192 *current = element->next; /* delete it */
1195 current = & ( (*current)->next);
1197 lock_ReleaseWrite(&cm_serverLock);
1199 /* if this volume is not replicated on this server */
1201 return 1; /* server is not on list */
1203 /* re-insert deleted element into the list with modified rank*/
1204 cm_InsertServerList(list, element);
1209 ** If there are more than one server on the list and the first n servers on
1210 ** the list have the same rank( n>1), then randomise among the first n servers.
1212 void cm_RandomizeServer(cm_serverRef_t** list)
1215 cm_serverRef_t* tsrp, *lastTsrp;
1216 unsigned short lowestRank;
1218 lock_ObtainWrite(&cm_serverLock);
1221 /* an empty list or a list with only one element */
1222 if ( !tsrp || ! tsrp->next ) {
1223 lock_ReleaseWrite(&cm_serverLock);
1227 /* count the number of servers with the lowest rank */
1228 lowestRank = tsrp->server->ipRank;
1229 for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
1231 if ( tsrp->server->ipRank != lowestRank)
1237 /* if there is only one server with the lowest rank, we are done */
1239 lock_ReleaseWrite(&cm_serverLock);
1243 picked = rand() % count;
1245 lock_ReleaseWrite(&cm_serverLock);
1250 while (--picked >= 0)
1255 lastTsrp->next = tsrp->next; /* delete random element from list*/
1256 tsrp->next = *list; /* insert element at the beginning of list */
1258 lock_ReleaseWrite(&cm_serverLock);
1261 /* call cm_FreeServer while holding a write lock on cm_serverLock */
1262 void cm_FreeServer(cm_server_t* serverp)
1264 cm_server_vols_t * tsrvp, *nextp;
1267 cm_PutServerNoLock(serverp);
1268 if (serverp->refCount == 0)
1271 * we need to check to ensure that all of the connections
1272 * for this server have a 0 refCount; otherwise, they will
1273 * not be garbage collected
1275 * must drop the cm_serverLock because cm_GCConnections
1276 * obtains the cm_connLock and that comes first in the
1279 lock_ReleaseWrite(&cm_serverLock);
1280 cm_GCConnections(serverp); /* connsp */
1281 lock_ObtainWrite(&cm_serverLock);
1286 * Once we have the cm_serverLock locked check to make
1287 * sure the refCount is still zero before removing the
1290 if (serverp->refCount == 0) {
1291 if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
1292 switch (serverp->type) {
1293 case CM_SERVER_VLDB:
1294 cm_numVldbServers--;
1296 case CM_SERVER_FILE:
1297 cm_numFileServers--;
1301 lock_FinalizeMutex(&serverp->mx);
1302 if ( cm_allServersp == serverp )
1303 cm_allServersp = serverp->allNextp;
1307 for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
1308 if ( tsp->allNextp == serverp ) {
1309 tsp->allNextp = serverp->allNextp;
1315 /* free the volid list */
1316 for ( tsrvp = serverp->vols; tsrvp; tsrvp = nextp) {
1317 nextp = tsrvp->nextp;
1326 /* Called with cm_serverLock write locked */
1327 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
1329 cm_server_vols_t * tsrvp;
1335 for (tsrvp = serverp->vols; tsrvp; tsrvp = tsrvp->nextp) {
1336 for (i=0; i<NUM_SERVER_VOLS; i++) {
1337 if (tsrvp->ids[i] == volID) {
1345 void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
1347 cm_serverRef_t **current;
1348 cm_serverRef_t **nextp;
1349 cm_serverRef_t * next;
1352 lock_ObtainWrite(&cm_serverLock);
1362 nextp = &(*current)->next;
1363 refCount = cm_PutServerRef(*current, TRUE);
1364 if (refCount == 0) {
1367 if ((*current)->volID)
1368 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1369 cm_FreeServer((*current)->server);
1373 if (flags & CM_FREESERVERLIST_DELETE) {
1374 (*current)->status = srv_deleted;
1375 if ((*current)->volID)
1376 cm_RemoveVolumeFromServer((*current)->server, (*current)->volID);
1384 lock_ReleaseWrite(&cm_serverLock);
1387 /* dump all servers to a file.
1388 * cookie is used to identify this batch for easy parsing,
1389 * and it a string provided by a caller
1391 int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
1400 lock_ObtainRead(&cm_serverLock);
1403 "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n",
1404 cookie, cm_numFileServers, cm_numVldbServers);
1405 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1407 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
1412 switch (tsp->type) {
1413 case CM_SERVER_VLDB:
1416 case CM_SERVER_FILE:
1423 afsUUID_to_string(&tsp->uuid, uuidstr, sizeof(uuidstr));
1424 afs_inet_ntoa_r(tsp->addr.sin_addr.s_addr, hoststr);
1425 down = ctime(&tsp->downTime);
1426 down[strlen(down)-1] = '\0';
1429 "%s - tsp=0x%p cell=%s addr=%-15s port=%u uuid=%s type=%s caps=0x%x "
1430 "flags=0x%x waitCount=%u rank=%u downTime=\"%s\" refCount=%u\r\n",
1431 cookie, tsp, tsp->cellp ? tsp->cellp->name : "", hoststr,
1432 ntohs(tsp->addr.sin_port), uuidstr, type,
1433 tsp->capabilities, tsp->flags, tsp->waitCount, tsp->ipRank,
1434 (tsp->flags & CM_SERVERFLAG_DOWN) ? down : "up",
1436 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1438 sprintf(output, "%s - Done dumping servers.\r\n", cookie);
1439 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
1442 lock_ReleaseRead(&cm_serverLock);
1448 * Determine if two servers are in fact the same.
1450 * Returns 1 if they match, 0 if they do not
1452 int cm_ServerEqual(cm_server_t *srv1, cm_server_t *srv2)
1456 if (srv1 == NULL || srv2 == NULL)
1462 if (srv1->flags & CM_SERVERFLAG_UUID) {
1463 if (!(srv2->flags & CM_SERVERFLAG_UUID))
1466 /* Both support UUID */
1467 if (UuidEqual((UUID *)&srv1->uuid, (UUID *)&srv2->uuid, &status))
1470 if (srv1->flags & CM_SERVERFLAG_UUID)
1473 /* Neither support UUID so perform an addr/port comparison */
1474 if ( srv1->addr.sin_family == srv2->addr.sin_family &&
1475 srv1->addr.sin_addr.s_addr == srv2->addr.sin_addr.s_addr &&
1476 srv1->addr.sin_port == srv2->addr.sin_port )