2 * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
4 * (C) COPYRIGHT IBM CORPORATION 1987, 1988
5 * LICENSED MATERIALS - PROPERTY OF IBM
10 #include <afs/afs_args.h>
23 /* read/write lock for all global storage in this module */
24 osi_rwlock_t cm_callbackLock;
26 /* count of # of callback breaking messages received by this CM so far. We use
27 * this count in determining whether there have been any callback breaks that
28 * apply to a call that returned a new callback. If the counter doesn't
29 * increase during a call, then we know that no callbacks were broken during
30 * that call, and thus that the callback that was just returned is still valid.
32 long cm_callbackCount;
34 /* count of number of RPCs potentially returning a callback executing now.
35 * When this counter hits zero, we can clear out the racing revokes list, since
36 * at that time, we know that none of the just-executed callback revokes will
37 * apply to any future call that returns a callback (since the latter hasn't
38 * even started execution yet).
40 long cm_activeCallbackGrantingCalls;
42 /* list of callbacks that have been broken recently. If a call returning a
43 * callback is executing and a callback revoke runs immediately after it at the
44 * server, the revoke may end up being processed before the response to the
45 * original callback granting call. We detect this by keeping a list of
46 * callback revokes that have been received since we *started* the callback
47 * granting call, and discarding any callbacks received for the same file ID,
48 * even if the callback revoke was received before the callback grant.
50 cm_racingRevokes_t *cm_racingRevokesp;
52 /* record a (potentially) racing revoke for this file ID; null means for all
53 * file IDs, and is used by InitCallBackState.
55 * The cancelFlags describe whether we're just discarding callbacks for the same
56 * file ID, the same volume, or all from the same server.
58 * Called with no locks held.
60 void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
62 cm_racingRevokes_t *rp;
64 lock_ObtainWrite(&cm_callbackLock);
65 if (cm_activeCallbackGrantingCalls > 0) {
66 rp = malloc(sizeof(*rp));
67 memset(rp, 0, sizeof(*rp));
68 osi_QAdd((osi_queue_t **) &cm_racingRevokesp, &rp->q);
69 rp->flags |= (cancelFlags & CM_RACINGFLAG_ALL);
70 if (fidp) rp->fid = *fidp;
71 rp->callbackCount = ++cm_callbackCount;
73 lock_ReleaseWrite(&cm_callbackLock);
77 * When we lose a callback, may have to send change notification replies.
79 void cm_CallbackNotifyChange(cm_scache_t *scp)
81 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
82 if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
84 FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
85 scp, NULL, NULL, TRUE);
90 tfid.cell = scp->fid.cell;
91 tfid.volume = scp->fid.volume;
92 tfid.vnode = scp->parentVnode;
93 tfid.unique = scp->parentUnique;
94 dscp = cm_FindSCache(&tfid);
96 dscp->flags & CM_SCACHEFLAG_ANYWATCH)
98 FILE_NOTIFY_GENERIC_FILE_FILTER,
99 dscp, NULL, NULL, TRUE);
103 /* called with no locks held for every file ID that is revoked directly by
104 * a callback revoke call. Does not have to handle volume callback breaks,
105 * since those have already been split out.
107 * The callp parameter is currently unused.
109 void cm_RevokeCallback(struct rx_call *callp, AFSFid *fidp)
115 /* don't bother setting cell, since we won't be checking it (to aid
116 * in working with multi-homed servers: we don't know the cell if we
117 * don't recognize the IP address).
120 tfid.volume = fidp->Volume;
121 tfid.vnode = fidp->Vnode;
122 tfid.unique = fidp->Unique;
123 hash = CM_SCACHE_HASH(&tfid);
125 osi_Log3(afsd_logp, "Revoke callback vol %d vn %d un %d",
126 fidp->Volume, fidp->Vnode, fidp->Unique);
128 /* do this first, so that if we're executing a callback granting call
129 * at this moment, we kill it before it can be merged in. Otherwise,
130 * it could complete while we're doing the scan below, and get missed
131 * by both the scan and by this code.
133 cm_RecordRacingRevoke(&tfid, 0);
135 lock_ObtainWrite(&cm_scacheLock);
136 /* do all in the hash bucket, since we don't know how many we'll find with
139 for(scp = cm_hashTablep[hash]; scp; scp=scp->nextp) {
140 if (scp->fid.volume == tfid.volume &&
141 scp->fid.vnode == tfid.vnode &&
142 scp->fid.unique == tfid.unique) {
144 lock_ReleaseWrite(&cm_scacheLock);
145 osi_Log1(afsd_logp, "Revoke scp %x", scp);
146 lock_ObtainMutex(&scp->mx);
147 cm_DiscardSCache(scp);
148 lock_ReleaseMutex(&scp->mx);
149 cm_CallbackNotifyChange(scp);
150 lock_ObtainWrite(&cm_scacheLock);
154 lock_ReleaseWrite(&cm_scacheLock);
157 /* called to revoke a volume callback, which is typically issued when a volume
158 * is moved from one server to another.
160 * Called with no locks held.
162 void cm_RevokeVolumeCallback(struct rx_call *callp, AFSFid *fidp)
168 /* do this first, so that if we're executing a callback granting call
169 * at this moment, we kill it before it can be merged in. Otherwise,
170 * it could complete while we're doing the scan below, and get missed
171 * by both the scan and by this code.
173 tfid.cell = tfid.vnode = tfid.unique = 0;
174 tfid.volume = fidp->Volume;
175 cm_RecordRacingRevoke(&tfid, CM_RACINGFLAG_CANCELVOL);
177 osi_Log1(afsd_logp, "Revoke Volume %d", fidp->Volume);
179 lock_ObtainWrite(&cm_scacheLock);
180 for(hash = 0; hash < cm_hashTableSize; hash++) {
181 for(scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
182 if (scp->fid.volume == fidp->Volume) {
184 lock_ReleaseWrite(&cm_scacheLock);
185 lock_ObtainMutex(&scp->mx);
186 cm_DiscardSCache(scp);
187 lock_ReleaseMutex(&scp->mx);
188 cm_CallbackNotifyChange(scp);
189 lock_ObtainWrite(&cm_scacheLock);
192 } /* search one hash bucket */
193 } /* search all hash buckets */
195 lock_ReleaseWrite(&cm_scacheLock);
198 /* handle incoming RPC callback breaking message.
199 * Called with no locks held.
201 SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArrayp)
206 for(i=0; i < (long) fidsArrayp->AFSCBFids_len; i++) {
207 tfidp = &fidsArrayp->AFSCBFids_val[i];
209 if (tfidp->Volume == 0) continue; /* means don't do anything */
210 else if (tfidp->Vnode == 0)
211 cm_RevokeVolumeCallback(callp, tfidp);
212 else cm_RevokeCallback(callp, tfidp);
218 /* called with no locks by RPC system when a server indicates that it has never
219 * heard from us, or for other reasons has had to discard callbacks from us
220 * without telling us, e.g. a network partition.
222 SRXAFSCB_InitCallBackState(struct rx_call *callp)
224 struct sockaddr_in taddr;
230 if ((rx_ConnectionOf(callp)) && (rx_PeerOf(rx_ConnectionOf(callp)))) {
231 taddr.sin_family = AF_INET;
232 taddr.sin_addr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(callp)));
234 tsp = cm_FindServer(&taddr, CM_SERVER_FILE);
236 osi_Log1(afsd_logp, "Init Callback State server %x", tsp);
238 /* record the callback in the racing revokes structure. This
239 * shouldn't be necessary, since we shouldn't be making callback
240 * granting calls while we're going to get an initstate call,
241 * but there probably are some obscure races, so better safe
244 * We do this first since we don't hold the cm_scacheLock and vnode
245 * locks over the entire callback scan operation below. The
246 * big loop below is guaranteed to hit any callback already
247 * processed. The call to RecordRacingRevoke is guaranteed
248 * to kill any callback that is currently being returned.
249 * Anything that sneaks past both must start
250 * after the call to RecordRacingRevoke.
252 cm_RecordRacingRevoke(NULL, CM_RACINGFLAG_CANCELALL);
254 /* now search all vnodes looking for guys with this callback, if we
255 * found it, or guys with any callbacks, if we didn't find the server
256 * (that's how multihomed machines will appear and how we'll handle
257 * them, albeit a little inefficiently). That is, we're discarding all
258 * callbacks from all hosts if we get an initstate call from an unknown
259 * host. Since these calls are rare, and multihomed servers
260 * are "rare," hopefully this won't be a problem.
262 lock_ObtainWrite(&cm_scacheLock);
263 for(hash = 0; hash < cm_hashTableSize; hash++) {
264 for(scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
266 lock_ReleaseWrite(&cm_scacheLock);
267 lock_ObtainMutex(&scp->mx);
269 if (scp->cbServerp != NULL) {
270 /* we have a callback, now decide if we should clear it */
271 if (scp->cbServerp == tsp || tsp == NULL) {
272 cm_DiscardSCache(scp);
276 lock_ReleaseMutex(&scp->mx);
278 cm_CallbackNotifyChange(scp);
279 lock_ObtainWrite(&cm_scacheLock);
281 } /* search one hash bucket */
282 } /* search all hash buckets */
284 lock_ReleaseWrite(&cm_scacheLock);
286 /* we're done with the server structure */
287 if (tsp) cm_PutServer(tsp);
293 /* just returns if we're up */
294 SRXAFSCB_Probe(struct rx_call *callp)
299 /* debug interface: not implemented */
300 SRXAFSCB_GetLock(struct rx_call *callp, long index, AFSDBLock *lockp)
306 /* debug interface: not implemented */
307 SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
313 /* debug interface: not implemented */
314 SRXAFSCB_XStatsVersion(struct rx_call *callp, long *vp)
321 /* debug interface: not implemented */
322 SRXAFSCB_GetXStats(struct rx_call *callp, long cvn, long coln, long *srvp, long *timep,
323 AFSCB_CollData *datap)
329 /* debug interface: not implemented */
330 SRXAFSCB_InitCallBackState2(struct rx_call *callp, struct interfaceAddr* addr)
336 /* debug interface: not implemented */
337 SRXAFSCB_WhoAreYou(struct rx_call *callp, struct interfaceAddr* addr)
343 /* debug interface: not implemented */
344 SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
350 /* debug interface: not implemented */
351 SRXAFSCB_ProbeUuid(struct rx_call *callp, afsUUID* clientUuid)
357 /*------------------------------------------------------------------------
358 * EXPORTED SRXAFSCB_GetServerPrefs
361 * Routine to list server preferences used by this client.
364 * a_call : Ptr to Rx call on which this request came in.
365 * a_index : Input server index
366 * a_srvr_addr : Output server address (0xffffffff on last server)
367 * a_srvr_rank : Output server rank
373 * Nothing interesting.
377 *------------------------------------------------------------------------*/
379 int SRXAFSCB_GetServerPrefs(
380 struct rx_call *a_call,
382 afs_int32 *a_srvr_addr,
383 afs_int32 *a_srvr_rank)
385 *a_srvr_addr = 0xffffffff;
386 *a_srvr_rank = 0xffffffff;
390 /*------------------------------------------------------------------------
391 * EXPORTED SRXAFSCB_GetCellServDB
394 * Routine to list cells configured for this client
397 * a_call : Ptr to Rx call on which this request came in.
398 * a_index : Input cell index
399 * a_name : Output cell name ("" on last cell)
400 * a_hosts : Output cell database servers
406 * Nothing interesting.
410 *------------------------------------------------------------------------*/
412 int SRXAFSCB_GetCellServDB(
413 struct rx_call *a_call,
420 t_name = (char *)malloc(AFSNAMEMAX);
423 bzero(a_hosts, AFSMAXCELLHOSTS * sizeof(afs_int32));
427 /*------------------------------------------------------------------------
428 * EXPORTED SRXAFSCB_GetLocalCell
431 * Routine to return name of client's local cell
434 * a_call : Ptr to Rx call on which this request came in.
435 * a_name : Output cell name
441 * Nothing interesting.
445 *------------------------------------------------------------------------*/
447 int SRXAFSCB_GetLocalCell(
448 struct rx_call *a_call,
453 t_name = (char *)malloc(AFSNAMEMAX);
455 strcpy(t_name, cm_rootCellp->namep);
465 * afs_MarshallCacheConfig - marshall client cache configuration
469 * IN callerVersion - the rpc stat version of the caller.
471 * IN config - client cache configuration.
473 * OUT ptr - buffer where configuration is marshalled.
479 static void afs_MarshallCacheConfig(
480 afs_uint32 callerVersion,
481 cm_initparams_v1 *config,
485 * We currently only support version 1.
487 *(ptr++) = config->nChunkFiles;
488 *(ptr++) = config->nStatCaches;
489 *(ptr++) = config->nDataCaches;
490 *(ptr++) = config->nVolumeCaches;
491 *(ptr++) = config->firstChunkSize;
492 *(ptr++) = config->otherChunkSize;
493 *(ptr++) = config->cacheSize;
494 *(ptr++) = config->setTime;
495 *(ptr++) = config->memCache;
500 /*------------------------------------------------------------------------
501 * EXPORTED SRXAFSCB_GetCacheConfig
504 * Routine to return parameters used to initialize client cache.
505 * Client may request any format version. Server may not return
506 * format version greater than version requested by client.
509 * a_call: Ptr to Rx call on which this request came in.
510 * callerVersion: Data format version desired by the client.
511 * serverVersion: Data format version of output data.
512 * configCount: Number bytes allocated for output data.
513 * config: Client cache configuration.
519 * Nothing interesting.
523 *------------------------------------------------------------------------*/
525 int SRXAFSCB_GetCacheConfig(a_call, callerVersion, serverVersion,
527 struct rx_call *a_call;
528 afs_uint32 callerVersion;
529 afs_uint32 *serverVersion;
530 afs_uint32 *configCount;
533 afs_uint32 *t_config;
535 extern cm_initparams_v1 cm_initParams;
538 * Currently only support version 1
540 allocsize = sizeof(cm_initparams_v1);
541 t_config = (afs_uint32 *)malloc(allocsize);
543 afs_MarshallCacheConfig(callerVersion, &cm_initParams, t_config);
545 *serverVersion = AFS_CLIENT_RETRIEVAL_FIRST_EDITION;
546 *configCount = allocsize;
547 config->cacheConfig_val = t_config;
548 config->cacheConfig_len = allocsize/sizeof(afs_uint32);
553 /* called by afsd without any locks to initialize this module */
554 void cm_InitCallback(void)
556 lock_InitializeRWLock(&cm_callbackLock, "cm_callbackLock");
557 cm_activeCallbackGrantingCalls = 0;
560 /* called with locked scp; tells us whether we've got a callback.
561 * Expirations are checked by a background daemon so as to make
562 * this function as inexpensive as possible
564 int cm_HaveCallback(cm_scache_t *scp)
566 if (scp->cbServerp != NULL)
571 /* need to detect a broken callback that races with our obtaining a callback.
572 * Need to be able to do this even if we don't know the file ID of the file
573 * we're breaking the callback on at the time we start the acquisition of the
574 * callback (as in the case where we are creating a file).
576 * So, we start by writing down the count of the # of callbacks we've received
577 * so far, and bumping a global counter of the # of callback granting calls
578 * outstanding (all done under cm_callbackLock).
580 * When we're back from the call, we look at all of the callback revokes with
581 * counter numbers greater than the one we recorded in our caller's structure,
582 * and replay those that are higher than when we started the call.
584 * We free all the structures in the queue when the count of the # of outstanding
585 * callback-granting calls drops to zero.
587 * We call this function with the scp locked, too, but in its current implementation,
588 * this knowledge is not used.
590 void cm_StartCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp)
592 lock_ObtainWrite(&cm_callbackLock);
593 cbrp->callbackCount = cm_callbackCount;
594 cm_activeCallbackGrantingCalls++;
595 cbrp->startTime = osi_Time();
596 cbrp->serverp = NULL;
597 lock_ReleaseWrite(&cm_callbackLock);
600 /* Called at the end of a callback-granting call, to remove the callback
601 * info from the scache entry, if necessary.
603 * Called with scp locked, so we can discard the callbacks easily with
604 * this locking hierarchy.
606 void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
607 AFSCallBack *cbp, long flags)
609 cm_racingRevokes_t *revp; /* where we are */
610 cm_racingRevokes_t *nrevp; /* where we'll be next */
613 lock_ObtainWrite(&cm_callbackLock);
614 if (flags & CM_CALLBACK_MAINTAINCOUNT) {
615 osi_assert(cm_activeCallbackGrantingCalls > 0);
618 osi_assert(cm_activeCallbackGrantingCalls-- > 0);
620 if (cm_activeCallbackGrantingCalls == 0) freeFlag = 1;
623 /* record the callback; we'll clear it below if we really lose it */
625 scp->cbServerp = cbrp->serverp;
626 scp->cbExpires = cbrp->startTime + cbp->ExpirationTime;
629 /* a callback was actually revoked during our granting call, so
630 * run down the list of revoked fids, looking for ours.
631 * If activeCallbackGrantingCalls is zero, free the elements, too.
633 * May need to go through entire list just to do the freeing.
635 for(revp = cm_racingRevokesp; revp; revp = nrevp) {
636 nrevp = (cm_racingRevokes_t *) osi_QNext(&revp->q);
637 /* if this callback came in later than when we started the
638 * callback-granting call, and if this fid is the right fid,
639 * then clear the callback.
641 if (scp && cbrp->callbackCount != cm_callbackCount
642 && revp->callbackCount > cbrp->callbackCount
644 (scp->fid.volume == revp->fid.volume &&
645 scp->fid.vnode == revp->fid.vnode &&
646 scp->fid.unique == revp->fid.unique)
648 ((revp->flags & CM_RACINGFLAG_CANCELVOL) &&
649 scp->fid.volume == revp->fid.volume)
651 (revp->flags & CM_RACINGFLAG_CANCELALL))) {
652 /* this one matches */
654 "Racing revoke scp %x old cbc %d rev cbc %d cur cbc %d",
656 cbrp->callbackCount, revp->callbackCount,
658 cm_DiscardSCache(scp);
660 * Since we don't have a callback to preserve, it's
661 * OK to drop the lock and re-obtain it.
663 lock_ReleaseMutex(&scp->mx);
664 cm_CallbackNotifyChange(scp);
665 lock_ObtainMutex(&scp->mx);
667 if (freeFlag) free(revp);
670 /* if we freed the list, zap the pointer to it */
671 if (freeFlag) cm_racingRevokesp = NULL;
673 lock_ReleaseWrite(&cm_callbackLock);
676 /* if flags is 1, we want to force the code to make one call, anyway.
677 * called with locked scp; returns with same.
679 long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
680 struct cm_req *reqp, long flags)
684 AFSFetchStatus afsStatus;
686 AFSCallBack callback;
688 cm_callbackRequest_t cbr;
692 mustCall = (flags & 1);
693 cm_AFSFidFromFid(&tfid, &scp->fid);
695 if (!mustCall && cm_HaveCallback(scp)) return 0;
697 /* turn off mustCall, since it has now forced us past the check above */
700 /* otherwise, we have to make an RPC to get the status */
701 sflags = CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK;
702 cm_SyncOp(scp, NULL, NULL, NULL, 0, sflags);
703 cm_StartCallbackGrantingCall(scp, &cbr);
704 lock_ReleaseMutex(&scp->mx);
706 /* now make the RPC */
707 osi_Log1(afsd_logp, "CALL FetchStatus vp %x", (long) scp);
709 code = cm_Conn(&scp->fid, userp, reqp, &connp);
712 code = RXAFS_FetchStatus(connp->callp, &tfid,
713 &afsStatus, &callback, &volSync);
715 } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync,
717 code = cm_MapRPCError(code, reqp);
718 osi_Log0(afsd_logp, "CALL FetchStatus DONE");
720 lock_ObtainMutex(&scp->mx);
721 cm_SyncOpDone(scp, NULL, sflags);
723 cm_EndCallbackGrantingCall(scp, &cbr, &callback, 0);
724 cm_MergeStatus(scp, &afsStatus, &volSync, userp, 0);
727 cm_EndCallbackGrantingCall(NULL, NULL, NULL, 0);
729 /* now check to see if we got an error */
730 if (code) return code;
734 /* called periodically by cm_daemon to shut down use of expired callbacks */
735 void cm_CheckCBExpiration(void)
742 lock_ObtainWrite(&cm_scacheLock);
743 for(i=0; i<cm_hashTableSize; i++) {
744 for(scp = cm_hashTablep[i]; scp; scp=scp->nextp) {
746 lock_ReleaseWrite(&cm_scacheLock);
747 lock_ObtainMutex(&scp->mx);
748 if (scp->cbServerp && now > scp->cbExpires) {
749 cm_DiscardSCache(scp);
751 lock_ReleaseMutex(&scp->mx);
752 lock_ObtainWrite(&cm_scacheLock);
753 osi_assert(scp->refCount-- > 0);
756 lock_ReleaseWrite(&cm_scacheLock);