c1a0a9d1edbc76b9dfa8b1df69e0b2703826cffe
[openafs.git] / src / WINNT / afsd / cm_callback.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 #include <afs/param.h>
11 #include <afs/afs_args.h>
12 #include <afs/stds.h>
13
14 #include <windows.h>
15 #include <winsock2.h>
16 #include <malloc.h>
17 #include <string.h>
18 #include <stdlib.h>
19
20 #include <osi.h>
21
22 #include "afsd.h"
23
24 /* read/write lock for all global storage in this module */
25 osi_rwlock_t cm_callbackLock;
26
27 /* count of # of callback breaking messages received by this CM so far.  We use
28  * this count in determining whether there have been any callback breaks that
29  * apply to a call that returned a new callback.  If the counter doesn't
30  * increase during a call, then we know that no callbacks were broken during
31  * that call, and thus that the callback that was just returned is still valid.
32  */
33 long cm_callbackCount;
34
35 /* count of number of RPCs potentially returning a callback executing now.
36  * When this counter hits zero, we can clear out the racing revokes list, since
37  * at that time, we know that none of the just-executed callback revokes will
38  * apply to any future call that returns a callback (since the latter hasn't
39  * even started execution yet).
40  */
41 long cm_activeCallbackGrantingCalls;
42
43 /* list of callbacks that have been broken recently.  If a call returning a
44  * callback is executing and a callback revoke runs immediately after it at the
45  * server, the revoke may end up being processed before the response to the
46  * original callback granting call.  We detect this by keeping a list of
47  * callback revokes that have been received since we *started* the callback
48  * granting call, and discarding any callbacks received for the same file ID,
49  * even if the callback revoke was received before the callback grant.
50  */
51 cm_racingRevokes_t *cm_racingRevokesp;
52
53 /* record a (potentially) racing revoke for this file ID; null means for all
54  * file IDs, and is used by InitCallBackState.
55  *
56  * The cancelFlags describe whether we're just discarding callbacks for the same
57  * file ID, the same volume, or all from the same server.
58  *
59  * Called with no locks held.
60  */
61 void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
62 {
63         cm_racingRevokes_t *rp;
64
65         lock_ObtainWrite(&cm_callbackLock);
66         if (cm_activeCallbackGrantingCalls > 0) {
67                 rp = malloc(sizeof(*rp));
68                 memset(rp, 0, sizeof(*rp));
69                 osi_QAdd((osi_queue_t **) &cm_racingRevokesp, &rp->q);
70                 rp->flags |= (cancelFlags & CM_RACINGFLAG_ALL);
71                 if (fidp) rp->fid = *fidp;
72                 rp->callbackCount = ++cm_callbackCount;
73         }
74         lock_ReleaseWrite(&cm_callbackLock);
75 }
76
77 /*
78  * When we lose a callback, may have to send change notification replies.
79  */
80 void cm_CallbackNotifyChange(cm_scache_t *scp)
81 {
82         if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
83                 if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
84                         smb_NotifyChange(0,
85                          FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
86                          scp, NULL, NULL, TRUE);
87         } else {
88                 cm_fid_t tfid;
89                 cm_scache_t *dscp;
90
91                 tfid.cell = scp->fid.cell;
92                 tfid.volume = scp->fid.volume;
93                 tfid.vnode = scp->parentVnode;
94                 tfid.unique = scp->parentUnique;
95                 dscp = cm_FindSCache(&tfid);
96                 if (dscp &&
97                         dscp->flags & CM_SCACHEFLAG_ANYWATCH)
98                         smb_NotifyChange(0,
99                          FILE_NOTIFY_GENERIC_FILE_FILTER,
100                          dscp, NULL, NULL, TRUE);
101         }
102 }
103
104 /* called with no locks held for every file ID that is revoked directly by
105  * a callback revoke call.  Does not have to handle volume callback breaks,
106  * since those have already been split out.
107  *
108  * The callp parameter is currently unused.
109  */
110 void cm_RevokeCallback(struct rx_call *callp, AFSFid *fidp)
111 {
112         cm_fid_t tfid;
113         cm_scache_t *scp;
114         long hash;
115         
116         /* don't bother setting cell, since we won't be checking it (to aid
117          * in working with multi-homed servers: we don't know the cell if we
118          * don't recognize the IP address).
119          */
120         tfid.cell = 0;
121         tfid.volume = fidp->Volume;
122         tfid.vnode = fidp->Vnode;
123         tfid.unique = fidp->Unique;
124         hash = CM_SCACHE_HASH(&tfid);
125
126         osi_Log3(afsd_logp, "Revoke callback vol %d vn %d un %d",
127                  fidp->Volume, fidp->Vnode, fidp->Unique);
128         
129         /* do this first, so that if we're executing a callback granting call
130          * at this moment, we kill it before it can be merged in.  Otherwise,
131          * it could complete while we're doing the scan below, and get missed
132          * by both the scan and by this code.
133          */
134         cm_RecordRacingRevoke(&tfid, 0);
135
136         lock_ObtainWrite(&cm_scacheLock);
137         /* do all in the hash bucket, since we don't know how many we'll find with
138          * varying cells.
139          */
140         for(scp = cm_hashTablep[hash]; scp; scp=scp->nextp) {
141                 if (scp->fid.volume == tfid.volume &&
142                         scp->fid.vnode == tfid.vnode &&
143                         scp->fid.unique == tfid.unique) {
144                         scp->refCount++;
145                         lock_ReleaseWrite(&cm_scacheLock);
146                         osi_Log1(afsd_logp, "Revoke scp %x", scp);
147                         lock_ObtainMutex(&scp->mx);
148                         cm_DiscardSCache(scp);
149                         lock_ReleaseMutex(&scp->mx);
150                         cm_CallbackNotifyChange(scp);
151                         lock_ObtainWrite(&cm_scacheLock);
152                         scp->refCount--;
153                 }
154         }
155         lock_ReleaseWrite(&cm_scacheLock);
156 }
157
158 /* called to revoke a volume callback, which is typically issued when a volume
159  * is moved from one server to another.
160  *
161  * Called with no locks held.
162  */
163 void cm_RevokeVolumeCallback(struct rx_call *callp, AFSFid *fidp)
164 {
165         long hash;
166         cm_scache_t *scp;
167         cm_fid_t tfid;
168
169         /* do this first, so that if we're executing a callback granting call
170          * at this moment, we kill it before it can be merged in.  Otherwise,
171          * it could complete while we're doing the scan below, and get missed
172          * by both the scan and by this code.
173          */
174         tfid.cell = tfid.vnode = tfid.unique = 0;
175         tfid.volume = fidp->Volume;
176         cm_RecordRacingRevoke(&tfid, CM_RACINGFLAG_CANCELVOL);
177
178         osi_Log1(afsd_logp, "Revoke Volume %d", fidp->Volume);
179
180         lock_ObtainWrite(&cm_scacheLock);
181         for(hash = 0; hash < cm_hashTableSize; hash++) {
182                 for(scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
183                         if (scp->fid.volume == fidp->Volume) {
184                                 scp->refCount++;
185                                 lock_ReleaseWrite(&cm_scacheLock);
186                                 lock_ObtainMutex(&scp->mx);
187                                 cm_DiscardSCache(scp);
188                                 lock_ReleaseMutex(&scp->mx);
189                                 cm_CallbackNotifyChange(scp);
190                                 lock_ObtainWrite(&cm_scacheLock);
191                                 scp->refCount--;
192                         }
193                 }       /* search one hash bucket */
194         }       /* search all hash buckets */
195         
196         lock_ReleaseWrite(&cm_scacheLock);
197 }
198
199 /* handle incoming RPC callback breaking message.
200  * Called with no locks held.
201  */
202 SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArrayp)
203 {
204         int i;
205         AFSFid *tfidp;
206         
207         for(i=0; i < (long) fidsArrayp->AFSCBFids_len; i++) {
208                 tfidp = &fidsArrayp->AFSCBFids_val[i];
209                 
210                 if (tfidp->Volume == 0) continue;       /* means don't do anything */
211                 else if (tfidp->Vnode == 0)
212                         cm_RevokeVolumeCallback(callp, tfidp);
213                 else cm_RevokeCallback(callp, tfidp);
214         }
215
216         return 0;
217 }
218
219 /* called with no locks by RPC system when a server indicates that it has never
220  * heard from us, or for other reasons has had to discard callbacks from us
221  * without telling us, e.g. a network partition.
222  */
223 SRXAFSCB_InitCallBackState(struct rx_call *callp)
224 {
225     struct sockaddr_in taddr;
226     cm_server_t *tsp;
227     cm_scache_t *scp;
228     int hash;
229     int discarded;
230
231     if ((rx_ConnectionOf(callp)) && (rx_PeerOf(rx_ConnectionOf(callp)))) {
232         taddr.sin_family = AF_INET;
233         taddr.sin_addr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(callp)));
234
235         tsp = cm_FindServer(&taddr, CM_SERVER_FILE);
236
237         osi_Log1(afsd_logp, "Init Callback State server %x", tsp);
238         
239         /* record the callback in the racing revokes structure.  This
240          * shouldn't be necessary, since we shouldn't be making callback
241          * granting calls while we're going to get an initstate call,
242          * but there probably are some obscure races, so better safe
243          * than sorry.
244          *
245          * We do this first since we don't hold the cm_scacheLock and vnode
246          * locks over the entire callback scan operation below.  The
247          * big loop below is guaranteed to hit any callback already
248          * processed.  The call to RecordRacingRevoke is guaranteed
249          * to kill any callback that is currently being returned.
250          * Anything that sneaks past both must start
251          * after the call to RecordRacingRevoke.
252          */
253         cm_RecordRacingRevoke(NULL, CM_RACINGFLAG_CANCELALL);
254         
255         /* now search all vnodes looking for guys with this callback, if we
256          * found it, or guys with any callbacks, if we didn't find the server
257          * (that's how multihomed machines will appear and how we'll handle
258          * them, albeit a little inefficiently).  That is, we're discarding all
259          * callbacks from all hosts if we get an initstate call from an unknown
260          * host.  Since these calls are rare, and multihomed servers
261          * are "rare," hopefully this won't be a problem.
262          */
263         lock_ObtainWrite(&cm_scacheLock);
264         for(hash = 0; hash < cm_hashTableSize; hash++) {
265                 for(scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
266                         scp->refCount++;
267                         lock_ReleaseWrite(&cm_scacheLock);
268                         lock_ObtainMutex(&scp->mx);
269                         discarded = 0;
270                         if (scp->cbServerp != NULL) {
271                                 /* we have a callback, now decide if we should clear it */
272                                 if (scp->cbServerp == tsp || tsp == NULL) {
273                                         cm_DiscardSCache(scp);
274                                         discarded = 1;
275                                 }
276                         }
277                         lock_ReleaseMutex(&scp->mx);
278                         if (discarded)
279                                 cm_CallbackNotifyChange(scp);
280                         lock_ObtainWrite(&cm_scacheLock);
281                         scp->refCount--;
282                 }       /* search one hash bucket */
283         }       /* search all hash buckets */
284         
285         lock_ReleaseWrite(&cm_scacheLock);
286         
287         /* we're done with the server structure */
288         if (tsp) cm_PutServer(tsp);
289     }
290
291     return 0;
292 }
293
294 /* just returns if we're up */
295 SRXAFSCB_Probe(struct rx_call *callp)
296 {
297         return 0;
298 }
299
300 /* debug interface: not implemented */
301 SRXAFSCB_GetLock(struct rx_call *callp, long index, AFSDBLock *lockp)
302 {
303         /* XXXX */
304         return RXGEN_OPCODE;
305 }
306
307 /* debug interface: not implemented */
308 SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
309 {
310         /* XXXX */
311         return RXGEN_OPCODE;
312 }
313
314 /* debug interface: not implemented */
315 SRXAFSCB_XStatsVersion(struct rx_call *callp, long *vp)
316 {
317         /* XXXX */
318         *vp = -1;
319         return RXGEN_OPCODE;
320 }
321
322 /* debug interface: not implemented */
323 SRXAFSCB_GetXStats(struct rx_call *callp, long cvn, long coln, long *srvp, long *timep,
324         AFSCB_CollData *datap)
325 {
326         /* XXXX */
327         return RXGEN_OPCODE;
328 }
329
330 /* debug interface: not implemented */
331 SRXAFSCB_InitCallBackState2(struct rx_call *callp, struct interfaceAddr* addr)
332 {
333         /* XXXX */
334         return RXGEN_OPCODE;
335 }
336
337 /* debug interface: not implemented */
338 SRXAFSCB_WhoAreYou(struct rx_call *callp, struct interfaceAddr* addr)
339 {
340         /* XXXX */
341         return RXGEN_OPCODE;
342 }
343
344 /* debug interface: not implemented */
345 SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
346 {
347         /* XXXX */
348         return RXGEN_OPCODE;
349 }
350
351 /* debug interface: not implemented */
352 SRXAFSCB_ProbeUuid(struct rx_call *callp, afsUUID* clientUuid)
353 {
354         /* XXXX */
355         return RXGEN_OPCODE;
356 }
357
358 /*------------------------------------------------------------------------
359  * EXPORTED SRXAFSCB_GetServerPrefs
360  *
361  * Description:
362  *      Routine to list server preferences used by this client.
363  *
364  * Arguments:
365  *      a_call  : Ptr to Rx call on which this request came in.
366  *      a_index : Input server index
367  *      a_srvr_addr  : Output server address (0xffffffff on last server)
368  *      a_srvr_rank  : Output server rank
369  *
370  * Returns:
371  *      0 on success
372  *
373  * Environment:
374  *      Nothing interesting.
375  *
376  * Side Effects:
377  *      As advertised.
378  *------------------------------------------------------------------------*/
379
380 int SRXAFSCB_GetServerPrefs(
381     struct rx_call *a_call,
382     afs_int32 a_index,
383     afs_int32 *a_srvr_addr,
384     afs_int32 *a_srvr_rank)
385 {
386     *a_srvr_addr = 0xffffffff;
387     *a_srvr_rank = 0xffffffff;
388     return 0;
389 }
390
391 /*------------------------------------------------------------------------
392  * EXPORTED SRXAFSCB_GetCellServDB
393  *
394  * Description:
395  *      Routine to list cells configured for this client
396  *
397  * Arguments:
398  *      a_call  : Ptr to Rx call on which this request came in.
399  *      a_index : Input cell index
400  *      a_name  : Output cell name ("" on last cell)
401  *      a_hosts : Output cell database servers
402  *
403  * Returns:
404  *      0 on success
405  *
406  * Environment:
407  *      Nothing interesting.
408  *
409  * Side Effects:
410  *      As advertised.
411  *------------------------------------------------------------------------*/
412
413 int SRXAFSCB_GetCellServDB(
414     struct rx_call *a_call,
415     afs_int32 a_index,
416     char **a_name,
417     afs_int32 *a_hosts)
418 {
419     char *t_name;
420
421     t_name = (char *)malloc(AFSNAMEMAX);
422     t_name[0] = '\0';
423     *a_name = t_name;
424     bzero(a_hosts, AFSMAXCELLHOSTS * sizeof(afs_int32));
425     return 0;
426 }
427
428 /*------------------------------------------------------------------------
429  * EXPORTED SRXAFSCB_GetLocalCell
430  *
431  * Description:
432  *      Routine to return name of client's local cell
433  *
434  * Arguments:
435  *      a_call  : Ptr to Rx call on which this request came in.
436  *      a_name  : Output cell name
437  *
438  * Returns:
439  *      0 on success
440  *
441  * Environment:
442  *      Nothing interesting.
443  *
444  * Side Effects:
445  *      As advertised.
446  *------------------------------------------------------------------------*/
447
448 int SRXAFSCB_GetLocalCell(
449     struct rx_call *a_call,
450     char **a_name)
451 {
452     char *t_name;
453
454     t_name = (char *)malloc(AFSNAMEMAX);
455     if (cm_rootCellp) {
456         strcpy(t_name, cm_rootCellp->namep);
457     } else {
458         t_name[0] = '\0';
459     }
460     *a_name = t_name;
461     return 0;
462 }
463
464
465 /*
466  * afs_MarshallCacheConfig - marshall client cache configuration
467  *
468  * PARAMETERS
469  *
470  * IN callerVersion - the rpc stat version of the caller.
471  *
472  * IN config - client cache configuration.
473  *
474  * OUT ptr - buffer where configuration is marshalled.
475  *
476  * RETURN CODES
477  *
478  * Returns void.
479  */
480 static void afs_MarshallCacheConfig(
481     afs_uint32 callerVersion,
482     cm_initparams_v1 *config,
483     afs_uint32 *ptr)
484 {
485     /*
486      * We currently only support version 1.
487      */
488     *(ptr++) = config->nChunkFiles;
489     *(ptr++) = config->nStatCaches;
490     *(ptr++) = config->nDataCaches;
491     *(ptr++) = config->nVolumeCaches;
492     *(ptr++) = config->firstChunkSize;
493     *(ptr++) = config->otherChunkSize;
494     *(ptr++) = config->cacheSize;
495     *(ptr++) = config->setTime;
496     *(ptr++) = config->memCache;
497
498 }
499  
500
501 /*------------------------------------------------------------------------
502  * EXPORTED SRXAFSCB_GetCacheConfig
503  *
504  * Description:
505  *      Routine to return parameters used to initialize client cache.
506  *      Client may request any format version. Server may not return
507  *      format version greater than version requested by client.
508  *
509  * Arguments:
510  *      a_call:        Ptr to Rx call on which this request came in.
511  *      callerVersion: Data format version desired by the client.
512  *      serverVersion: Data format version of output data.
513  *      configCount:   Number bytes allocated for output data.
514  *      config:        Client cache configuration.
515  *
516  * Returns:
517  *      0 on success
518  *
519  * Environment:
520  *      Nothing interesting.
521  *
522  * Side Effects:
523  *      As advertised.
524  *------------------------------------------------------------------------*/
525
526 int SRXAFSCB_GetCacheConfig(a_call, callerVersion, serverVersion,
527                             configCount, config)
528 struct rx_call *a_call;
529 afs_uint32 callerVersion;
530 afs_uint32 *serverVersion;
531 afs_uint32 *configCount;
532 cacheConfig *config;
533 {
534     afs_uint32 *t_config;
535     size_t allocsize;
536     extern cm_initparams_v1 cm_initParams;
537
538     /*
539      * Currently only support version 1
540      */
541     allocsize = sizeof(cm_initparams_v1);
542     t_config = (afs_uint32 *)malloc(allocsize);
543
544     afs_MarshallCacheConfig(callerVersion, &cm_initParams, t_config);
545
546     *serverVersion = AFS_CLIENT_RETRIEVAL_FIRST_EDITION;
547     *configCount = allocsize;
548     config->cacheConfig_val = t_config;
549     config->cacheConfig_len = allocsize/sizeof(afs_uint32);
550
551     return 0;
552 }
553
554 /* called by afsd without any locks to initialize this module */
555 void cm_InitCallback(void)
556 {
557         lock_InitializeRWLock(&cm_callbackLock, "cm_callbackLock");
558         cm_activeCallbackGrantingCalls = 0;
559 }
560
561 /* called with locked scp; tells us whether we've got a callback.
562  * Expirations are checked by a background daemon so as to make
563  * this function as inexpensive as possible
564  */
565 int cm_HaveCallback(cm_scache_t *scp)
566 {
567         if (scp->cbServerp != NULL)
568                 return 1;
569         else return 0;
570 }
571
572 /* need to detect a broken callback that races with our obtaining a callback.
573  * Need to be able to do this even if we don't know the file ID of the file
574  * we're breaking the callback on at the time we start the acquisition of the
575  * callback (as in the case where we are creating a file).
576  *
577  * So, we start by writing down the count of the # of callbacks we've received
578  * so far, and bumping a global counter of the # of callback granting calls
579  * outstanding (all done under cm_callbackLock).
580  *
581  * When we're back from the call, we look at all of the callback revokes with
582  * counter numbers greater than the one we recorded in our caller's structure,
583  * and replay those that are higher than when we started the call.
584  * 
585  * We free all the structures in the queue when the count of the # of outstanding
586  * callback-granting calls drops to zero.
587  *
588  * We call this function with the scp locked, too, but in its current implementation,
589  * this knowledge is not used.
590  */
591 void cm_StartCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp)
592 {
593         lock_ObtainWrite(&cm_callbackLock);
594         cbrp->callbackCount = cm_callbackCount;
595         cm_activeCallbackGrantingCalls++;
596         cbrp->startTime = osi_Time();
597         cbrp->serverp = NULL;
598         lock_ReleaseWrite(&cm_callbackLock);
599 }
600
601 /* Called at the end of a callback-granting call, to remove the callback
602  * info from the scache entry, if necessary.
603  *
604  * Called with scp locked, so we can discard the callbacks easily with
605  * this locking hierarchy.
606  */
607 void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
608         AFSCallBack *cbp, long flags)
609 {
610         cm_racingRevokes_t *revp;               /* where we are */
611         cm_racingRevokes_t *nrevp;              /* where we'll be next */
612         int freeFlag;
613
614         lock_ObtainWrite(&cm_callbackLock);
615         if (flags & CM_CALLBACK_MAINTAINCOUNT) {
616                 osi_assert(cm_activeCallbackGrantingCalls > 0);
617         }
618         else {
619                 osi_assert(cm_activeCallbackGrantingCalls-- > 0);
620         }
621         if (cm_activeCallbackGrantingCalls == 0) freeFlag = 1;
622         else freeFlag = 0;
623
624         /* record the callback; we'll clear it below if we really lose it */
625         if (scp) {
626                 scp->cbServerp = cbrp->serverp;
627                 scp->cbExpires = cbrp->startTime + cbp->ExpirationTime;
628         }
629
630         /* a callback was actually revoked during our granting call, so
631          * run down the list of revoked fids, looking for ours.
632          * If activeCallbackGrantingCalls is zero, free the elements, too.
633          *
634          * May need to go through entire list just to do the freeing.
635          */
636         for(revp = cm_racingRevokesp; revp; revp = nrevp) {
637                 nrevp = (cm_racingRevokes_t *) osi_QNext(&revp->q);
638                 /* if this callback came in later than when we started the
639                  * callback-granting call, and if this fid is the right fid,
640                  * then clear the callback.
641                  */
642                 if (scp && cbrp->callbackCount != cm_callbackCount
643                         && revp->callbackCount > cbrp->callbackCount
644                         && (
645                                 (scp->fid.volume == revp->fid.volume &&
646                                  scp->fid.vnode == revp->fid.vnode &&
647                                  scp->fid.unique == revp->fid.unique)
648                             ||
649                                 ((revp->flags & CM_RACINGFLAG_CANCELVOL) &&
650                                  scp->fid.volume == revp->fid.volume)
651                             ||
652                                 (revp->flags & CM_RACINGFLAG_CANCELALL))) {
653                         /* this one matches */
654                         osi_Log4(afsd_logp,
655                         "Racing revoke scp %x old cbc %d rev cbc %d cur cbc %d",
656                                  scp,
657                                  cbrp->callbackCount, revp->callbackCount,
658                                  cm_callbackCount);
659                         cm_DiscardSCache(scp);
660                         /*
661                          * Since we don't have a callback to preserve, it's
662                          * OK to drop the lock and re-obtain it.
663                          */
664                         lock_ReleaseMutex(&scp->mx);
665                         cm_CallbackNotifyChange(scp);
666                         lock_ObtainMutex(&scp->mx);
667                 }
668                 if (freeFlag) free(revp);
669         }
670
671         /* if we freed the list, zap the pointer to it */
672         if (freeFlag) cm_racingRevokesp = NULL;
673
674         lock_ReleaseWrite(&cm_callbackLock);
675 }
676
677 /* if flags is 1, we want to force the code to make one call, anyway.
678  * called with locked scp; returns with same.
679  */
680 long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
681         struct cm_req *reqp, long flags)
682 {
683         long code;
684         cm_conn_t *connp;
685         AFSFetchStatus afsStatus;
686         AFSVolSync volSync;
687         AFSCallBack callback;
688         AFSFid tfid;
689         cm_callbackRequest_t cbr;
690         int mustCall;
691         long sflags;
692
693         mustCall = (flags & 1);
694         cm_AFSFidFromFid(&tfid, &scp->fid);
695         while (1) {
696                 if (!mustCall && cm_HaveCallback(scp)) return 0;
697
698                 /* turn off mustCall, since it has now forced us past the check above */
699                 mustCall = 0;
700
701                 /* otherwise, we have to make an RPC to get the status */
702                 sflags = CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK;
703                 cm_SyncOp(scp, NULL, NULL, NULL, 0, sflags);
704                 cm_StartCallbackGrantingCall(scp, &cbr);
705                 lock_ReleaseMutex(&scp->mx);
706                 
707                 /* now make the RPC */
708                 osi_Log1(afsd_logp, "CALL FetchStatus vp %x", (long) scp);
709                 do {
710                         code = cm_Conn(&scp->fid, userp, reqp, &connp);
711                         if (code) continue;
712                 
713                         code = RXAFS_FetchStatus(connp->callp, &tfid,
714                                 &afsStatus, &callback, &volSync);
715
716                 } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync,
717                                     &cbr, code));
718                 code = cm_MapRPCError(code, reqp);
719                 osi_Log0(afsd_logp, "CALL FetchStatus DONE");
720
721                 lock_ObtainMutex(&scp->mx);
722                 cm_SyncOpDone(scp, NULL, sflags);
723                 if (code == 0) {
724                         cm_EndCallbackGrantingCall(scp, &cbr, &callback, 0);
725                         cm_MergeStatus(scp, &afsStatus, &volSync, userp, 0);
726                 }
727                 else
728                         cm_EndCallbackGrantingCall(NULL, NULL, NULL, 0);
729
730                 /* now check to see if we got an error */
731                 if (code) return code;
732         }
733 }
734
735 /* called periodically by cm_daemon to shut down use of expired callbacks */
736 void cm_CheckCBExpiration(void)
737 {
738         int i;
739         cm_scache_t *scp;
740         long now;
741         
742         now = osi_Time();
743         lock_ObtainWrite(&cm_scacheLock);
744         for(i=0; i<cm_hashTableSize; i++) {
745                 for(scp = cm_hashTablep[i]; scp; scp=scp->nextp) {
746                         scp->refCount++;
747                         lock_ReleaseWrite(&cm_scacheLock);
748                         lock_ObtainMutex(&scp->mx);
749                         if (scp->cbServerp && now > scp->cbExpires) {
750                                 cm_DiscardSCache(scp);
751                         }
752                         lock_ReleaseMutex(&scp->mx);
753                         lock_ObtainWrite(&cm_scacheLock);
754                         osi_assert(scp->refCount-- > 0);
755                 }
756         }
757         lock_ReleaseWrite(&cm_scacheLock);
758 }