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