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