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