From 61e6f04009bba3ac13a8eda4a6663f4b6508dbc9 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 28 Jun 2007 05:04:21 +0000 Subject: [PATCH] windows-give-up-callbacks-20070627 This large patch adds support for giving up callbacks in response to three events: 1. power management suspend 2. power management shutdown 3. stat cache object recycling The third item is submitted as a condition compilation if GIVE_UP_CALLBACKS is defined. Properly handing callback give ups and the associated race conditions with revokes and fetch status requests requires a great deal of over head. The first attempt used one GiveUpCallBacks RPC for each callback that was being dropped as the stat cache object was recycled. This resulted in a 27% performance drop in the MIT stress test. The code that is being committed maintains a callback give up list on each server object. The callback is added to the list as the callbacks are dropped and then they are sent to the server in bulk by the background daemon thread if the server is known to be UP after a ping. Logic is added to the EndCallbackRequest and CallbackRevoke operations to ensure that race conditions are addressed. With all of this, there is a 17% performance drop in the MIT stress test. As a result, it is my conclusion that the client side costs associated with optimizing the load on the server are simply too high. I am committing this code to ensure that it is not lost. I will remove this support in the next patch while leaving the support for giving up all callbacks in response to suspend and shutdown events. --- src/WINNT/afsd/afsd_service.c | 16 +++- src/WINNT/afsd/cm_callback.c | 190 +++++++++++++++++++++++++++++++++++++++++- src/WINNT/afsd/cm_callback.h | 12 +++ src/WINNT/afsd/cm_scache.c | 53 ++++++++++-- src/WINNT/afsd/cm_scache.h | 2 + src/WINNT/afsd/cm_server.c | 100 ++++++++++++++++++++-- src/WINNT/afsd/cm_server.h | 25 +++++- 7 files changed, 375 insertions(+), 23 deletions(-) diff --git a/src/WINNT/afsd/afsd_service.c b/src/WINNT/afsd/afsd_service.c index 9b0fad4..20fc69d 100644 --- a/src/WINNT/afsd/afsd_service.c +++ b/src/WINNT/afsd/afsd_service.c @@ -311,16 +311,20 @@ afsd_ServiceControlHandlerEx( case PBT_APMQUERYSUSPEND: afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND"); /* Write all dirty buffers back to server */ - if ( !lana_OnlyLoopback() ) + if ( !lana_OnlyLoopback() ) { buf_CleanAndReset(); + cm_SuspendSCache(); + } afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete"); dwRet = NO_ERROR; break; case PBT_APMQUERYSTANDBY: afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY"); /* Write all dirty buffers back to server */ - if ( !lana_OnlyLoopback() ) + if ( !lana_OnlyLoopback() ) { buf_CleanAndReset(); + cm_SuspendSCache(); + } afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete"); dwRet = NO_ERROR; break; @@ -329,15 +333,19 @@ afsd_ServiceControlHandlerEx( case PBT_APMSUSPEND: afsi_log("SERVICE_CONTROL_APMSUSPEND"); powerStateSuspended = 1; - if (osVersion.dwMajorVersion >= 6) + if (osVersion.dwMajorVersion >= 6) { + cm_SuspendSCache(); smb_StopListeners(); + } dwRet = NO_ERROR; break; case PBT_APMSTANDBY: afsi_log("SERVICE_CONTROL_APMSTANDBY"); powerStateSuspended = 1; - if (osVersion.dwMajorVersion >= 6) + if (osVersion.dwMajorVersion >= 6) { + cm_SuspendSCache(); smb_StopListeners(); + } dwRet = NO_ERROR; break; case PBT_APMRESUMECRITICAL: diff --git a/src/WINNT/afsd/cm_callback.c b/src/WINNT/afsd/cm_callback.c index 1b694ec..80bf705 100644 --- a/src/WINNT/afsd/cm_callback.c +++ b/src/WINNT/afsd/cm_callback.c @@ -203,10 +203,19 @@ void cm_RevokeCallback(struct rx_call *callp, cm_cell_t * cellp, AFSFid *fidp) lock_ReleaseWrite(&cm_scacheLock); osi_Log4(afsd_logp, "RevokeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u", scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique); + +#ifdef GIVE_UP_CALLBACKS + lock_ObtainMutex(&scp->cbServerp->mx); + cm_RemoveFidFromGiveUpCallBackList(scp->cbServerp, &scp->fid); + lock_ReleaseMutex(&scp->cbServerp->mx); +#endif /* GIVE_UP_CALLBACKS */ + lock_ObtainMutex(&scp->mx); cm_DiscardSCache(scp); lock_ReleaseMutex(&scp->mx); + cm_CallbackNotifyChange(scp); + lock_ObtainWrite(&cm_scacheLock); cm_ReleaseSCacheNoLock(scp); } @@ -239,7 +248,6 @@ void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fi tfid.volume = fidp->Volume; cm_RecordRacingRevoke(&tfid, CM_RACINGFLAG_CANCELVOL); - lock_ObtainWrite(&cm_scacheLock); for (hash = 0; hash < cm_data.scacheHashTableSize; hash++) { for(scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) { @@ -249,11 +257,19 @@ void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fi scp->cbServerp != NULL) { cm_HoldSCacheNoLock(scp); lock_ReleaseWrite(&cm_scacheLock); + +#ifdef GIVE_UP_CALLBACKS + lock_ObtainMutex(&scp->cbServerp->mx); + cm_RemoveFidFromGiveUpCallBackList(scp->cbServerp, &scp->fid); + lock_ReleaseMutex(&scp->cbServerp->mx); +#endif /* GIVE_UP_CALLBACKS */ + lock_ObtainMutex(&scp->mx); osi_Log4(afsd_logp, "RevokeVolumeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u", scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique); cm_DiscardSCache(scp); lock_ReleaseMutex(&scp->mx); + cm_CallbackNotifyChange(scp); lock_ObtainWrite(&cm_scacheLock); cm_ReleaseSCacheNoLock(scp); @@ -350,7 +366,7 @@ SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArray host = rx_HostOf(peerp); port = rx_PortOf(peerp); - tsp = cm_FindServerByIP(host); + tsp = cm_FindServerByIP(host, CM_SERVER_FILE); if (tsp) cellp = tsp->cellp; } @@ -484,9 +500,24 @@ SRXAFSCB_InitCallBackState(struct rx_call *callp) cm_SetServerNo64Bit(tsp, 0); cm_SetServerNoInlineBulk(tsp, 0); +#ifdef GIVE_UP_CALLBACKS + /* Clear the callbacks list */ + lock_ObtainMutex(&tsp->mx); + cm_FreeGiveUpCallBackList(tsp); + lock_ReleaseMutex(&tsp->mx); +#endif /* GIVE_UP_CALLBACKS */ + /* we're done with the server structure */ cm_PutServer(tsp); - } + } +#ifdef GIVE_UP_CALLBACKS + else { + /* if we didn't recognize the server, we cleared all callbacks + * on all stat scache objects. So we must clear all of the + * Give Up CallBack lists */ + cm_FreeAllGiveUpCallBackLists(); + } +#endif /* GIVE_UP_CALLBACKS */ } MUTEX_EXIT(&callp->lock); return 0; @@ -1526,8 +1557,11 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp, cm_racingRevokes_t *revp; /* where we are */ cm_racingRevokes_t *nrevp; /* where we'll be next */ int freeFlag; - cm_server_t * serverp = 0; + cm_server_t * serverp = NULL; int discardScp = 0; +#ifdef GIVE_UP_CALLBACKS + int addFidToGUCB = 0; +#endif /* GIVE_UP_CALLBACKS */ lock_ObtainWrite(&cm_callbackLock); if (flags & CM_CALLBACK_MAINTAINCOUNT) { @@ -1546,6 +1580,9 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp, if (scp) { if (scp->cbServerp != cbrp->serverp) { serverp = scp->cbServerp; +#ifdef GIVE_UP_CALLBACKS + addFidToGUCB = 1; +#endif /* GIVE_UP_CALLBACKS */ if (!freeFlag) cm_GetServer(cbrp->serverp); scp->cbServerp = cbrp->serverp; @@ -1607,9 +1644,23 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp, lock_ReleaseMutex(&scp->mx); cm_CallbackNotifyChange(scp); lock_ObtainMutex(&scp->mx); + } +#ifdef GIVE_UP_CALLBACKS + else if (scp) { + lock_ObtainMutex(&scp->cbServerp->mx); + cm_RemoveFidFromGiveUpCallBackList(scp->cbServerp, &scp->fid); + lock_ReleaseMutex(&scp->cbServerp->mx); } +#endif /* GIVE_UP_CALLBACKS */ if ( serverp ) { +#ifdef GIVE_UP_CALLBACKS + if (addFidToGUCB) { + lock_ObtainMutex(&serverp->mx); + cm_AddFidToGiveUpCallBackList(serverp, &scp->fid); + lock_ReleaseMutex(&serverp->mx); + } +#endif /* GIVE_UP_CALLBACKS */ lock_ObtainWrite(&cm_serverLock); cm_FreeServer(serverp); lock_ReleaseWrite(&cm_serverLock); @@ -1780,3 +1831,134 @@ void cm_CheckCBExpiration(void) osi_Log0(afsd_logp, "CheckCBExpiration Complete"); } + +#ifdef GIVE_UP_CALLBACKS +/* server mutex must be held */ +/* do not hold cm_scacheLock */ +void cm_GiveUpCallBacksToServer(cm_server_t * serverp) +{ + struct AFSFid *tfids = NULL; + struct AFSCallBack callBacks[1]; + struct AFSCBFids fidArray; + struct AFSCBs cbArray; + afs_int32 code = 0; + cm_server_gucb_t *gucbp, *nextp; + cm_conn_t *connp; + struct rx_connection * callp; + cm_req_t req; + int i, j; + + for ( gucbp = serverp->gucbs, serverp->gucbs = NULL, lock_ReleaseMutex(&serverp->mx); + gucbp; + gucbp = nextp ) + { + nextp = gucbp->nextp; + + if (!tfids) { /* only need to do these once */ + tfids = (struct AFSFid *)malloc(AFS_MAXCBRSCALL * sizeof(*tfids)); + osi_Assert(tfids); + + fidArray.AFSCBFids_val = (struct AFSFid *)tfids; + + cbArray.AFSCBs_len = 1; + cbArray.AFSCBs_val = callBacks; + memset(&callBacks[0], 0, sizeof(callBacks[0])); + callBacks[0].CallBackType = CB_EXCLUSIVE; + } + memset(tfids, 0, AFS_MAXCBRSCALL * sizeof(*tfids)); + + for ( i=0, j=0; icount; i++ ) { + if (gucbp->fids[i].cell != 0) { + cm_AFSFidFromFid(&tfids[j++], &gucbp->fids[i]); + } + } + fidArray.AFSCBFids_len = j; + + cm_InitReq(&req); + req.flags |= CM_REQ_NORETRY; + + osi_Log1(afsd_logp, "CALL GiveUpCallbacks serverp %xp", serverp); + do { + code = cm_ConnByServer(serverp, cm_rootUserp, &connp); + if (code) + continue; + + callp = cm_GetRxConn(connp); + code = RXAFS_GiveUpCallBacks(callp, &fidArray, &cbArray); + rx_PutConnection(callp); + } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code)); + code = cm_MapRPCError(code, &req); + + if (code) + osi_Log1(afsd_logp, "CALL GiveUpCallback FAILURE, code 0x%x", code); + else + osi_Log0(afsd_logp, "CALL GiveUpCallback SUCCESS"); + + free(gucbp); + } + lock_ObtainMutex(&serverp->mx); +} + + +void +cm_GiveUpCallback(cm_scache_t * scp) +{ + time_t now; + + cm_HoldSCacheNoLock(scp); + now = osi_Time(); + + if (scp->cbExpires > 0 && (scp->cbServerp == NULL || now < scp->cbExpires)) { + lock_ObtainMutex(&scp->cbServerp->mx); + cm_AddFidToGiveUpCallBackList(scp->cbServerp, &scp->fid); + lock_ReleaseMutex(&scp->cbServerp->mx); + + /* assume the callbacks were given up even if we fail */ + cm_PutServer(scp->cbServerp); + scp->cbServerp = NULL; + scp->cbExpires = 0; + } + cm_ReleaseSCacheNoLock(scp); +} +#endif /* GIVE_UP_CALLBACKS */ + +void +cm_GiveUpAllCallbacks(cm_server_t *tsp) +{ + long code; + cm_conn_t *connp; + struct rx_connection * rxconnp; + + if (tsp->type == CM_SERVER_FILE) { + code = cm_ConnByServer(tsp, cm_rootUserp, &connp); + if (code == 0) { + rxconnp = cm_GetRxConn(connp); + code = RXAFS_GiveUpAllCallBacks(rxconnp); + rx_PutConnection(rxconnp); + + lock_ObtainMutex(&tsp->mx); +#ifdef GIVE_UP_CALLBACKS + cm_FreeGiveUpCallBackList(tsp); +#endif /* GIVE_UP_CALLBACKS */ + lock_ReleaseMutex(&tsp->mx); + } + } +} + +void +cm_GiveUpAllCallbacksAllServers(void) +{ + cm_server_t *tsp; + + lock_ObtainWrite(&cm_serverLock); + for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) { + cm_GetServerNoLock(tsp); + lock_ReleaseWrite(&cm_serverLock); + cm_GiveUpAllCallbacks(tsp); + lock_ObtainWrite(&cm_serverLock); + cm_PutServerNoLock(tsp); + } + lock_ReleaseWrite(&cm_serverLock); +} + + diff --git a/src/WINNT/afsd/cm_callback.h b/src/WINNT/afsd/cm_callback.h index 013777e..bb9c735 100644 --- a/src/WINNT/afsd/cm_callback.h +++ b/src/WINNT/afsd/cm_callback.h @@ -68,4 +68,16 @@ extern osi_rwlock_t cm_callbackLock; extern void cm_CallbackNotifyChange(cm_scache_t *scp); +#ifdef GIVE_UP_CALLBACKS +extern void cm_GiveUpCallback(struct cm_scache *); + +extern void cm_GiveUpCallBacksToServer(cm_server_t * serverp); + +#define AFS_MAXCBRSCALL 16 /* max to return in a given call */ +#endif /* GIVE_UP_CALLBACKS */ + +extern void cm_GiveUpAllCallbacks(cm_server_t *tsp); + +extern void cm_GiveUpAllCallbacksAllServers(void); + #endif /* _CM_CALLBACK_H_ENV__ */ diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index 6863ba2..70b1e22 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -160,17 +160,23 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags) scp->bulkStatProgress = hzero; scp->waitCount = 0; - scp->fid.vnode = 0; - scp->fid.volume = 0; - scp->fid.unique = 0; - scp->fid.cell = 0; - +#ifdef GIVE_UP_CALLBACKS /* discard callback */ if (scp->cbServerp) { - cm_PutServer(scp->cbServerp); - scp->cbServerp = NULL; + cm_GiveUpCallback(scp); + } +#else /* GIVE_UP_CALLBACKS */ + if (scp->cbServerp) { + cm_PutServer(scp->cbServerp); + scp->cbServerp = NULL; } scp->cbExpires = 0; +#endif /* GIVE_UP_CALLBACKS */ + + scp->fid.vnode = 0; + scp->fid.volume = 0; + scp->fid.unique = 0; + scp->fid.cell = 0; /* remove from dnlc */ cm_dnlcPurgedp(scp); @@ -447,11 +453,33 @@ cm_ValidateSCache(void) return cm_dnlcValidate(); } +void +cm_SuspendSCache(void) +{ + cm_scache_t * scp; + + cm_GiveUpAllCallbacksAllServers(); + + lock_ObtainWrite(&cm_scacheLock); + for ( scp = cm_data.allSCachesp; scp; + scp = scp->allNextp ) { + if (scp->cbServerp) { + cm_PutServer(scp->cbServerp); + scp->cbServerp = NULL; + } + scp->cbExpires = 0; + scp->flags &= ~CM_SCACHEFLAG_CALLBACK; + } + lock_ReleaseWrite(&cm_scacheLock); +} + long cm_ShutdownSCache(void) { cm_scache_t * scp; + lock_ObtainWrite(&cm_scacheLock); + for ( scp = cm_data.allSCachesp; scp; scp = scp->allNextp ) { if (scp->randomACLp) { @@ -459,9 +487,20 @@ cm_ShutdownSCache(void) cm_FreeAllACLEnts(scp); lock_ReleaseMutex(&scp->mx); } + + if (scp->cbServerp) { + cm_PutServer(scp->cbServerp); + scp->cbServerp = NULL; + } + scp->cbExpires = 0; + scp->flags &= ~CM_SCACHEFLAG_CALLBACK; + lock_FinalizeMutex(&scp->mx); lock_FinalizeRWLock(&scp->bufCreateLock); } + lock_ReleaseWrite(&cm_scacheLock); + + cm_GiveUpAllCallbacksAllServers(); return cm_dnlcShutdown(); } diff --git a/src/WINNT/afsd/cm_scache.h b/src/WINNT/afsd/cm_scache.h index d045143..0d28fbf 100644 --- a/src/WINNT/afsd/cm_scache.h +++ b/src/WINNT/afsd/cm_scache.h @@ -375,6 +375,8 @@ extern long cm_ValidateSCache(void); extern long cm_ShutdownSCache(void); +extern void cm_SuspendSCache(void); + extern long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags); extern void cm_RemoveSCacheFromHashTable(cm_scache_t *scp); diff --git a/src/WINNT/afsd/cm_server.c b/src/WINNT/afsd/cm_server.c index 827f65b..ac93fd4 100644 --- a/src/WINNT/afsd/cm_server.c +++ b/src/WINNT/afsd/cm_server.c @@ -232,6 +232,17 @@ void cm_CheckServers(long flags, cm_cell_t *cellp) if (doPing) cm_PingServer(tsp); +#ifdef GIVE_UP_CALLBACKS + /* if this is a file server and it is not currently down + * give up any callbacks we have queued + */ + if (isFS && !(tsp->flags & CM_SERVERFLAG_DOWN)) { + lock_ObtainMutex(&tsp->mx); + cm_GiveUpCallBacksToServer(tsp); + lock_ReleaseMutex(&tsp->mx); + } +#endif /* GIVE_UP_CALLBACKS */ + /* also, run the GC function for connections on all of the * server's connections. */ @@ -383,6 +394,22 @@ cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cell return tsp; } +cm_server_t * +cm_FindServerByIP(afs_uint32 ipaddr, int type) +{ + cm_server_t *tsp; + + lock_ObtainRead(&cm_serverLock); + for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) { + if (tsp->type == type && + tsp->addr.sin_addr.S_un.S_addr == ipaddr) + break; + } + lock_ReleaseRead(&cm_serverLock); + + return tsp; +} + /* find a server based on its properties */ cm_server_t *cm_FindServer(struct sockaddr_in *addrp, int type) { @@ -711,18 +738,77 @@ void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags) lock_ReleaseWrite(&cm_serverLock); } -cm_server_t * -cm_FindServerByIP(afs_uint32 ipaddr) +#ifdef GIVE_UP_CALLBACKS +cm_server_gucb_t *cm_NewServerGUCBs(void) { + cm_server_gucb_t *gucbp; + + gucbp = malloc(sizeof(*gucbp)); + if (gucbp) + memset(gucbp, 0, sizeof(*gucbp)); + + return gucbp; +} + + +/* server mutex must be held */ +void cm_AddFidToGiveUpCallBackList(cm_server_t * serverp, cm_fid_t *fidp) { + cm_server_gucb_t ** gucbpp; + + for ( gucbpp = &serverp->gucbs; *gucbpp; gucbpp = &(*gucbpp)->nextp ) { + if ((*gucbpp)->count < AFS_MAXCBRSCALL) { + (*gucbpp)->fids[(*gucbpp)->count] = *fidp; + (*gucbpp)->count++; + return; + } + } + + /* if we get here all of the allocated pages are full */ + (*gucbpp) = cm_NewServerGUCBs(); + if (*gucbpp) { + (*gucbpp)->fids[0] = *fidp; + (*gucbpp)->count = 1; + } +} + +/* server mutex must be held */ +void cm_RemoveFidFromGiveUpCallBackList(cm_server_t *serverp, cm_fid_t *fidp) { + cm_server_gucb_t *gucbp; + int i; + + for ( gucbp = serverp->gucbs; gucbp; gucbp = gucbp->nextp ) { + for ( i=0; i < gucbp->count; i++ ) { + if (cm_FidCmp(&gucbp->fids[i], fidp) == 0) { + /* invalidate this entry. we will skip over it later */ + gucbp->fids[i].cell = 0; + break; + } + } + } +} + +/* server mutex must be held */ +void cm_FreeGiveUpCallBackList(cm_server_t * serverp) +{ + cm_server_gucb_t *gucbp, *nextp; + + for ( gucbp = serverp->gucbs, serverp->gucbs = NULL; gucbp; gucbp = nextp ) { + nextp = gucbp->nextp; + free(gucbp); + } +} + +void cm_FreeAllGiveUpCallBackLists(void) { cm_server_t *tsp; lock_ObtainRead(&cm_serverLock); for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) { - if (tsp->addr.sin_addr.S_un.S_addr == ipaddr) - break; + if (tsp->type == CM_SERVER_FILE && tsp->gucbs != NULL) { + lock_ObtainMutex(&tsp->mx); + cm_FreeGiveUpCallBackList(tsp); + lock_ReleaseMutex(&tsp->mx); + } } lock_ReleaseRead(&cm_serverLock); - - return tsp; } - +#endif /* GIVE_UP_CALLBACKS */ diff --git a/src/WINNT/afsd/cm_server.h b/src/WINNT/afsd/cm_server.h index ba07030..5e8ad39 100644 --- a/src/WINNT/afsd/cm_server.h +++ b/src/WINNT/afsd/cm_server.h @@ -20,6 +20,15 @@ typedef struct cm_server_vols { struct cm_server_vols *nextp; } cm_server_vols_t; +#ifdef GIVE_UP_CALLBACKS +#define AFS_MAXCBRSCALL 16 +typedef struct cm_server_gucb { + afs_uint32 count; + cm_fid_t fids[AFS_MAXCBRSCALL]; + struct cm_server_gucb * nextp; +} cm_server_gucb_t; +#endif /* GIVE_UP_CALLBACKS */ + /* pointed to by volumes and cells without holds; cm_serverLock is obtained * at the appropriate times to change the pointers to these servers. */ @@ -36,6 +45,9 @@ typedef struct cm_server { osi_mutex_t mx; unsigned short ipRank; /* server priority */ cm_server_vols_t * vols; /* by mx */ +#ifdef GIVE_UP_CALLBACKS + cm_server_gucb_t * gucbs; /* by mx */ +#endif /* GIVE_UP_CALLBACKS */ } cm_server_t; enum repstate {srv_not_busy, srv_busy, srv_offline, srv_deleted}; @@ -121,6 +133,17 @@ extern void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit); extern void cm_SetServerNoInlineBulk(cm_server_t * serverp, int no); -extern cm_server_t * cm_FindServerByIP(afs_uint32 addr); +extern cm_server_t * cm_FindServerByIP(afs_uint32 addr, int type); + +#ifdef GIVE_UP_CALLBACKS +extern cm_server_gucb_t *cm_NewServerGUCBs(void); + +extern void cm_AddFidToGiveUpCallBackList(cm_server_t * serverp, cm_fid_t *fidp); + +extern void cm_RemoveFidFromGiveUpCallBackList(cm_server_t *serverp, cm_fid_t *fidp); + +extern void cm_FreeGiveUpCallBackList(cm_server_t * serverp); +extern void cm_FreeAllGiveUpCallBackLists(void); +#endif /* GIVE_UP_CALLBACKS */ #endif /* __CM_SERVER_H_ENV__ */ -- 1.9.4