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