Windows: out of order locks cm_CheckCBExpiration
[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 <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/afs_args.h>
15 #include <afs/stds.h>
16
17 #include <windows.h>
18 #include <winsock2.h>
19 #include <malloc.h>
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include "afsd.h"
24 #include "smb.h"
25 #include <osi.h>
26 #include <rx_pthread.h>
27
28 #include <WINNT/syscfg.h>
29 #include <WINNT/afsreg.h>
30
31 int
32 SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid);
33
34 /* read/write lock for all global storage in this module */
35 osi_rwlock_t cm_callbackLock;
36
37 afs_int32 cm_OfflineROIsValid = 0;
38
39 afs_int32 cm_giveUpAllCBs = 0;
40
41 afs_int32 cm_shutdown = 0;
42
43 #ifdef AFS_FREELANCE_CLIENT
44 extern osi_mutex_t cm_Freelance_Lock;
45 #endif
46
47 /* count of # of callback breaking messages received by this CM so far.  We use
48  * this count in determining whether there have been any callback breaks that
49  * apply to a call that returned a new callback.  If the counter doesn't
50  * increase during a call, then we know that no callbacks were broken during
51  * that call, and thus that the callback that was just returned is still valid.
52  */
53 long cm_callbackCount;
54
55 /* count of number of RPCs potentially returning a callback executing now.
56  * When this counter hits zero, we can clear out the racing revokes list, since
57  * at that time, we know that none of the just-executed callback revokes will
58  * apply to any future call that returns a callback (since the latter hasn't
59  * even started execution yet).
60  */
61 long cm_activeCallbackGrantingCalls;
62
63 /* list of callbacks that have been broken recently.  If a call returning a
64  * callback is executing and a callback revoke runs immediately after it at the
65  * server, the revoke may end up being processed before the response to the
66  * original callback granting call.  We detect this by keeping a list of
67  * callback revokes that have been received since we *started* the callback
68  * granting call, and discarding any callbacks received for the same file ID,
69  * even if the callback revoke was received before the callback grant.
70  */
71 cm_racingRevokes_t *cm_racingRevokesp;
72
73 /* record a (potentially) racing revoke for this file ID; null means for all
74  * file IDs, and is used by InitCallBackState.
75  *
76  * The cancelFlags describe whether we're just discarding callbacks for the same
77  * file ID, the same volume, or all from the same server.
78  *
79  * Called with no locks held.
80  */
81 void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
82 {
83     cm_racingRevokes_t *rp;
84
85     lock_ObtainWrite(&cm_callbackLock);
86
87     osi_Log3(afsd_logp, "RecordRacingRevoke Volume %d Flags %lX activeCalls %d",
88                 fidp ? fidp->volume : 0, cancelFlags, cm_activeCallbackGrantingCalls);
89
90     if (cm_activeCallbackGrantingCalls > 0) {
91         rp = malloc(sizeof(*rp));
92         memset(rp, 0, sizeof(*rp));
93         osi_QAdd((osi_queue_t **) &cm_racingRevokesp, &rp->q);
94         rp->flags |= (cancelFlags & CM_RACINGFLAG_ALL);
95         if (fidp) rp->fid = *fidp;
96         rp->callbackCount = ++cm_callbackCount;
97     }
98     lock_ReleaseWrite(&cm_callbackLock);
99 }
100
101 /*
102  * When we lose a callback, may have to send change notification replies.
103  * Do not call with a lock on the scp.
104  */
105 void cm_CallbackNotifyChange(cm_scache_t *scp)
106 {
107     DWORD dwDelay = 0;
108     HKEY  hKey;
109     DWORD dummyLen;
110
111     /* why does this have to query the registry each time? */
112         if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
113                       AFSREG_CLT_OPENAFS_SUBKEY,
114                       0,
115                       KEY_READ|KEY_QUERY_VALUE,
116                       &hKey) == ERROR_SUCCESS) {
117
118         dummyLen = sizeof(DWORD);
119         RegQueryValueEx(hKey, "CallBack Notify Change Delay", NULL, NULL,
120                         (BYTE *) &dwDelay, &dummyLen);
121         RegCloseKey(hKey);
122     }
123
124     if (dwDelay > 5000)    /* do not allow a delay of more then 5 seconds */
125         dwDelay = 5000;   
126
127     osi_Log3(afsd_logp, "CallbackNotifyChange FileType %d Flags %lX Delay %dms",
128               scp->fileType, scp->flags, dwDelay);
129
130     if (dwDelay)
131         Sleep(dwDelay);
132
133     /* for directories, this sends a change notification on the dir itself */
134     if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
135         if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
136             smb_NotifyChange(0,
137                              FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
138                              scp, NULL, NULL, TRUE);
139     } else {
140         /* and for files, this sends a change notification on the file's parent dir */
141         cm_fid_t tfid;
142         cm_scache_t *dscp;
143
144         cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
145         dscp = cm_FindSCache(&tfid);
146         if ( dscp &&
147              dscp->flags & CM_SCACHEFLAG_ANYWATCH )
148             smb_NotifyChange( 0,
149                               FILE_NOTIFY_GENERIC_FILE_FILTER,
150                               dscp, NULL, NULL, TRUE);
151         if (dscp) 
152             cm_ReleaseSCache(dscp);
153     }
154 }
155
156 /* called with no locks held for every file ID that is revoked directly by
157  * a callback revoke call.  Does not have to handle volume callback breaks,
158  * since those have already been split out.
159  *
160  * The callp parameter is currently unused.
161  */
162 void cm_RevokeCallback(struct rx_call *callp, cm_cell_t * cellp, AFSFid *fidp)
163 {
164     cm_fid_t tfid;
165     cm_scache_t *scp;
166     long hash;
167         
168     tfid.cell = cellp ? cellp->cellID : 0;
169     tfid.volume = fidp->Volume;
170     tfid.vnode = fidp->Vnode;
171     tfid.unique = fidp->Unique;
172     hash = CM_SCACHE_HASH(&tfid);
173
174     osi_Log3(afsd_logp, "RevokeCallback vol %u vn %u uniq %u",
175              fidp->Volume, fidp->Vnode, fidp->Unique);
176         
177     /* do this first, so that if we're executing a callback granting call
178      * at this moment, we kill it before it can be merged in.  Otherwise,
179      * it could complete while we're doing the scan below, and get missed
180      * by both the scan and by this code.
181      */
182     cm_RecordRacingRevoke(&tfid, 0);
183
184     lock_ObtainWrite(&cm_scacheLock);
185     /* do all in the hash bucket, since we don't know how many we'll find with
186      * varying cells.
187      */
188     for (scp = cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
189         if (scp->fid.volume == tfid.volume &&
190              scp->fid.vnode == tfid.vnode &&
191              scp->fid.unique == tfid.unique &&
192              (cellp == NULL || scp->fid.cell == cellp->cellID) &&
193              cm_HaveCallback(scp))
194         {
195             cm_HoldSCacheNoLock(scp);
196             lock_ReleaseWrite(&cm_scacheLock);
197             osi_Log4(afsd_logp, "RevokeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u", 
198                      scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
199
200             lock_ObtainWrite(&scp->rw);
201             cm_DiscardSCache(scp);
202             lock_ReleaseWrite(&scp->rw);
203
204             cm_CallbackNotifyChange(scp);
205             
206             lock_ObtainWrite(&cm_scacheLock);
207             cm_ReleaseSCacheNoLock(scp);
208         }
209     }
210     lock_ReleaseWrite(&cm_scacheLock);
211
212     osi_Log3(afsd_logp, "RevokeCallback Complete vol %u vn %u uniq %u",
213              fidp->Volume, fidp->Vnode, fidp->Unique);
214 }
215
216 static __inline void
217 cm_callbackDiscardROVolumeByFID(cm_fid_t *fidp)
218 {
219     cm_volume_t *volp = cm_GetVolumeByFID(fidp);
220     if (volp) {
221         cm_PutVolume(volp);
222         if (volp->cbExpiresRO) {
223             volp->cbExpiresRO = 0;
224             if (volp->cbServerpRO) {
225                 cm_PutServer(volp->cbServerpRO);
226                 volp->cbServerpRO = NULL;
227             }
228             volp->creationDateRO = 0;
229         }
230     }
231 }
232
233 /* called to revoke a volume callback, which is typically issued when a volume
234  * is moved from one server to another.
235  *
236  * Called with no locks held.
237  */
238 void cm_RevokeVolumeCallback(struct rx_call *callp, cm_cell_t *cellp, AFSFid *fidp)
239 {
240     unsigned long hash;
241     cm_scache_t *scp;
242     cm_fid_t tfid;
243
244     osi_Log1(afsd_logp, "RevokeVolumeCallback vol %d", fidp->Volume);
245
246     /* do this first, so that if we're executing a callback granting call
247      * at this moment, we kill it before it can be merged in.  Otherwise,
248      * it could complete while we're doing the scan below, and get missed
249      * by both the scan and by this code.
250      */
251     tfid.cell = cellp ? cellp->cellID : 0;
252     tfid.volume = fidp->Volume;
253     tfid.vnode = tfid.unique = 0;
254
255     cm_RecordRacingRevoke(&tfid, CM_RACINGFLAG_CANCELVOL);
256
257     lock_ObtainWrite(&cm_scacheLock);
258     for (hash = 0; hash < cm_data.scacheHashTableSize; hash++) {
259         for(scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
260             if (scp->fid.volume == fidp->Volume &&
261                 (cellp == NULL || scp->fid.cell == cellp->cellID) &&
262                  scp->cbExpires > 0 &&
263                  scp->cbServerp != NULL) {
264                 cm_HoldSCacheNoLock(scp);
265                 lock_ReleaseWrite(&cm_scacheLock);
266
267                 lock_ObtainWrite(&scp->rw);
268                 osi_Log4(afsd_logp, "RevokeVolumeCallback Discarding SCache scp 0x%p vol %u vn %u uniq %u", 
269                           scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
270                 cm_DiscardSCache(scp);
271                 lock_ReleaseWrite(&scp->rw);
272
273                 cm_CallbackNotifyChange(scp);
274                 lock_ObtainWrite(&cm_scacheLock);
275                 cm_ReleaseSCacheNoLock(scp);
276                 if (scp->flags & CM_SCACHEFLAG_PURERO)
277                     cm_callbackDiscardROVolumeByFID(&scp->fid);
278             }
279         }       /* search one hash bucket */
280     }   /* search all hash buckets */
281
282     lock_ReleaseWrite(&cm_scacheLock);
283
284     osi_Log1(afsd_logp, "RevokeVolumeCallback Complete vol %d", fidp->Volume);
285 }
286
287 /*
288  * afs_data_pointer_to_int32() - returns least significant afs_int32 of the
289  * given data pointer, without triggering "cast truncates pointer"
290  * warnings.  We use this where we explicitly don't care whether a
291  * pointer is truncated -- it loses information where a pointer is
292  * larger than an afs_int32.
293  */
294
295 static afs_int32
296 afs_data_pointer_to_int32(const void *p)
297 {
298     union {
299         afs_int32 i32[sizeof(void *) / sizeof(afs_int32)];
300         const void *p;
301     } ip;
302
303     int i32_sub;                /* subscript of least significant afs_int32 in ip.i32[] */
304
305     /* set i32_sub */
306
307     {
308         /* used to determine the byte order of the system */
309
310         union {
311             char c[sizeof(int) / sizeof(char)];
312             int i;
313         } ci;
314
315         ci.i = 1;
316         if (ci.c[0] == 1) {
317             /* little-endian system */
318             i32_sub = 0;
319         } else {
320             /* big-endian system */
321             i32_sub = (sizeof ip.i32 / sizeof ip.i32[0]) - 1;
322         }
323     }
324
325     ip.p = p;
326     return ip.i32[i32_sub];
327 }
328 /*------------------------------------------------------------------------
329  * EXPORTED SRXAFSCB_CallBack
330  *
331  * Description:
332  *      Routine called by the server-side callback RPC interface to
333  *      implement passing in callback information.
334  *      table.
335  *
336  * Arguments:
337  *      rx_call    : Ptr to Rx call on which this request came in.
338  *      fidsArrayp : Ptr to array of fids involved.
339  *      cbsArrayp  : Ptr to matching callback info for the fids.
340  *
341  * Returns:
342  *      0 (always).
343  *
344  * Environment:
345  *      Nothing interesting.
346  *
347  * Side Effects:
348  *      As advertised.
349  *------------------------------------------------------------------------*/
350 /* handle incoming RPC callback breaking message.
351  * Called with no locks held.
352  */
353 int
354 SRXAFSCB_CallBack(struct rx_call *callp, AFSCBFids *fidsArrayp, AFSCBs *cbsArrayp)
355 {
356     int i;
357     AFSFid *tfidp;
358     struct rx_connection *connp;
359     struct rx_peer *peerp;
360     unsigned long host = 0;
361     unsigned short port = 0;
362     cm_server_t *tsp = NULL;
363     cm_cell_t* cellp = NULL;
364
365     if (cm_shutdown)
366         return 1;
367
368     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
369         host = rx_HostOf(peerp);
370         port = rx_PortOf(peerp);
371
372         tsp = cm_FindServerByIP(host, port, CM_SERVER_FILE);
373         if (tsp) {
374             cellp = tsp->cellp;
375             cm_PutServer(tsp);
376         }
377
378         if (!cellp)
379             osi_Log2(afsd_logp, "SRXAFSCB_CallBack from host 0x%x port %d",
380                      ntohl(host),
381                      ntohs(port));
382         else 
383             osi_Log3(afsd_logp, "SRXAFSCB_CallBack from host 0x%x port %d for cell %s",
384                      ntohl(host),
385                      ntohs(port),
386                      cellp->name /* does not need to be saved, doesn't change */);
387     } else {
388         osi_Log0(afsd_logp, "SRXAFSCB_CallBack from unknown host");
389     }
390
391
392     for (i=0; i < (long) fidsArrayp->AFSCBFids_len; i++) {
393         tfidp = &fidsArrayp->AFSCBFids_val[i];
394                 
395         if (tfidp->Volume == 0)
396             continue;   /* means don't do anything */
397         else if (tfidp->Vnode == 0)
398             cm_RevokeVolumeCallback(callp, cellp, tfidp);
399         else
400             cm_RevokeCallback(callp, cellp, tfidp);
401     }
402     return 0;
403 }
404
405 /*------------------------------------------------------------------------
406  * EXPORTED SRXAFSCB_InitCallBackState
407  *
408  * Description:
409  *      Routine called by the server-side callback RPC interface to
410  *      implement clearing all callbacks from this host.
411  *
412  * Arguments:
413  *      rx_call : Ptr to Rx call on which this request came in.
414  *
415  * Returns:
416  *      0 (always).
417  *
418  * Environment:
419  *      Nothing interesting.
420  *
421  * Side Effects:
422  *      As advertised.
423  *------------------------------------------------------------------------*/
424 /* called with no locks by RPC system when a server indicates that it has never
425  * heard from us, or for other reasons has had to discard callbacks from us
426  * without telling us, e.g. a network partition.
427  */
428 int
429 SRXAFSCB_InitCallBackState(struct rx_call *callp)
430 {
431     if (cm_shutdown)
432         return 1;
433
434     osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState ->");
435
436     return SRXAFSCB_InitCallBackState3(callp, NULL);
437 }
438
439 /*------------------------------------------------------------------------
440  * EXPORTED SRXAFSCB_Probe
441  *
442  * Description:
443  *      Routine called by the server-side callback RPC interface to
444  *      implement ``probing'' the Cache Manager, just making sure it's
445  *      still there.
446  *
447  * Arguments:
448  *      rx_call : Ptr to Rx call on which this request came in.
449  *
450  * Returns:
451  *      0 (always).
452  *
453  * Environment:
454  *      Nothing interesting.
455  *
456  * Side Effects:
457  *      As advertised.
458  *------------------------------------------------------------------------*/
459 int
460 SRXAFSCB_Probe(struct rx_call *callp)
461 {
462     struct rx_connection *connp;
463     struct rx_peer *peerp;
464     unsigned long host = 0;
465     unsigned short port = 0;
466
467     if (cm_shutdown)
468         return 1;
469
470     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
471         host = rx_HostOf(peerp);
472         port = rx_PortOf(peerp);
473     }
474
475     osi_Log2(afsd_logp, "SRXAFSCB_Probe from host 0x%x port %d",
476               ntohl(host),
477               ntohs(port));
478
479     return 0;
480 }
481
482 /*------------------------------------------------------------------------
483  * EXPORTED SRXAFSCB_GetLock
484  *
485  * Description:
486  *      Routine called by the server-side callback RPC interface to
487  *      implement pulling out the contents of a lock in the lock
488  *      table.
489  *
490  * Arguments:
491  *      a_call   : Ptr to Rx call on which this request came in.
492  *      a_index  : Index of desired lock.
493  *      a_result : Ptr to a buffer for the given lock.
494  *
495  * Returns:
496  *      0 if everything went fine,
497  *      1 if we were given a bad index.
498  *
499  * Environment:
500  *      Nothing interesting.
501  *
502  * Side Effects:
503  *      As advertised.
504  *------------------------------------------------------------------------*/
505 /* debug interface */
506
507 extern osi_rwlock_t cm_aclLock;
508 extern osi_rwlock_t buf_globalLock;
509 extern osi_rwlock_t cm_cellLock;
510 extern osi_rwlock_t cm_connLock;
511 extern osi_rwlock_t cm_daemonLock;
512 extern osi_rwlock_t cm_dnlcLock;
513 extern osi_rwlock_t cm_scacheLock;
514 extern osi_rwlock_t cm_serverLock;
515 extern osi_rwlock_t cm_syscfgLock;
516 extern osi_rwlock_t cm_userLock;
517 extern osi_rwlock_t cm_utilsLock;
518 extern osi_rwlock_t cm_volumeLock;
519 extern osi_rwlock_t smb_globalLock;
520 extern osi_rwlock_t smb_rctLock;
521
522 extern osi_mutex_t cm_Freelance_Lock;
523 extern osi_mutex_t cm_Afsdsbmt_Lock;
524 extern osi_mutex_t tokenEventLock;
525 extern osi_mutex_t  smb_ListenerLock;
526 extern osi_mutex_t smb_RawBufLock;
527 extern osi_mutex_t smb_Dir_Watch_Lock;
528
529 #define LOCKTYPE_RW     1
530 #define LOCKTYPE_MUTEX  2
531 static struct _ltable {
532     char *name;
533     char *addr;
534     int  type;
535 } ltable[] = {
536     {"cm_scacheLock",    (char*)&cm_scacheLock,         LOCKTYPE_RW},
537     {"buf_globalLock",   (char*)&buf_globalLock,        LOCKTYPE_RW},
538     {"cm_serverLock",    (char*)&cm_serverLock,         LOCKTYPE_RW},
539     {"cm_callbackLock",  (char*)&cm_callbackLock,       LOCKTYPE_RW},
540     {"cm_syscfgLock",    (char*)&cm_syscfgLock,         LOCKTYPE_RW},
541     {"cm_aclLock",       (char*)&cm_aclLock,            LOCKTYPE_RW},
542     {"cm_cellLock",      (char*)&cm_cellLock,           LOCKTYPE_RW},
543     {"cm_connLock",      (char*)&cm_connLock,           LOCKTYPE_RW},
544     {"cm_userLock",      (char*)&cm_userLock,           LOCKTYPE_RW},
545     {"cm_volumeLock",    (char*)&cm_volumeLock,         LOCKTYPE_RW},
546     {"cm_daemonLock",    (char*)&cm_daemonLock,         LOCKTYPE_RW},
547     {"cm_dnlcLock",      (char*)&cm_dnlcLock,           LOCKTYPE_RW},
548     {"cm_utilsLock",     (char*)&cm_utilsLock,          LOCKTYPE_RW},
549     {"smb_globalLock",   (char*)&smb_globalLock,        LOCKTYPE_RW},
550     {"smb_rctLock",      (char*)&smb_rctLock,           LOCKTYPE_RW},
551     {"cm_Freelance_Lock",(char*)&cm_Freelance_Lock,     LOCKTYPE_MUTEX},
552     {"cm_Afsdsbmt_Lock", (char*)&cm_Afsdsbmt_Lock,      LOCKTYPE_MUTEX},
553     {"tokenEventLock",   (char*)&tokenEventLock,        LOCKTYPE_MUTEX},
554     {"smb_ListenerLock", (char*)&smb_ListenerLock,      LOCKTYPE_MUTEX},
555     {"smb_RawBufLock",   (char*)&smb_RawBufLock,        LOCKTYPE_MUTEX},
556     {"smb_Dir_Watch_Lock",(char*)&smb_Dir_Watch_Lock,   LOCKTYPE_MUTEX}
557 };
558
559 int
560 SRXAFSCB_GetLock(struct rx_call *callp, long index, AFSDBLock *lockp)
561 {
562     struct _ltable *tl;          /*Ptr to lock table entry */
563     osi_rwlock_t  *rwp;
564     osi_mutex_t   *mtxp;
565     int nentries;               /*Num entries in table */
566     int code;                   /*Return code */
567     struct rx_connection *connp;
568     struct rx_peer *peerp;
569     unsigned long host = 0;
570     unsigned short port = 0;
571
572     if (cm_shutdown)
573         return 1;
574
575     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
576         host = rx_HostOf(peerp);
577         port = rx_PortOf(peerp);
578     }
579
580     osi_Log3(afsd_logp, "SRXAFSCB_GetLock(%d) from host 0x%x port %d", 
581              index, ntohl(host), ntohs(port));
582
583     nentries = sizeof(ltable) / sizeof(struct _ltable);
584     if (index < 0 || index >= nentries) {
585         /*
586          * Past EOF
587          */
588         code = 1;
589     } else {
590         /*
591          * Found it - copy out its contents.
592          */
593         tl = &ltable[index];
594         strncpy(lockp->name, tl->name, sizeof(lockp->name));
595         lockp->name[sizeof(lockp->name)-1] = '\0';
596         lockp->lock.waitStates = 0;
597         switch ( tl->type ) {
598         case LOCKTYPE_RW:
599             rwp = (osi_rwlock_t *)tl->addr;
600             lockp->lock.exclLocked = rwp->flags;
601             lockp->lock.readersReading = rwp->readers;
602             lockp->lock.numWaiting = rwp->waiters;
603             break;
604         case LOCKTYPE_MUTEX:
605             mtxp = (osi_mutex_t *)tl->addr;
606             lockp->lock.exclLocked = mtxp->flags;
607             lockp->lock.readersReading = 0;
608             lockp->lock.numWaiting = mtxp->waiters;
609             break;
610         }
611         lockp->lock.pid_last_reader = 0;
612         lockp->lock.pid_writer = 0;
613         lockp->lock.src_indicator = 0;
614         code = 0;
615     }
616
617     return code;
618 }
619
620 /* debug interface */
621 int
622 SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
623 {
624     afs_uint32 i;
625     cm_scache_t * scp;
626     int code;
627     struct rx_connection *connp;
628     struct rx_peer *peerp;
629     unsigned long host = 0;
630     unsigned short port = 0;
631
632     if (cm_shutdown)
633         return 1;
634
635     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
636         host = rx_HostOf(peerp);
637         port = rx_PortOf(peerp);
638     }
639
640     osi_Log2(afsd_logp, "SRXAFSCB_GetCE from host 0x%x port %d",
641              ntohl(host), ntohs(port));
642
643     lock_ObtainRead(&cm_scacheLock);
644     for (i = 0; i < cm_data.scacheHashTableSize; i++) {
645         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
646             if (index == 0)
647                 goto searchDone;
648             index--;
649         }                       /*Zip through current hash chain */
650     }                           /*Zip through hash chains */
651
652   searchDone:
653     if (scp == NULL) {
654         /*Past EOF */
655         code = 1;
656         goto fcnDone;
657     }
658
659     /*
660      * Copy out the located entry.
661      */
662     memset(cep, 0, sizeof(AFSDBCacheEntry));
663     cep->addr = afs_data_pointer_to_int32(scp);
664     cep->cell = scp->fid.cell;
665     cep->netFid.Volume = scp->fid.volume;
666     cep->netFid.Vnode = scp->fid.vnode;
667     cep->netFid.Unique = scp->fid.unique;
668     cep->lock.waitStates = 0;
669     cep->lock.exclLocked = scp->rw.flags;
670     cep->lock.readersReading = 0;
671     cep->lock.numWaiting = scp->rw.waiters;
672     cep->lock.pid_last_reader = 0;
673     cep->lock.pid_writer = 0;
674     cep->lock.src_indicator = 0;
675     cep->Length = scp->length.LowPart;
676     cep->DataVersion = (afs_uint32)(scp->dataVersion & 0xFFFFFFFF);
677     cep->callback = afs_data_pointer_to_int32(scp->cbServerp);
678     if (scp->flags & CM_SCACHEFLAG_PURERO) {
679         cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
680         if (volp) {
681             cep->cbExpires = volp->cbExpiresRO;
682             cm_PutVolume(volp);
683         }
684     } else {
685         /* TODO: deal with time_t below */
686         cep->cbExpires = (afs_int32) scp->cbExpires;
687     }
688     cep->refCount = scp->refCount;
689     cep->opens = scp->openReads;
690     cep->writers = scp->openWrites;
691     switch (scp->fileType) {
692     case CM_SCACHETYPE_FILE:
693         cep->mvstat = 0;
694         break;
695     case CM_SCACHETYPE_MOUNTPOINT:
696         cep->mvstat = 1;
697         break;
698     case CM_SCACHETYPE_DIRECTORY:
699         if (scp->fid.vnode == 1 && scp->fid.unique == 1)
700             cep->mvstat = 2;
701         else
702             cep->mvstat = 3;
703         break;
704     case CM_SCACHETYPE_SYMLINK:
705         cep->mvstat = 4;
706         break;
707     case CM_SCACHETYPE_DFSLINK:
708         cep->mvstat = 5;
709         break;
710     case CM_SCACHETYPE_INVALID:
711         cep->mvstat = 6;
712         break;
713     }
714     cep->states = 0;
715     if (scp->flags & CM_SCACHEFLAG_STATD)
716         cep->states |= 1;
717     if (scp->flags & CM_SCACHEFLAG_RO || scp->flags & CM_SCACHEFLAG_PURERO)
718         cep->states |= 4;
719     if (scp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
720         scp->mountPointStringp[0])
721         cep->states |= 8;
722     if (scp->flags & CM_SCACHEFLAG_WAITING)
723         cep->states |= 0x40;
724     code = 0;
725
726     /*
727      * Return our results.
728      */
729   fcnDone:
730     lock_ReleaseRead(&cm_scacheLock);
731
732     return (code);
733 }
734
735 /* debug interface */
736 int
737 SRXAFSCB_GetCE64(struct rx_call *callp, long index, AFSDBCacheEntry64 *cep)
738 {
739     afs_uint32 i;
740     cm_scache_t * scp;
741     int code;
742     struct rx_connection *connp;
743     struct rx_peer *peerp;
744     unsigned long host = 0;
745     unsigned short port = 0;
746
747     if (cm_shutdown)
748         return 1;
749
750     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
751         host = rx_HostOf(peerp);
752         port = rx_PortOf(peerp);
753     }
754
755     osi_Log2(afsd_logp, "SRXAFSCB_GetCE64 from host 0x%x port %d",
756              ntohl(host), ntohs(port));
757
758     lock_ObtainRead(&cm_scacheLock);
759     for (i = 0; i < cm_data.scacheHashTableSize; i++) {
760         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
761             if (index == 0)
762                 goto searchDone;
763             index--;
764         }                       /*Zip through current hash chain */
765     }                           /*Zip through hash chains */
766
767   searchDone:
768     if (scp == NULL) {
769         /*Past EOF */
770         code = 1;
771         goto fcnDone;
772     }
773
774     /*
775      * Copy out the located entry.
776      */
777     memset(cep, 0, sizeof(AFSDBCacheEntry64));
778     cep->addr = afs_data_pointer_to_int32(scp);
779     cep->cell = scp->fid.cell;
780     cep->netFid.Volume = scp->fid.volume;
781     cep->netFid.Vnode = scp->fid.vnode;
782     cep->netFid.Unique = scp->fid.unique;
783     cep->lock.waitStates = 0;
784     cep->lock.exclLocked = scp->rw.flags;
785     cep->lock.readersReading = 0;
786     cep->lock.numWaiting = scp->rw.waiters;
787     cep->lock.pid_last_reader = 0;
788     cep->lock.pid_writer = 0;
789     cep->lock.src_indicator = 0;
790     cep->Length = (afs_int64) scp->length.QuadPart;
791     cep->DataVersion = (afs_uint32)(scp->dataVersion & 0xFFFFFFFF);
792     cep->callback = afs_data_pointer_to_int32(scp->cbServerp);
793     if (scp->flags & CM_SCACHEFLAG_PURERO) {
794         cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
795         if (volp) {
796             cep->cbExpires = volp->cbExpiresRO;
797             cm_PutVolume(volp);
798         }
799     } else {
800         /* TODO: handle time_t */
801         cep->cbExpires = (afs_int32) scp->cbExpires;
802     }
803     cep->refCount = scp->refCount;
804     cep->opens = scp->openReads;
805     cep->writers = scp->openWrites;
806     switch (scp->fileType) {
807     case CM_SCACHETYPE_FILE:
808         cep->mvstat = 0;
809         break;
810     case CM_SCACHETYPE_MOUNTPOINT:
811         cep->mvstat = 1;
812         break;
813     case CM_SCACHETYPE_DIRECTORY:
814         if (scp->fid.vnode == 1 && scp->fid.unique == 1)
815             cep->mvstat = 2;
816         else
817             cep->mvstat = 3;
818         break;
819     case CM_SCACHETYPE_SYMLINK:
820         cep->mvstat = 4;
821         break;
822     case CM_SCACHETYPE_DFSLINK:
823         cep->mvstat = 5;
824         break;
825     case CM_SCACHETYPE_INVALID:
826         cep->mvstat = 6;
827         break;
828     }
829     cep->states = 0;
830     if (scp->flags & CM_SCACHEFLAG_STATD)
831         cep->states |= 1;
832     if (scp->flags & CM_SCACHEFLAG_RO || scp->flags & CM_SCACHEFLAG_PURERO)
833         cep->states |= 4;
834     if (scp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
835         scp->mountPointStringp[0])
836         cep->states |= 8;
837     if (scp->flags & CM_SCACHEFLAG_WAITING)
838         cep->states |= 0x40;
839     code = 0;
840
841     /*
842      * Return our results.
843      */
844   fcnDone:
845     lock_ReleaseRead(&cm_scacheLock);
846
847     return (code);
848 }
849
850 /* debug interface: not implemented */
851 int
852 SRXAFSCB_XStatsVersion(struct rx_call *callp, long *vp)
853 {
854     struct rx_connection *connp;
855     struct rx_peer *peerp;
856     unsigned long host = 0;
857     unsigned short port = 0;
858
859     if (cm_shutdown)
860         return 1;
861
862     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
863         host = rx_HostOf(peerp);
864         port = rx_PortOf(peerp);
865     }
866
867     osi_Log2(afsd_logp, "SRXAFSCB_XStatsVersion from host 0x%x port %d - not implemented",
868              ntohl(host), ntohs(port));
869     *vp = -1;
870
871     return RXGEN_OPCODE;
872 }
873
874 /* debug interface: not implemented */
875 int
876 SRXAFSCB_GetXStats(struct rx_call *callp, long cvn, long coln, long *srvp, long *timep,
877                    AFSCB_CollData *datap)
878 {
879     struct rx_connection *connp;
880     struct rx_peer *peerp;
881     unsigned long host = 0;
882     unsigned short port = 0;
883
884     if (cm_shutdown)
885         return 1;
886
887     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
888         host = rx_HostOf(peerp);
889         port = rx_PortOf(peerp);
890     }
891
892     osi_Log2(afsd_logp, "SRXAFSCB_GetXStats from host 0x%x port %d - not implemented",
893              ntohl(host), ntohs(port));
894
895     return RXGEN_OPCODE;
896 }
897
898 int
899 SRXAFSCB_InitCallBackState2(struct rx_call *callp, struct interfaceAddr* addr)
900 {
901     if (cm_shutdown)
902         return 1;
903
904     osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState2 ->");
905
906     return SRXAFSCB_InitCallBackState3(callp, NULL);
907 }
908
909 /* debug interface */
910 int
911 SRXAFSCB_WhoAreYou(struct rx_call *callp, struct interfaceAddr* addr)
912 {
913     int i;
914     long code;
915     struct rx_connection *connp;
916     struct rx_peer *peerp;
917     unsigned long host = 0;
918     unsigned short port = 0;
919
920     if (cm_shutdown)
921         return 1;
922
923     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
924         host = rx_HostOf(peerp);
925         port = rx_PortOf(peerp);
926     }
927
928     osi_Log2(afsd_logp, "SRXAFSCB_WhoAreYou from host 0x%x port %d",
929               ntohl(host),
930               ntohs(port));
931
932     lock_ObtainRead(&cm_syscfgLock);
933     if (cm_LanAdapterChangeDetected) {
934         lock_ConvertRToW(&cm_syscfgLock);
935         if (cm_LanAdapterChangeDetected) {
936             /* get network related info */
937             cm_noIPAddr = CM_MAXINTERFACE_ADDR;
938             code = syscfg_GetIFInfo(&cm_noIPAddr,
939                                      cm_IPAddr, cm_SubnetMask,
940                                      cm_NetMtu, cm_NetFlags);
941             cm_LanAdapterChangeDetected = 0;
942         }
943         lock_ConvertWToR(&cm_syscfgLock);
944     }
945
946     /* return all network interface addresses */
947     addr->numberOfInterfaces = cm_noIPAddr;
948     addr->uuid = cm_data.Uuid;
949     for ( i=0; i < cm_noIPAddr; i++ ) {
950         addr->addr_in[i] = cm_IPAddr[i];
951         addr->subnetmask[i] = cm_SubnetMask[i];
952         addr->mtu[i] = (rx_mtu == -1 || (rx_mtu != -1 && cm_NetMtu[i] < rx_mtu)) ? 
953             cm_NetMtu[i] : rx_mtu;
954     }
955
956     lock_ReleaseRead(&cm_syscfgLock);
957
958     return 0;
959 }
960
961 int
962 SRXAFSCB_InitCallBackState3(struct rx_call *callp, afsUUID* serverUuid)
963 {
964     char *p = NULL;
965
966     struct sockaddr_in taddr;
967     cm_server_t *tsp = NULL;
968     cm_scache_t *scp = NULL;
969     cm_cell_t* cellp = NULL;
970     afs_uint32 hash;
971     int discarded;
972     struct rx_connection *connp;
973     struct rx_peer *peerp;
974     unsigned long host = 0;
975     unsigned short port = 0;
976
977     if (cm_shutdown)
978         return 1;
979
980     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
981         host = rx_HostOf(peerp);
982         port = rx_PortOf(peerp);
983
984         if (serverUuid) {
985             if (UuidToString((UUID *)serverUuid, &p) == RPC_S_OK) {
986                 osi_Log1(afsd_logp, "SRXAFSCB_InitCallBackState3 Uuid%s ->",osi_LogSaveString(afsd_logp,p));
987                 RpcStringFree(&p);
988             } 
989
990             tsp = cm_FindServerByUuid(serverUuid, CM_SERVER_FILE);
991         }
992         if (!tsp)
993             tsp = cm_FindServerByIP(host, port, CM_SERVER_FILE);
994         if (tsp) {
995             cellp = tsp->cellp;
996             cm_PutServer(tsp);
997         }
998
999         if (!cellp)
1000             osi_Log2(afsd_logp, "SRXAFSCB_InitCallBackState3 from host 0x%x port %d",
1001                      ntohl(host),
1002                      ntohs(port));
1003         else 
1004             osi_Log3(afsd_logp, "SRXAFSCB_InitCallBackState3 from host 0x%x port %d for cell %s",
1005                      ntohl(host),
1006                      ntohs(port),
1007                      cellp->name /* does not need to be saved, doesn't change */);
1008     } else {
1009         osi_Log0(afsd_logp, "SRXAFSCB_InitCallBackState3 from unknown host");
1010     }
1011
1012     if (connp && peerp) {
1013         taddr.sin_family = AF_INET;
1014         taddr.sin_addr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(callp)));
1015         taddr.sin_port = rx_PortOf(rx_PeerOf(rx_ConnectionOf(callp)));
1016
1017         tsp = cm_FindServer(&taddr, CM_SERVER_FILE);
1018
1019         osi_Log1(afsd_logp, "InitCallbackState3 server %x", tsp);
1020         
1021         /* record the callback in the racing revokes structure.  This
1022          * shouldn't be necessary, since we shouldn't be making callback
1023          * granting calls while we're going to get an initstate call,
1024          * but there probably are some obscure races, so better safe
1025          * than sorry.
1026          *
1027          * We do this first since we don't hold the cm_scacheLock and vnode
1028          * locks over the entire callback scan operation below.  The
1029          * big loop below is guaranteed to hit any callback already
1030          * processed.  The call to RecordRacingRevoke is guaranteed
1031          * to kill any callback that is currently being returned.
1032          * Anything that sneaks past both must start
1033          * after the call to RecordRacingRevoke.
1034          */
1035         if (cellp) {
1036             cm_fid_t fid;
1037
1038             fid.cell = cellp->cellID;
1039             fid.volume = fid.vnode = fid.unique = 0;
1040
1041             cm_RecordRacingRevoke(&fid, CM_RACINGFLAG_CANCELALL);
1042         } else {
1043             cm_RecordRacingRevoke(NULL, CM_RACINGFLAG_CANCELALL);
1044         }
1045
1046         /* now search all vnodes looking for guys with this callback, if we
1047          * found it, or guys with any callbacks, if we didn't find the server
1048          * (that's how multihomed machines will appear and how we'll handle
1049          * them, albeit a little inefficiently).  That is, we're discarding all
1050          * callbacks from all hosts if we get an initstate call from an unknown
1051          * host.  Since these calls are rare, and multihomed servers
1052          * are "rare," hopefully this won't be a problem.
1053          */
1054         lock_ObtainWrite(&cm_scacheLock);
1055         for (hash = 0; hash < cm_data.scacheHashTableSize; hash++) {
1056             for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
1057                 cm_HoldSCacheNoLock(scp);
1058                 lock_ReleaseWrite(&cm_scacheLock);
1059                 lock_ObtainWrite(&scp->rw);
1060                 discarded = 0;
1061                 if (scp->cbExpires > 0 && scp->cbServerp != NULL) {
1062                     /* we have a callback, now decide if we should clear it */
1063                     if (cm_ServerEqual(scp->cbServerp, tsp)) {
1064                         osi_Log4(afsd_logp, "InitCallbackState3 Discarding SCache scp 0x%p vol %u vn %u uniq %u", 
1065                                   scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
1066                         cm_DiscardSCache(scp);
1067                         discarded = 1;
1068                     }
1069                 }
1070                 lock_ReleaseWrite(&scp->rw);
1071                 if (discarded)
1072                     cm_CallbackNotifyChange(scp);
1073                 lock_ObtainWrite(&cm_scacheLock);
1074                 cm_ReleaseSCacheNoLock(scp);
1075
1076                 if (discarded && (scp->flags & CM_SCACHEFLAG_PURERO))
1077                     cm_callbackDiscardROVolumeByFID(&scp->fid);
1078
1079             }   /* search one hash bucket */
1080         }       /* search all hash buckets */
1081         
1082         lock_ReleaseWrite(&cm_scacheLock);
1083         
1084         if (tsp) {
1085             /* reset the No flags on the server */
1086             cm_SetServerNo64Bit(tsp, 0);
1087             cm_SetServerNoInlineBulk(tsp, 0);
1088
1089             /* we're done with the server structure */
1090             cm_PutServer(tsp);
1091         } 
1092     }
1093     return 0;
1094 }
1095
1096 /* debug interface */
1097 int
1098 SRXAFSCB_ProbeUuid(struct rx_call *callp, afsUUID* clientUuid)
1099 {
1100     struct rx_connection *connp;
1101     struct rx_peer *peerp;
1102     unsigned long host = 0;
1103     unsigned short port = 0;
1104     char *p,*q;
1105     int code = 0;
1106
1107     if (cm_shutdown)
1108         return 1;
1109
1110     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1111         host = rx_HostOf(peerp);
1112         port = rx_PortOf(peerp);
1113     }
1114
1115     if ( !afs_uuid_equal(&cm_data.Uuid, clientUuid) ) {
1116         UuidToString((UUID *)&cm_data.Uuid, &p);
1117         UuidToString((UUID *)clientUuid, &q);
1118         osi_Log4(afsd_logp, "SRXAFSCB_ProbeUuid %s != %s from host 0x%x port %d", 
1119                   osi_LogSaveString(afsd_logp,p), 
1120                   osi_LogSaveString(afsd_logp,q),
1121                   ntohl(host),
1122                   ntohs(port));
1123         RpcStringFree(&p);
1124         RpcStringFree(&q);
1125
1126         code = 1;       /* failure */
1127     } else
1128         osi_Log2(afsd_logp, "SRXAFSCB_ProbeUuid (success) from host 0x%x port %d",
1129                   ntohl(host),
1130                   ntohs(port));
1131
1132     return code;
1133 }
1134
1135 /* debug interface */
1136 static int 
1137 GetCellCommon(afs_int32 a_cellnum, char **a_name, serverList *a_hosts)
1138 {
1139     afs_int32 sn;
1140     cm_cell_t * cellp;
1141     cm_serverRef_t * serverRefp; 
1142
1143     cellp = cm_FindCellByID(a_cellnum, CM_FLAG_NOPROBE);
1144     if (!cellp) {
1145         *a_name = strdup("");
1146         return 0;
1147     }
1148
1149     lock_ObtainRead(&cm_serverLock);
1150     *a_name = strdup(cellp->name);
1151
1152     for ( sn = 0, serverRefp = cellp->vlServersp; 
1153           sn < AFSMAXCELLHOSTS && serverRefp;
1154           sn++, serverRefp = serverRefp->next);
1155
1156     a_hosts->serverList_len = sn;
1157     a_hosts->serverList_val = (afs_int32 *)xdr_alloc(sn * sizeof(afs_int32));
1158
1159     for ( sn = 0, serverRefp = cellp->vlServersp; 
1160           sn < AFSMAXCELLHOSTS && serverRefp;
1161           sn++, serverRefp = serverRefp->next)
1162     {
1163         a_hosts->serverList_val[sn] = ntohl(serverRefp->server->addr.sin_addr.s_addr);
1164     }
1165
1166     lock_ReleaseRead(&cm_serverLock);
1167     return 0;
1168 }
1169
1170 /* debug interface */
1171 int 
1172 SRXAFSCB_GetCellByNum(struct rx_call *callp, afs_int32 a_cellnum,
1173                       char **a_name, serverList *a_hosts)
1174 {
1175     struct rx_connection *connp;
1176     struct rx_peer *peerp;
1177     unsigned long host = 0;
1178     unsigned short port = 0;
1179     int rc;
1180
1181     if (cm_shutdown)
1182         return 1;
1183
1184     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1185         host = rx_HostOf(peerp);
1186         port = rx_PortOf(peerp);
1187     }
1188
1189     osi_Log3(afsd_logp, "SRXAFSCB_GetCellByNum(%d) from host 0x%x port %d",
1190              a_cellnum, ntohl(host), ntohs(port));
1191
1192     a_hosts->serverList_val = 0;
1193     a_hosts->serverList_len = 0;
1194
1195
1196     rc = GetCellCommon(a_cellnum, a_name, a_hosts);
1197
1198     return rc;
1199 }
1200
1201 /* debug interface */
1202 int 
1203 SRXAFSCB_TellMeAboutYourself( struct rx_call *callp, 
1204                               struct interfaceAddr *addr,
1205                               Capabilities * capabilities)
1206 {
1207     int i;
1208     afs_uint32 *dataBuffP;
1209     afs_int32 dataBytes;
1210     long code;
1211     struct rx_connection *connp;
1212     struct rx_peer *peerp;
1213     unsigned long host = 0;
1214     unsigned short port = 0;
1215
1216     if (cm_shutdown)
1217         return 1;
1218
1219     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1220         host = rx_HostOf(peerp);
1221         port = rx_PortOf(peerp);
1222     }
1223
1224     osi_Log2(afsd_logp, "SRXAFSCB_TellMeAboutYourself from host 0x%x port %d",
1225               ntohl(host),
1226               ntohs(port));
1227
1228     lock_ObtainRead(&cm_syscfgLock);
1229     if (cm_LanAdapterChangeDetected) {
1230         lock_ConvertRToW(&cm_syscfgLock);
1231         if (cm_LanAdapterChangeDetected) {
1232             /* get network related info */
1233             cm_noIPAddr = CM_MAXINTERFACE_ADDR;
1234             code = syscfg_GetIFInfo(&cm_noIPAddr,
1235                                      cm_IPAddr, cm_SubnetMask,
1236                                      cm_NetMtu, cm_NetFlags);
1237             cm_LanAdapterChangeDetected = 0;
1238         }
1239         lock_ConvertWToR(&cm_syscfgLock);
1240     }
1241
1242     /* return all network interface addresses */
1243     addr->numberOfInterfaces = cm_noIPAddr;
1244     addr->uuid = cm_data.Uuid;
1245     for ( i=0; i < cm_noIPAddr; i++ ) {
1246         addr->addr_in[i] = cm_IPAddr[i];
1247         addr->subnetmask[i] = cm_SubnetMask[i];
1248         addr->mtu[i] = (rx_mtu == -1 || (rx_mtu != -1 && cm_NetMtu[i] < rx_mtu)) ? 
1249             cm_NetMtu[i] : rx_mtu;
1250     }
1251     lock_ReleaseRead(&cm_syscfgLock);
1252
1253     dataBytes = 1 * sizeof(afs_uint32);
1254     dataBuffP = (afs_uint32 *) xdr_alloc(dataBytes);
1255     dataBuffP[0] = CLIENT_CAPABILITY_ERRORTRANS;
1256     capabilities->Capabilities_len = dataBytes / sizeof(afs_uint32);
1257     capabilities->Capabilities_val = dataBuffP;
1258
1259     return 0;
1260 }
1261
1262 /*------------------------------------------------------------------------
1263  * EXPORTED SRXAFSCB_GetServerPrefs
1264  *
1265  * Description:
1266  *      Routine to list server preferences used by this client.
1267  *
1268  * Arguments:
1269  *      a_call  : Ptr to Rx call on which this request came in.
1270  *      a_index : Input server index
1271  *      a_srvr_addr  : Output server address (0xffffffff on last server)
1272  *      a_srvr_rank  : Output server rank
1273  *
1274  * Returns:
1275  *      0 on success
1276  *
1277  * Environment:
1278  *      Nothing interesting.
1279  *
1280  * Side Effects:
1281  *      As advertised.
1282  *------------------------------------------------------------------------*/
1283
1284 int SRXAFSCB_GetServerPrefs(
1285     struct rx_call *callp,
1286     afs_int32 a_index,
1287     afs_int32 *a_srvr_addr,
1288     afs_int32 *a_srvr_rank)
1289 {
1290     struct rx_connection *connp;
1291     struct rx_peer *peerp;
1292     unsigned long host = 0;
1293     unsigned short port = 0;
1294
1295     if (cm_shutdown)
1296         return 1;
1297
1298     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1299         host = rx_HostOf(peerp);
1300         port = rx_PortOf(peerp);
1301     }
1302
1303     osi_Log2(afsd_logp, "SRXAFSCB_GetServerPrefs from host 0x%x port %d - not implemented",
1304               ntohl(host),
1305               ntohs(port));
1306
1307     *a_srvr_addr = 0xffffffff;
1308     *a_srvr_rank = 0xffffffff;
1309
1310     return 0;
1311 }
1312
1313 /*------------------------------------------------------------------------
1314  * EXPORTED SRXAFSCB_GetCellServDB
1315  *
1316  * Description:
1317  *      Routine to list cells configured for this client
1318  *
1319  * Arguments:
1320  *      a_call  : Ptr to Rx call on which this request came in.
1321  *      a_index : Input cell index
1322  *      a_name  : Output cell name ("" on last cell)
1323  *      a_hosts : Output cell database servers
1324  *
1325  * Returns:
1326  *      0 on success
1327  *
1328  * Environment:
1329  *      Nothing interesting.
1330  *
1331  * Side Effects:
1332  *      As advertised.
1333  *------------------------------------------------------------------------*/
1334
1335 int SRXAFSCB_GetCellServDB(struct rx_call *callp, afs_int32 index, char **a_name, 
1336                            serverList *a_hosts)
1337 {
1338     struct rx_connection *connp;
1339     struct rx_peer *peerp;
1340     unsigned long host = 0;
1341     unsigned short port = 0;
1342     int rc;
1343
1344     if (cm_shutdown)
1345         return 1;
1346
1347     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1348         host = rx_HostOf(peerp);
1349         port = rx_PortOf(peerp);
1350     }
1351
1352     osi_Log2(afsd_logp, "SRXAFSCB_GetCellServDB from host 0x%x port %d - not implemented",
1353              ntohl(host), ntohs(port));
1354
1355 #ifdef AFS_FREELANCE_CLIENT
1356     if (cm_freelanceEnabled && index == 0) {
1357         rc = GetCellCommon(AFS_FAKE_ROOT_CELL_ID, a_name, a_hosts);
1358     } else
1359 #endif
1360     {
1361         rc = GetCellCommon(index+1, a_name, a_hosts);
1362     }
1363     return 0;
1364 }
1365
1366 /*------------------------------------------------------------------------
1367  * EXPORTED SRXAFSCB_GetLocalCell
1368  *
1369  * Description:
1370  *      Routine to return name of client's local cell
1371  *
1372  * Arguments:
1373  *      a_call  : Ptr to Rx call on which this request came in.
1374  *      a_name  : Output cell name
1375  *
1376  * Returns:
1377  *      0 on success
1378  *
1379  * Environment:
1380  *      Nothing interesting.
1381  *
1382  * Side Effects:
1383  *      As advertised.
1384  *------------------------------------------------------------------------*/
1385
1386 int SRXAFSCB_GetLocalCell(struct rx_call *callp, char **a_name)
1387 {
1388     char *t_name;
1389     struct rx_connection *connp;
1390     struct rx_peer *peerp;
1391     unsigned long host = 0;
1392     unsigned short port = 0;
1393
1394     if (cm_shutdown)
1395         return 1;
1396
1397     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1398         host = rx_HostOf(peerp);
1399         port = rx_PortOf(peerp);
1400     }
1401
1402     osi_Log2(afsd_logp, "SRXAFSCB_GetLocalCell from host 0x%x port %d",
1403              ntohl(host), ntohs(port));
1404
1405     if (cm_data.rootCellp) {
1406         t_name = strdup(cm_data.rootCellp->name);
1407     } else {
1408         t_name = (char *)xdr_alloc(1);
1409         t_name[0] = '\0';
1410     }
1411     *a_name = t_name;
1412
1413     return 0;
1414 }
1415
1416
1417 /*
1418  * afs_MarshallCacheConfig - marshall client cache configuration
1419  *
1420  * PARAMETERS
1421  *
1422  * IN callerVersion - the rpc stat version of the caller.
1423  *
1424  * IN config - client cache configuration.
1425  *
1426  * OUT ptr - buffer where configuration is marshalled.
1427  *
1428  * RETURN CODES
1429  *
1430  * Returns void.
1431  */
1432 static void afs_MarshallCacheConfig(
1433     afs_uint32 callerVersion,
1434     cm_initparams_v1 *config,
1435     afs_uint32 *ptr)
1436 {
1437     /*
1438      * We currently only support version 1.
1439      */
1440     *(ptr++) = config->nChunkFiles;
1441     *(ptr++) = config->nStatCaches;
1442     *(ptr++) = config->nDataCaches;
1443     *(ptr++) = config->nVolumeCaches;
1444     *(ptr++) = config->firstChunkSize;
1445     *(ptr++) = config->otherChunkSize;
1446     *(ptr++) = config->cacheSize;
1447     *(ptr++) = config->setTime;
1448     *(ptr++) = config->memCache;
1449
1450 }
1451  
1452
1453 /*------------------------------------------------------------------------
1454  * EXPORTED SRXAFSCB_GetCacheConfig
1455  *
1456  * Description:
1457  *      Routine to return parameters used to initialize client cache.
1458  *      Client may request any format version. Server may not return
1459  *      format version greater than version requested by client.
1460  *
1461  * Arguments:
1462  *      a_call:        Ptr to Rx call on which this request came in.
1463  *      callerVersion: Data format version desired by the client.
1464  *      serverVersion: Data format version of output data.
1465  *      configCount:   Number bytes allocated for output data.
1466  *      config:        Client cache configuration.
1467  *
1468  * Returns:
1469  *      0 on success
1470  *
1471  * Environment:
1472  *      Nothing interesting.
1473  *
1474  * Side Effects:
1475  *      As advertised.
1476  *------------------------------------------------------------------------*/
1477
1478 int SRXAFSCB_GetCacheConfig(struct rx_call *callp,
1479                             afs_uint32 callerVersion,
1480                             afs_uint32 *serverVersion,
1481                             afs_uint32 *configCount,
1482                             cacheConfig *config)
1483 {
1484     afs_uint32 *t_config;
1485     size_t allocsize;
1486     extern cm_initparams_v1 cm_initParams;
1487     struct rx_connection *connp;
1488     struct rx_peer *peerp;
1489     unsigned long host = 0;
1490     unsigned short port = 0;
1491
1492     if (cm_shutdown)
1493         return 1;
1494
1495     if ((connp = rx_ConnectionOf(callp)) && (peerp = rx_PeerOf(connp))) {
1496         host = rx_HostOf(peerp);
1497         port = rx_PortOf(peerp);
1498     }
1499
1500     osi_Log2(afsd_logp, "SRXAFSCB_GetCacheConfig from host 0x%x port %d - version 1 only",
1501              ntohl(host), ntohs(port));
1502
1503     /*
1504      * Currently only support version 1
1505      */
1506     allocsize = sizeof(cm_initparams_v1);
1507     t_config = (afs_uint32 *)xdr_alloc(allocsize);
1508
1509     afs_MarshallCacheConfig(callerVersion, &cm_initParams, t_config);
1510
1511     *serverVersion = AFS_CLIENT_RETRIEVAL_FIRST_EDITION;
1512 #ifdef DEBUG
1513 #ifndef SIZE_MAX
1514 #define SIZE_MAX UINT_MAX
1515 #endif
1516     osi_assertx(allocsize < SIZE_MAX, "allocsize >= SIZE_MAX");
1517 #endif
1518     *configCount = (afs_uint32)allocsize;
1519     config->cacheConfig_val = t_config;
1520     config->cacheConfig_len = (*configCount)/sizeof(afs_uint32);
1521
1522     return 0;
1523 }
1524
1525 /* called by afsd without any locks to initialize this module */
1526 void cm_InitCallback(void)
1527 {
1528     lock_InitializeRWLock(&cm_callbackLock, "cm_callbackLock", LOCK_HIERARCHY_CALLBACK_GLOBAL);
1529     cm_activeCallbackGrantingCalls = 0;
1530 }
1531
1532 /* called with locked scp; tells us whether we've got a callback.
1533  * Expirations are checked by a background daemon so as to make
1534  * this function as inexpensive as possible
1535  */
1536 int cm_HaveCallback(cm_scache_t *scp)
1537 {
1538 #ifdef AFS_FREELANCE_CLIENT
1539     if (cm_freelanceEnabled && 
1540         scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
1541         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
1542         if (cm_getLocalMountPointChange()) {
1543             cm_clearLocalMountPointChange();
1544             lock_ReleaseWrite(&scp->rw);
1545             cm_reInitLocalMountPoints();
1546             lock_ObtainWrite(&scp->rw);
1547         }
1548         return (cm_data.fakeDirVersion == scp->dataVersion);
1549     }
1550 #endif
1551     if (cm_readonlyVolumeVersioning &&
1552         (scp->flags & CM_SCACHEFLAG_PURERO)) {
1553         cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
1554         if (volp) {
1555             int haveCB = 0;
1556             if (cm_OfflineROIsValid) {
1557                 switch (cm_GetVolumeStatus(volp, scp->fid.volume)) {
1558                 case vl_offline:
1559                 case vl_alldown:
1560                 case vl_unknown:
1561                     haveCB = 1;
1562                     break;
1563                 }
1564             }
1565             if (!haveCB &&
1566                 volp->creationDateRO == scp->volumeCreationDate &&
1567                 volp->cbServerpRO != NULL) {
1568                 haveCB = 1;
1569             }
1570             cm_PutVolume(volp);
1571             return haveCB;
1572         }
1573     }
1574     if (scp->cbServerp != NULL)
1575         return 1;
1576     else
1577         return 0;
1578 }
1579
1580 /* need to detect a broken callback that races with our obtaining a callback.
1581  * Need to be able to do this even if we don't know the file ID of the file
1582  * we're breaking the callback on at the time we start the acquisition of the
1583  * callback (as in the case where we are creating a file).
1584  *
1585  * So, we start by writing down the count of the # of callbacks we've received
1586  * so far, and bumping a global counter of the # of callback granting calls
1587  * outstanding (all done under cm_callbackLock).
1588  *
1589  * When we're back from the call, we look at all of the callback revokes with
1590  * counter numbers greater than the one we recorded in our caller's structure,
1591  * and replay those that are higher than when we started the call.
1592  * 
1593  * We free all the structures in the queue when the count of the # of outstanding
1594  * callback-granting calls drops to zero.
1595  *
1596  * We call this function with the scp locked, too, but in its current implementation,
1597  * this knowledge is not used.
1598  */
1599 void cm_StartCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp)
1600 {
1601     lock_ObtainWrite(&cm_callbackLock);
1602     cbrp->callbackCount = cm_callbackCount;
1603     cm_activeCallbackGrantingCalls++;
1604     cbrp->startTime = time(NULL);
1605     cbrp->serverp = NULL;
1606     lock_ReleaseWrite(&cm_callbackLock);
1607 }
1608
1609 /* Called at the end of a callback-granting call, to remove the callback
1610  * info from the scache entry, if necessary.
1611  *
1612  * Called with scp write locked, so we can discard the callbacks easily with
1613  * this locking hierarchy.
1614  */
1615 void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
1616                                 AFSCallBack *cbp, AFSVolSync *volSyncp, long flags)
1617 {
1618     cm_racingRevokes_t *revp;           /* where we are */
1619     cm_racingRevokes_t *nrevp;          /* where we'll be next */
1620     int freeFlag;
1621     cm_server_t * serverp = NULL;
1622     int discardScp = 0, discardVolCB = 0;
1623
1624     lock_ObtainWrite(&cm_callbackLock);
1625     if (flags & CM_CALLBACK_MAINTAINCOUNT) {
1626         osi_assertx(cm_activeCallbackGrantingCalls > 0, 
1627                     "CM_CALLBACK_MAINTAINCOUNT && cm_activeCallbackGrantingCalls == 0");
1628     }
1629     else {
1630         osi_assertx(cm_activeCallbackGrantingCalls-- > 0,
1631                     "!CM_CALLBACK_MAINTAINCOUNT && cm_activeCallbackGrantingCalls == 0");
1632     }
1633     if (cm_activeCallbackGrantingCalls == 0) 
1634         freeFlag = 1;
1635     else 
1636         freeFlag = 0;
1637
1638     /* record the callback; we'll clear it below if we really lose it */
1639     if (cbrp) {
1640         if (scp) {
1641             if (!cm_ServerEqual(scp->cbServerp, cbrp->serverp)) {
1642                 serverp = scp->cbServerp;
1643                 if (!freeFlag)
1644                     cm_GetServer(cbrp->serverp);
1645                 scp->cbServerp = cbrp->serverp;
1646             } else {
1647                 if (freeFlag)
1648                     serverp = cbrp->serverp;
1649             }
1650             scp->cbExpires = cbrp->startTime + cbp->ExpirationTime;
1651         } else {
1652             if (freeFlag)
1653                 serverp = cbrp->serverp;
1654         }
1655         if (freeFlag)
1656             cbrp->serverp = NULL;
1657     }
1658
1659     /* a callback was actually revoked during our granting call, so
1660      * run down the list of revoked fids, looking for ours.
1661      * If activeCallbackGrantingCalls is zero, free the elements, too.
1662      *
1663      * May need to go through entire list just to do the freeing.
1664      */
1665     for (revp = cm_racingRevokesp; revp; revp = nrevp) {
1666         nrevp = (cm_racingRevokes_t *) osi_QNext(&revp->q);
1667         /* if this callback came in later than when we started the
1668          * callback-granting call, and if this fid is the right fid,
1669          * then clear the callback.
1670          */
1671         if (scp && cbrp && cbrp->callbackCount != cm_callbackCount
1672              && revp->callbackCount > cbrp->callbackCount
1673              && (( scp->fid.volume == revp->fid.volume &&
1674                    scp->fid.vnode == revp->fid.vnode &&
1675                    scp->fid.unique == revp->fid.unique)
1676                   ||
1677                   ((revp->flags & CM_RACINGFLAG_CANCELVOL) &&
1678                     scp->fid.volume == revp->fid.volume)
1679                   ||
1680                   ((revp->flags & CM_RACINGFLAG_CANCELALL) && 
1681                    (revp->fid.cell == 0 || scp->fid.cell == revp->fid.cell)))) {
1682             /* this one matches */
1683             osi_Log4(afsd_logp,
1684                       "Racing revoke scp 0x%p old cbc %d rev cbc %d cur cbc %d",
1685                       scp,
1686                       cbrp->callbackCount, revp->callbackCount,
1687                       cm_callbackCount);
1688             discardScp = 1;
1689             if ((scp->flags & CM_SCACHEFLAG_PURERO) &&
1690                  (revp->flags & CM_RACINGFLAG_ALL))
1691                 cm_callbackDiscardROVolumeByFID(&scp->fid);
1692         }
1693         if (freeFlag) 
1694             free(revp);
1695     }
1696
1697     /* if we freed the list, zap the pointer to it */
1698     if (freeFlag) 
1699         cm_racingRevokesp = NULL;
1700
1701     lock_ReleaseWrite(&cm_callbackLock);
1702
1703     if ( discardScp ) {
1704         cm_DiscardSCache(scp);
1705         lock_ReleaseWrite(&scp->rw);
1706         cm_CallbackNotifyChange(scp);
1707         lock_ObtainWrite(&scp->rw);
1708     } else {
1709         if (scp && scp->flags & CM_SCACHEFLAG_PURERO) {
1710             cm_volume_t * volp = cm_GetVolumeByFID(&scp->fid);
1711             if (volp) {
1712                 if (volSyncp) {
1713                     lock_ObtainWrite(&cm_scacheLock);
1714                     volp->cbExpiresRO = scp->cbExpires;
1715                     volp->creationDateRO = volSyncp->spare1;
1716                     if (volp->cbServerpRO != scp->cbServerp) {
1717                         if (volp->cbServerpRO)
1718                             cm_PutServer(volp->cbServerpRO);
1719                         cm_GetServer(scp->cbServerp);
1720                         volp->cbServerpRO = scp->cbServerp;
1721                     }
1722                     lock_ReleaseWrite(&cm_scacheLock);
1723                 }
1724                 cm_PutVolume(volp);
1725             }
1726         }
1727     }
1728
1729     if ( serverp ) {
1730         lock_ObtainWrite(&cm_serverLock);
1731         cm_FreeServer(serverp);
1732         lock_ReleaseWrite(&cm_serverLock);
1733     }
1734 }
1735
1736 /* if flags is 1, we want to force the code to make one call, anyway.
1737  * called with locked scp; returns with same.
1738  */
1739 long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
1740                     struct cm_req *reqp, long flags)
1741 {
1742     long code = 0;
1743     cm_conn_t *connp = NULL;
1744     AFSFetchStatus afsStatus;
1745     AFSVolSync volSync;
1746     AFSCallBack callback;
1747     AFSFid tfid;
1748     cm_callbackRequest_t cbr;
1749     int mustCall;
1750     cm_fid_t sfid;
1751     struct rx_connection * rxconnp = NULL;
1752     int syncop_done = 0;
1753
1754     memset(&volSync, 0, sizeof(volSync));
1755
1756     osi_Log4(afsd_logp, "GetCallback scp 0x%p cell %d vol %d flags %lX", 
1757              scp, scp->fid.cell, scp->fid.volume, flags);
1758
1759 #ifdef AFS_FREELANCE_CLIENT
1760     // The case where a callback is needed on /afs is handled
1761     // specially. We need to fetch the status by calling
1762     // cm_MergeStatus
1763     if (cm_freelanceEnabled &&
1764         (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
1765          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)) {
1766
1767         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1768                           CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK);
1769         if (code)
1770             goto done;
1771         syncop_done = 1;
1772
1773         if (scp->dataVersion != cm_data.fakeDirVersion) {
1774             memset(&afsStatus, 0, sizeof(afsStatus));
1775             memset(&volSync, 0, sizeof(volSync));
1776
1777             // Fetch the status info 
1778             cm_MergeStatus(NULL, scp, &afsStatus, &volSync, userp, reqp, 0);
1779         }
1780         goto done;
1781     }
1782 #endif /* AFS_FREELANCE_CLIENT */
1783         
1784     mustCall = (flags & 1);
1785     cm_AFSFidFromFid(&tfid, &scp->fid);
1786     while (1) {
1787         if (!mustCall && cm_HaveCallback(scp))
1788             break;
1789
1790         /* turn off mustCall, since it has now forced us past the check above */
1791         mustCall = 0;
1792
1793         /* otherwise, we have to make an RPC to get the status */
1794         if (!syncop_done) {
1795             code = cm_SyncOp(scp, NULL, userp, reqp, 0, 
1796                              CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK);
1797             if (code)
1798                 break;
1799             syncop_done = 1;
1800         }
1801         cm_StartCallbackGrantingCall(scp, &cbr);
1802         sfid = scp->fid;
1803         lock_ReleaseWrite(&scp->rw);
1804                 
1805         /* now make the RPC */
1806         osi_Log4(afsd_logp, "CALL FetchStatus scp 0x%p vol %u vn %u uniq %u", 
1807                  scp, sfid.volume, sfid.vnode, sfid.unique);
1808         do {
1809             code = cm_ConnFromFID(&sfid, userp, reqp, &connp);
1810             if (code) 
1811                 continue;
1812
1813             rxconnp = cm_GetRxConn(connp);
1814             code = RXAFS_FetchStatus(rxconnp, &tfid,
1815                                      &afsStatus, &callback, &volSync);
1816             rx_PutConnection(rxconnp);
1817
1818         } while (cm_Analyze(connp, userp, reqp, &sfid, &volSync, NULL,
1819                             &cbr, code));
1820         code = cm_MapRPCError(code, reqp);
1821         if (code)
1822             osi_Log4(afsd_logp, "CALL FetchStatus FAILURE code 0x%x scp 0x%p vol %u vn %u", 
1823                      code, scp, scp->fid.volume, scp->fid.vnode);
1824         else
1825             osi_Log4(afsd_logp, "CALL FetchStatus SUCCESS scp 0x%p vol %u vn %u uniq %u", 
1826                      scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
1827
1828         lock_ObtainWrite(&scp->rw);
1829         if (code == 0) {
1830             cm_EndCallbackGrantingCall(scp, &cbr, &callback, &volSync, 0);
1831             cm_MergeStatus(NULL, scp, &afsStatus, &volSync, userp, reqp, 0);
1832         } else {
1833             cm_EndCallbackGrantingCall(NULL, &cbr, NULL, NULL, 0);
1834         }
1835
1836         /* if we got an error, return to caller */
1837         if (code)
1838             break;
1839     }
1840
1841   done:
1842     if (syncop_done)
1843         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK);
1844     
1845     if (code) {
1846         osi_Log2(afsd_logp, "GetCallback Failed code 0x%x scp 0x%p -->",code, scp);
1847         osi_Log4(afsd_logp, "            cell %u vol %u vn %u uniq %u",
1848                  scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
1849     } else {
1850         osi_Log3(afsd_logp, "GetCallback Complete scp 0x%p cell %d vol %d", 
1851                   scp, scp->fid.cell, scp->fid.volume);
1852     }
1853
1854     return code;
1855 }
1856
1857
1858 /*
1859  * cm_CBServersDownTime() returns 1 if the downTime parameter is valid.
1860  *
1861  * Servers with multiple interfaces have multiple cm_server_t objects
1862  * which share the same UUID.  If one interface is down but others are up,
1863  * the server should not be considered down.  The returned downTime should
1864  * be the largest non-zero value if down or zero if up.  If the cbServerp
1865  * is down, it is updated to refer to an interface that is up (if one exists).
1866  *
1867  * called with cm_scacheLock held
1868  */
1869 static long
1870 cm_CBServersDownTime(cm_scache_t *scp, cm_volume_t *volp, time_t * pdownTime)
1871 {
1872     cm_vol_state_t *statep;
1873     cm_serverRef_t *tsrp;
1874     int alldown = 1;
1875     time_t downTime = 0;
1876     cm_server_t * upserver = NULL;
1877     cm_server_t * downserver;
1878
1879     *pdownTime = 0;
1880
1881     if (scp->cbServerp == NULL)
1882         return 1;
1883
1884     if (!(scp->cbServerp->flags & CM_SERVERFLAG_DOWN))
1885         return 1;
1886
1887     statep = cm_VolumeStateByID(volp, scp->fid.volume);
1888     if (statep) {
1889         for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
1890             if (tsrp->status == srv_deleted)
1891                 continue;
1892
1893             if (!cm_ServerEqual(tsrp->server, scp->cbServerp))
1894                 continue;
1895
1896             if (!(tsrp->server->flags & CM_SERVERFLAG_DOWN)) {
1897                 alldown = 0;
1898                 if (!upserver) {
1899                     upserver = tsrp->server;
1900                     cm_GetServer(upserver);
1901                 }
1902             }
1903
1904             if (tsrp->server->downTime > downTime)
1905                 downTime = tsrp->server->downTime;
1906         }
1907     } else {
1908         downTime = scp->cbServerp->downTime;
1909     }
1910
1911     /* if the cbServerp does not match the current volume server list
1912      * we report the callback server as up so the callback can be 
1913      * expired.
1914      */
1915
1916     if (alldown) {
1917         *pdownTime = downTime;
1918     } else {
1919         lock_ObtainWrite(&scp->rw);
1920         downserver = scp->cbServerp;
1921         scp->cbServerp = upserver;
1922         lock_ReleaseWrite(&scp->rw);
1923         cm_PutServer(downserver);
1924     }
1925     return 1;
1926 }
1927
1928 /* called periodically by cm_daemon to shut down use of expired callbacks */
1929 void cm_CheckCBExpiration(void)
1930 {
1931     afs_uint32 i;
1932     cm_scache_t *scp;
1933     cm_volume_t *volp;
1934     enum volstatus volstate;
1935     time_t now, downTime;
1936         
1937     osi_Log0(afsd_logp, "CheckCBExpiration");
1938
1939     now = time(NULL);
1940     lock_ObtainWrite(&cm_scacheLock);
1941     for (i=0; i<cm_data.scacheHashTableSize; i++) {
1942         for (scp = cm_data.scacheHashTablep[i]; scp; scp=scp->nextp) {
1943             volp = NULL;
1944             cm_HoldSCacheNoLock(scp);
1945             lock_ReleaseWrite(&cm_scacheLock);
1946
1947             /*
1948              * If this is not a PURERO object and there is no callback
1949              * or it hasn't expired, there is nothing to do
1950              */
1951             if (!(scp->flags & CM_SCACHEFLAG_PURERO) &&
1952                 (scp->cbServerp == NULL || scp->cbExpires == 0 || now < scp->cbExpires))
1953                 goto scp_complete;
1954
1955             /*
1956              * Determine the volume state and update the callback info
1957              * to the latest if it is a PURERO object.
1958              */
1959             volp = cm_GetVolumeByFID(&scp->fid);
1960             volstate = vl_unknown;
1961             downTime = 0;
1962             if (volp) {
1963                 if ((scp->flags & CM_SCACHEFLAG_PURERO) &&
1964                     volp->cbExpiresRO > scp->cbExpires && scp->cbExpires > 0)
1965                 {
1966                     lock_ObtainWrite(&scp->rw);
1967                     scp->cbExpires = volp->cbExpiresRO;
1968                     if (volp->cbServerpRO != scp->cbServerp) {
1969                         if (scp->cbServerp)
1970                             cm_PutServer(scp->cbServerp);
1971                         cm_GetServer(volp->cbServerpRO);
1972                         scp->cbServerp = volp->cbServerpRO;
1973                     }
1974                     lock_ReleaseWrite(&scp->rw);
1975                 }
1976                 volstate = cm_GetVolumeStatus(volp, scp->fid.volume);
1977             }
1978
1979             /* If there is no callback or it hasn't expired, there is nothing to do */
1980             if (scp->cbServerp == NULL || scp->cbExpires == 0 || now < scp->cbExpires)
1981                 goto scp_complete;
1982
1983             /* If the volume is known not to be online, do not expire the callback */
1984             if (volstate != vl_online)
1985                 goto scp_complete;
1986
1987             /*
1988              * If all the servers are down and the callback expired after the
1989              * issuing server went down, do not expire the callback
1990              */
1991             if (cm_CBServersDownTime(scp, volp, &downTime) && downTime && downTime < scp->cbExpires)
1992                 goto scp_complete;
1993
1994             /* The callback has expired, discard the status info */
1995             osi_Log4(afsd_logp, "Callback Expiration Discarding SCache scp 0x%p vol %u vn %u uniq %u",
1996                      scp, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
1997             lock_ObtainWrite(&scp->rw);
1998             cm_DiscardSCache(scp);
1999             lock_ReleaseWrite(&scp->rw);
2000
2001             cm_CallbackNotifyChange(scp);
2002
2003           scp_complete:
2004             if (volp)
2005                 cm_PutVolume(volp);
2006
2007             lock_ObtainWrite(&cm_scacheLock);
2008             cm_ReleaseSCacheNoLock(scp);
2009         }
2010     }
2011     lock_ReleaseWrite(&cm_scacheLock);
2012
2013     osi_Log0(afsd_logp, "CheckCBExpiration Complete");
2014 }
2015
2016
2017 void 
2018 cm_GiveUpAllCallbacks(cm_server_t *tsp, afs_int32 markDown)
2019 {
2020     long code;
2021     cm_conn_t *connp;
2022     struct rx_connection * rxconnp;
2023
2024     if ((tsp->type == CM_SERVER_FILE) && !(tsp->flags & CM_SERVERFLAG_DOWN)) 
2025     {
2026         code = cm_ConnByServer(tsp, cm_rootUserp, &connp);
2027         if (code == 0) {
2028             rxconnp = cm_GetRxConn(connp);
2029             rx_SetConnDeadTime(rxconnp, 10);
2030             code = RXAFS_GiveUpAllCallBacks(rxconnp);
2031             rx_SetConnDeadTime(rxconnp, ConnDeadtimeout);
2032             rx_PutConnection(rxconnp);
2033         }
2034
2035         if (markDown) {
2036             cm_server_vols_t * tsrvp;
2037             cm_volume_t * volp;
2038             int i;
2039
2040             cm_ForceNewConnections(tsp);
2041
2042             lock_ObtainMutex(&tsp->mx);
2043             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
2044                 tsp->flags |= CM_SERVERFLAG_DOWN;
2045                 tsp->downTime = time(NULL);
2046             }
2047             /* Now update the volume status */
2048             for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
2049                 for (i=0; i<NUM_SERVER_VOLS; i++) {
2050                     if (tsrvp->ids[i] != 0) {
2051                         cm_req_t req;
2052
2053                         cm_InitReq(&req);
2054                         lock_ReleaseMutex(&tsp->mx);
2055                         code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
2056                                                  &req, CM_GETVOL_FLAG_NO_LRU_UPDATE | CM_GETVOL_FLAG_NO_RESET, &volp);
2057                         lock_ObtainMutex(&tsp->mx);
2058                         if (code == 0) {    
2059                             cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
2060                             cm_PutVolume(volp);
2061                         }       
2062                     }
2063                 }
2064             }
2065             lock_ReleaseMutex(&tsp->mx);
2066         }
2067     }
2068 }
2069
2070 void
2071 cm_GiveUpAllCallbacksAllServers(afs_int32 markDown)
2072 {
2073     cm_server_t *tsp;
2074
2075     if (!cm_giveUpAllCBs)
2076         return;
2077
2078     lock_ObtainWrite(&cm_serverLock);
2079     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
2080         cm_GetServerNoLock(tsp);
2081         lock_ReleaseWrite(&cm_serverLock);
2082         cm_GiveUpAllCallbacks(tsp, markDown);
2083         lock_ObtainWrite(&cm_serverLock);
2084         cm_PutServerNoLock(tsp);
2085     }
2086     lock_ReleaseWrite(&cm_serverLock);
2087 }
2088
2089 void
2090 cm_GiveUpAllCallbacksAllServersMulti(afs_int32 markDown)
2091 {
2092     long code;
2093     cm_conn_t **conns = NULL;
2094     struct rx_connection **rxconns = NULL;
2095     afs_int32 i, nconns = 0, maxconns;
2096     cm_server_t ** serversp, *tsp;
2097     afs_int32 *results;
2098     time_t start, *deltas;
2099
2100     maxconns = cm_numFileServers;
2101     if (maxconns == 0)
2102         return;
2103
2104     conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
2105     rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
2106     deltas = (time_t *)malloc(maxconns * sizeof (time_t));
2107     results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
2108     serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
2109
2110     lock_ObtainRead(&cm_serverLock);
2111     for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
2112         if (tsp->type != CM_SERVER_FILE ||
2113             (tsp->flags & CM_SERVERFLAG_DOWN) ||
2114             tsp->cellp == NULL          /* SetPrefs only */)
2115             continue;
2116
2117         cm_GetServerNoLock(tsp);
2118         lock_ReleaseRead(&cm_serverLock);
2119
2120         serversp[nconns] = tsp;
2121         code = cm_ConnByServer(tsp, cm_rootUserp, &conns[nconns]);
2122         if (code) {
2123             lock_ObtainRead(&cm_serverLock);
2124             cm_PutServerNoLock(tsp);
2125             continue;
2126         }
2127         lock_ObtainRead(&cm_serverLock);
2128         rxconns[nconns] = cm_GetRxConn(conns[nconns]);
2129         rx_SetConnDeadTime(rxconns[nconns], 10);
2130
2131         nconns++;
2132     }
2133     lock_ReleaseRead(&cm_serverLock);
2134
2135     if (nconns) {
2136         /* Perform the multi call */
2137         start = time(NULL);
2138         multi_Rx(rxconns,nconns)
2139         {
2140             multi_RXAFS_GiveUpAllCallBacks();
2141             results[multi_i]=multi_error;
2142         } multi_End;
2143     }
2144
2145     /* Process results of servers that support RXAFS_GetCapabilities */
2146     for (i=0; i<nconns; i++) {
2147         rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
2148         rx_PutConnection(rxconns[i]);
2149         cm_PutConn(conns[i]);
2150
2151         tsp = serversp[i];
2152         cm_GCConnections(tsp);
2153
2154         if (markDown) {
2155             cm_server_vols_t * tsrvp;
2156             cm_volume_t * volp;
2157             int i;
2158
2159             cm_ForceNewConnections(tsp);
2160
2161             lock_ObtainMutex(&tsp->mx);
2162             if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
2163                 tsp->flags |= CM_SERVERFLAG_DOWN;
2164                 tsp->downTime = time(NULL);
2165             }
2166             /* Now update the volume status */
2167             for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
2168                 for (i=0; i<NUM_SERVER_VOLS; i++) {
2169                     if (tsrvp->ids[i] != 0) {
2170                         cm_req_t req;
2171
2172                         cm_InitReq(&req);
2173                         lock_ReleaseMutex(&tsp->mx);
2174                         code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
2175                                                  &req, CM_GETVOL_FLAG_NO_LRU_UPDATE | CM_GETVOL_FLAG_NO_RESET, &volp);
2176                         lock_ObtainMutex(&tsp->mx);
2177                         if (code == 0) {
2178                             cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
2179                             cm_PutVolume(volp);
2180                         }
2181                     }
2182                 }
2183             }
2184             lock_ReleaseMutex(&tsp->mx);
2185         }
2186     }
2187
2188     free(conns);
2189     free(rxconns);
2190     free(deltas);
2191     free(results);
2192     free(serversp);
2193 }
2194
2195