Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / afsd / cm_callback.c
1 /* 
2  * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
3  *
4  * (C) COPYRIGHT IBM CORPORATION 1987, 1988
5  * LICENSED MATERIALS - PROPERTY OF IBM
6  *
7  *
8  */
9 #include <afs/param.h>
10 #include <afs/afs_args.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <winsock2.h>
15 #include <malloc.h>
16 #include <string.h>
17 #include <stdlib.h>
18
19 #include <osi.h>
20
21 #include "afsd.h"
22
23 /* read/write lock for all global storage in this module */
24 osi_rwlock_t cm_callbackLock;
25
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.
31  */
32 long cm_callbackCount;
33
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).
39  */
40 long cm_activeCallbackGrantingCalls;
41
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.
49  */
50 cm_racingRevokes_t *cm_racingRevokesp;
51
52 /* record a (potentially) racing revoke for this file ID; null means for all
53  * file IDs, and is used by InitCallBackState.
54  *
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.
57  *
58  * Called with no locks held.
59  */
60 void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
61 {
62         cm_racingRevokes_t *rp;
63
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;
72         }
73         lock_ReleaseWrite(&cm_callbackLock);
74 }
75
76 /*
77  * When we lose a callback, may have to send change notification replies.
78  */
79 void cm_CallbackNotifyChange(cm_scache_t *scp)
80 {
81         if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
82                 if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
83                         smb_NotifyChange(0,
84                          FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
85                          scp, NULL, NULL, TRUE);
86         } else {
87                 cm_fid_t tfid;
88                 cm_scache_t *dscp;
89
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);
95                 if (dscp &&
96                         dscp->flags & CM_SCACHEFLAG_ANYWATCH)
97                         smb_NotifyChange(0,
98                          FILE_NOTIFY_GENERIC_FILE_FILTER,
99                          dscp, NULL, NULL, TRUE);
100         }
101 }
102
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.
106  *
107  * The callp parameter is currently unused.
108  */
109 void cm_RevokeCallback(struct rx_call *callp, AFSFid *fidp)
110 {
111         cm_fid_t tfid;
112         cm_scache_t *scp;
113         long hash;
114         
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).
118          */
119         tfid.cell = 0;
120         tfid.volume = fidp->Volume;
121         tfid.vnode = fidp->Vnode;
122         tfid.unique = fidp->Unique;
123         hash = CM_SCACHE_HASH(&tfid);
124
125         osi_Log3(afsd_logp, "Revoke callback vol %d vn %d un %d",
126                  fidp->Volume, fidp->Vnode, fidp->Unique);
127         
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.
132          */
133         cm_RecordRacingRevoke(&tfid, 0);
134
135         lock_ObtainWrite(&cm_scacheLock);
136         /* do all in the hash bucket, since we don't know how many we'll find with
137          * varying cells.
138          */
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) {
143                         scp->refCount++;
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);
151                         scp->refCount--;
152                 }
153         }
154         lock_ReleaseWrite(&cm_scacheLock);
155 }
156
157 /* called to revoke a volume callback, which is typically issued when a volume
158  * is moved from one server to another.
159  *
160  * Called with no locks held.
161  */
162 void cm_RevokeVolumeCallback(struct rx_call *callp, AFSFid *fidp)
163 {
164         long hash;
165         cm_scache_t *scp;
166         cm_fid_t tfid;
167
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.
172          */
173         tfid.cell = tfid.vnode = tfid.unique = 0;
174         tfid.volume = fidp->Volume;
175         cm_RecordRacingRevoke(&tfid, CM_RACINGFLAG_CANCELVOL);
176
177         osi_Log1(afsd_logp, "Revoke Volume %d", fidp->Volume);
178
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) {
183                                 scp->refCount++;
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);
190                                 scp->refCount--;
191                         }
192                 }       /* search one hash bucket */
193         }       /* search all hash buckets */
194         
195         lock_ReleaseWrite(&cm_scacheLock);
196 }
197
198 /* handle incoming RPC callback breaking message.
199  * Called with no locks held.
200  */
201 SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArrayp)
202 {
203         int i;
204         AFSFid *tfidp;
205         
206         for(i=0; i < (long) fidsArrayp->AFSCBFids_len; i++) {
207                 tfidp = &fidsArrayp->AFSCBFids_val[i];
208                 
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);
213         }
214
215         return 0;
216 }
217
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.
221  */
222 SRXAFSCB_InitCallBackState(struct rx_call *callp)
223 {
224     struct sockaddr_in taddr;
225     cm_server_t *tsp;
226     cm_scache_t *scp;
227     int hash;
228     int discarded;
229
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)));
233
234         tsp = cm_FindServer(&taddr, CM_SERVER_FILE);
235
236         osi_Log1(afsd_logp, "Init Callback State server %x", tsp);
237         
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
242          * than sorry.
243          *
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.
251          */
252         cm_RecordRacingRevoke(NULL, CM_RACINGFLAG_CANCELALL);
253         
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.
261          */
262         lock_ObtainWrite(&cm_scacheLock);
263         for(hash = 0; hash < cm_hashTableSize; hash++) {
264                 for(scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
265                         scp->refCount++;
266                         lock_ReleaseWrite(&cm_scacheLock);
267                         lock_ObtainMutex(&scp->mx);
268                         discarded = 0;
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);
273                                         discarded = 1;
274                                 }
275                         }
276                         lock_ReleaseMutex(&scp->mx);
277                         if (discarded)
278                                 cm_CallbackNotifyChange(scp);
279                         lock_ObtainWrite(&cm_scacheLock);
280                         scp->refCount--;
281                 }       /* search one hash bucket */
282         }       /* search all hash buckets */
283         
284         lock_ReleaseWrite(&cm_scacheLock);
285         
286         /* we're done with the server structure */
287         if (tsp) cm_PutServer(tsp);
288     }
289
290     return 0;
291 }
292
293 /* just returns if we're up */
294 SRXAFSCB_Probe(struct rx_call *callp)
295 {
296         return 0;
297 }
298
299 /* debug interface: not implemented */
300 SRXAFSCB_GetLock(struct rx_call *callp, long index, AFSDBLock *lockp)
301 {
302         /* XXXX */
303         return RXGEN_OPCODE;
304 }
305
306 /* debug interface: not implemented */
307 SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
308 {
309         /* XXXX */
310         return RXGEN_OPCODE;
311 }
312
313 /* debug interface: not implemented */
314 SRXAFSCB_XStatsVersion(struct rx_call *callp, long *vp)
315 {
316         /* XXXX */
317         *vp = -1;
318         return RXGEN_OPCODE;
319 }
320
321 /* debug interface: not implemented */
322 SRXAFSCB_GetXStats(struct rx_call *callp, long cvn, long coln, long *srvp, long *timep,
323         AFSCB_CollData *datap)
324 {
325         /* XXXX */
326         return RXGEN_OPCODE;
327 }
328
329 /* debug interface: not implemented */
330 SRXAFSCB_InitCallBackState2(struct rx_call *callp, struct interfaceAddr* addr)
331 {
332         /* XXXX */
333         return RXGEN_OPCODE;
334 }
335
336 /* debug interface: not implemented */
337 SRXAFSCB_WhoAreYou(struct rx_call *callp, struct interfaceAddr* addr)
338 {
339         /* XXXX */
340         return RXGEN_OPCODE;
341 }
342
343 /* debug interface: not implemented */
344 SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
345 {
346         /* XXXX */
347         return RXGEN_OPCODE;
348 }
349
350 /* debug interface: not implemented */
351 SRXAFSCB_ProbeUuid(struct rx_call *callp, afsUUID* clientUuid)
352 {
353         /* XXXX */
354         return RXGEN_OPCODE;
355 }
356
357 /*------------------------------------------------------------------------
358  * EXPORTED SRXAFSCB_GetServerPrefs
359  *
360  * Description:
361  *      Routine to list server preferences used by this client.
362  *
363  * Arguments:
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
368  *
369  * Returns:
370  *      0 on success
371  *
372  * Environment:
373  *      Nothing interesting.
374  *
375  * Side Effects:
376  *      As advertised.
377  *------------------------------------------------------------------------*/
378
379 int SRXAFSCB_GetServerPrefs(
380     struct rx_call *a_call,
381     afs_int32 a_index,
382     afs_int32 *a_srvr_addr,
383     afs_int32 *a_srvr_rank)
384 {
385     *a_srvr_addr = 0xffffffff;
386     *a_srvr_rank = 0xffffffff;
387     return 0;
388 }
389
390 /*------------------------------------------------------------------------
391  * EXPORTED SRXAFSCB_GetCellServDB
392  *
393  * Description:
394  *      Routine to list cells configured for this client
395  *
396  * Arguments:
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
401  *
402  * Returns:
403  *      0 on success
404  *
405  * Environment:
406  *      Nothing interesting.
407  *
408  * Side Effects:
409  *      As advertised.
410  *------------------------------------------------------------------------*/
411
412 int SRXAFSCB_GetCellServDB(
413     struct rx_call *a_call,
414     afs_int32 a_index,
415     char **a_name,
416     afs_int32 *a_hosts)
417 {
418     char *t_name;
419
420     t_name = (char *)malloc(AFSNAMEMAX);
421     t_name[0] = '\0';
422     *a_name = t_name;
423     bzero(a_hosts, AFSMAXCELLHOSTS * sizeof(afs_int32));
424     return 0;
425 }
426
427 /*------------------------------------------------------------------------
428  * EXPORTED SRXAFSCB_GetLocalCell
429  *
430  * Description:
431  *      Routine to return name of client's local cell
432  *
433  * Arguments:
434  *      a_call  : Ptr to Rx call on which this request came in.
435  *      a_name  : Output cell name
436  *
437  * Returns:
438  *      0 on success
439  *
440  * Environment:
441  *      Nothing interesting.
442  *
443  * Side Effects:
444  *      As advertised.
445  *------------------------------------------------------------------------*/
446
447 int SRXAFSCB_GetLocalCell(
448     struct rx_call *a_call,
449     char **a_name)
450 {
451     char *t_name;
452
453     t_name = (char *)malloc(AFSNAMEMAX);
454     if (cm_rootCellp) {
455         strcpy(t_name, cm_rootCellp->namep);
456     } else {
457         t_name[0] = '\0';
458     }
459     *a_name = t_name;
460     return 0;
461 }
462
463
464 /*
465  * afs_MarshallCacheConfig - marshall client cache configuration
466  *
467  * PARAMETERS
468  *
469  * IN callerVersion - the rpc stat version of the caller.
470  *
471  * IN config - client cache configuration.
472  *
473  * OUT ptr - buffer where configuration is marshalled.
474  *
475  * RETURN CODES
476  *
477  * Returns void.
478  */
479 static void afs_MarshallCacheConfig(
480     afs_uint32 callerVersion,
481     cm_initparams_v1 *config,
482     afs_uint32 *ptr)
483 {
484     /*
485      * We currently only support version 1.
486      */
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;
496
497 }
498  
499
500 /*------------------------------------------------------------------------
501  * EXPORTED SRXAFSCB_GetCacheConfig
502  *
503  * Description:
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.
507  *
508  * Arguments:
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.
514  *
515  * Returns:
516  *      0 on success
517  *
518  * Environment:
519  *      Nothing interesting.
520  *
521  * Side Effects:
522  *      As advertised.
523  *------------------------------------------------------------------------*/
524
525 int SRXAFSCB_GetCacheConfig(a_call, callerVersion, serverVersion,
526                             configCount, config)
527 struct rx_call *a_call;
528 afs_uint32 callerVersion;
529 afs_uint32 *serverVersion;
530 afs_uint32 *configCount;
531 cacheConfig *config;
532 {
533     afs_uint32 *t_config;
534     size_t allocsize;
535     extern cm_initparams_v1 cm_initParams;
536
537     /*
538      * Currently only support version 1
539      */
540     allocsize = sizeof(cm_initparams_v1);
541     t_config = (afs_uint32 *)malloc(allocsize);
542
543     afs_MarshallCacheConfig(callerVersion, &cm_initParams, t_config);
544
545     *serverVersion = AFS_CLIENT_RETRIEVAL_FIRST_EDITION;
546     *configCount = allocsize;
547     config->cacheConfig_val = t_config;
548     config->cacheConfig_len = allocsize/sizeof(afs_uint32);
549
550     return 0;
551 }
552
553 /* called by afsd without any locks to initialize this module */
554 void cm_InitCallback(void)
555 {
556         lock_InitializeRWLock(&cm_callbackLock, "cm_callbackLock");
557         cm_activeCallbackGrantingCalls = 0;
558 }
559
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
563  */
564 int cm_HaveCallback(cm_scache_t *scp)
565 {
566         if (scp->cbServerp != NULL)
567                 return 1;
568         else return 0;
569 }
570
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).
575  *
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).
579  *
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.
583  * 
584  * We free all the structures in the queue when the count of the # of outstanding
585  * callback-granting calls drops to zero.
586  *
587  * We call this function with the scp locked, too, but in its current implementation,
588  * this knowledge is not used.
589  */
590 void cm_StartCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp)
591 {
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);
598 }
599
600 /* Called at the end of a callback-granting call, to remove the callback
601  * info from the scache entry, if necessary.
602  *
603  * Called with scp locked, so we can discard the callbacks easily with
604  * this locking hierarchy.
605  */
606 void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
607         AFSCallBack *cbp, long flags)
608 {
609         cm_racingRevokes_t *revp;               /* where we are */
610         cm_racingRevokes_t *nrevp;              /* where we'll be next */
611         int freeFlag;
612
613         lock_ObtainWrite(&cm_callbackLock);
614         if (flags & CM_CALLBACK_MAINTAINCOUNT) {
615                 osi_assert(cm_activeCallbackGrantingCalls > 0);
616         }
617         else {
618                 osi_assert(cm_activeCallbackGrantingCalls-- > 0);
619         }
620         if (cm_activeCallbackGrantingCalls == 0) freeFlag = 1;
621         else freeFlag = 0;
622
623         /* record the callback; we'll clear it below if we really lose it */
624         if (scp) {
625                 scp->cbServerp = cbrp->serverp;
626                 scp->cbExpires = cbrp->startTime + cbp->ExpirationTime;
627         }
628
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.
632          *
633          * May need to go through entire list just to do the freeing.
634          */
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.
640                  */
641                 if (scp && cbrp->callbackCount != cm_callbackCount
642                         && revp->callbackCount > cbrp->callbackCount
643                         && (
644                                 (scp->fid.volume == revp->fid.volume &&
645                                  scp->fid.vnode == revp->fid.vnode &&
646                                  scp->fid.unique == revp->fid.unique)
647                             ||
648                                 ((revp->flags & CM_RACINGFLAG_CANCELVOL) &&
649                                  scp->fid.volume == revp->fid.volume)
650                             ||
651                                 (revp->flags & CM_RACINGFLAG_CANCELALL))) {
652                         /* this one matches */
653                         osi_Log4(afsd_logp,
654                         "Racing revoke scp %x old cbc %d rev cbc %d cur cbc %d",
655                                  scp,
656                                  cbrp->callbackCount, revp->callbackCount,
657                                  cm_callbackCount);
658                         cm_DiscardSCache(scp);
659                         /*
660                          * Since we don't have a callback to preserve, it's
661                          * OK to drop the lock and re-obtain it.
662                          */
663                         lock_ReleaseMutex(&scp->mx);
664                         cm_CallbackNotifyChange(scp);
665                         lock_ObtainMutex(&scp->mx);
666                 }
667                 if (freeFlag) free(revp);
668         }
669
670         /* if we freed the list, zap the pointer to it */
671         if (freeFlag) cm_racingRevokesp = NULL;
672
673         lock_ReleaseWrite(&cm_callbackLock);
674 }
675
676 /* if flags is 1, we want to force the code to make one call, anyway.
677  * called with locked scp; returns with same.
678  */
679 long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
680         struct cm_req *reqp, long flags)
681 {
682         long code;
683         cm_conn_t *connp;
684         AFSFetchStatus afsStatus;
685         AFSVolSync volSync;
686         AFSCallBack callback;
687         AFSFid tfid;
688         cm_callbackRequest_t cbr;
689         int mustCall;
690         long sflags;
691
692         mustCall = (flags & 1);
693         cm_AFSFidFromFid(&tfid, &scp->fid);
694         while (1) {
695                 if (!mustCall && cm_HaveCallback(scp)) return 0;
696
697                 /* turn off mustCall, since it has now forced us past the check above */
698                 mustCall = 0;
699
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);
705                 
706                 /* now make the RPC */
707                 osi_Log1(afsd_logp, "CALL FetchStatus vp %x", (long) scp);
708                 do {
709                         code = cm_Conn(&scp->fid, userp, reqp, &connp);
710                         if (code) continue;
711                 
712                         code = RXAFS_FetchStatus(connp->callp, &tfid,
713                                 &afsStatus, &callback, &volSync);
714
715                 } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync,
716                                     &cbr, code));
717                 code = cm_MapRPCError(code, reqp);
718                 osi_Log0(afsd_logp, "CALL FetchStatus DONE");
719
720                 lock_ObtainMutex(&scp->mx);
721                 cm_SyncOpDone(scp, NULL, sflags);
722                 if (code == 0) {
723                         cm_EndCallbackGrantingCall(scp, &cbr, &callback, 0);
724                         cm_MergeStatus(scp, &afsStatus, &volSync, userp, 0);
725                 }
726                 else
727                         cm_EndCallbackGrantingCall(NULL, NULL, NULL, 0);
728
729                 /* now check to see if we got an error */
730                 if (code) return code;
731         }
732 }
733
734 /* called periodically by cm_daemon to shut down use of expired callbacks */
735 void cm_CheckCBExpiration(void)
736 {
737         int i;
738         cm_scache_t *scp;
739         long now;
740         
741         now = osi_Time();
742         lock_ObtainWrite(&cm_scacheLock);
743         for(i=0; i<cm_hashTableSize; i++) {
744                 for(scp = cm_hashTablep[i]; scp; scp=scp->nextp) {
745                         scp->refCount++;
746                         lock_ReleaseWrite(&cm_scacheLock);
747                         lock_ObtainMutex(&scp->mx);
748                         if (scp->cbServerp && now > scp->cbExpires) {
749                                 cm_DiscardSCache(scp);
750                         }
751                         lock_ReleaseMutex(&scp->mx);
752                         lock_ObtainWrite(&cm_scacheLock);
753                         osi_assert(scp->refCount-- > 0);
754                 }
755         }
756         lock_ReleaseWrite(&cm_scacheLock);
757 }