4285fc41bfe50f92e4ed40a865520e957e2f9d3d
[openafs.git] / src / afs / afs_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 /*
11  * afs_callback.c:
12  *      Exported routines (and their private support) to implement
13  *      the callback RPC interface.
14  */
15
16 #include <afsconfig.h>
17 #include "afs/param.h"
18
19 RCSID("$Header$");
20
21 #include "afs/sysincludes.h" /*Standard vendor system headers*/
22 #include "afsincludes.h" /*AFS-based standard headers*/
23 #include "afs/afs_stats.h"      /*Cache Manager stats*/
24 #include "afs/afs_args.h"
25
26 afs_int32 afs_allCBs    = 0;            /*Break callbacks on all objects */
27 afs_int32 afs_oddCBs    = 0;            /*Break callbacks on dirs*/
28 afs_int32 afs_evenCBs = 0;              /*Break callbacks received on files*/
29 afs_int32 afs_allZaps = 0;              /*Objects entries deleted */
30 afs_int32 afs_oddZaps = 0;              /*Dir cache entries deleted*/
31 afs_int32 afs_evenZaps = 0;             /*File cache entries deleted*/
32 afs_int32 afs_connectBacks = 0;
33
34 /*
35  * Some debugging aids.
36  */
37 static struct ltable {
38     char *name;
39     char *addr;
40 } ltable []= {
41     {"afs_xvcache", (char *)&afs_xvcache},
42     {"afs_xdcache", (char *)&afs_xdcache},
43     {"afs_xserver", (char *)&afs_xserver},
44     {"afs_xvcb",    (char *)&afs_xvcb},
45     {"afs_xbrs",    (char *)&afs_xbrs},
46     {"afs_xcell",   (char *)&afs_xcell},
47     {"afs_xconn",   (char *)&afs_xconn},
48     {"afs_xuser",   (char *)&afs_xuser},
49     {"afs_xvolume", (char *)&afs_xvolume},
50     {"puttofile",   (char *)&afs_puttofileLock},
51     {"afs_ftf",     (char *)&afs_ftf},
52     {"afs_xcbhash", (char *)&afs_xcbhash},
53     {"afs_xaxs",    (char *)&afs_xaxs},
54     {"afs_xinterface", (char *)&afs_xinterface}
55 };
56 unsigned long  lastCallBack_vnode;
57 unsigned int   lastCallBack_dv;
58 osi_timeval_t  lastCallBack_time;
59
60 /* these are for storing alternate interface addresses */
61 struct interfaceAddr afs_cb_interface;
62
63 /*------------------------------------------------------------------------
64  * EXPORTED SRXAFSCB_GetCE
65  *
66  * Description:
67  *      Routine called by the server-side callback RPC interface to
68  *      implement pulling out the contents of the i'th cache entry.
69  *
70  * Arguments:
71  *      a_call   : Ptr to Rx call on which this request came in.
72  *      a_index  : Index of desired cache entry.
73  *      a_result : Ptr to a buffer for the given cache entry.
74  *
75  * Returns:
76  *      0 if everything went fine,
77  *      1 if we were given a bad index.
78  *
79  * Environment:
80  *      Nothing interesting.
81  *
82  * Side Effects:
83  *      As advertised.
84  *------------------------------------------------------------------------*/
85
86 int SRXAFSCB_GetCE(struct rx_call *a_call, afs_int32 a_index, struct AFSDBCacheEntry *a_result)
87 {
88
89     register int i;                     /*Loop variable*/
90     register struct vcache *tvc;        /*Ptr to current cache entry*/
91     int code;                           /*Return code*/
92     XSTATS_DECLS;
93
94     RX_AFS_GLOCK();
95
96     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_GETCE);
97
98     AFS_STATCNT(SRXAFSCB_GetCE);
99     for (i = 0; i < VCSIZE; i++) {
100         for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
101             if (a_index == 0)
102                 goto searchDone;
103             a_index--;
104         } /*Zip through current hash chain*/
105     } /*Zip through hash chains*/
106
107   searchDone:
108     if (tvc == NULL) {
109         /*Past EOF*/
110         code = 1;
111         goto fcnDone;
112     }
113
114     /*
115      * Copy out the located entry.
116      */
117     a_result->addr = afs_data_pointer_to_int32(tvc);
118     a_result->cell = tvc->fid.Cell;
119     a_result->netFid.Volume = tvc->fid.Fid.Volume;
120     a_result->netFid.Vnode = tvc->fid.Fid.Vnode;
121     a_result->netFid.Unique = tvc->fid.Fid.Unique;
122     a_result->lock.waitStates = tvc->lock.wait_states;
123     a_result->lock.exclLocked = tvc->lock.excl_locked;
124     a_result->lock.readersReading = tvc->lock.readers_reading;
125     a_result->lock.numWaiting = tvc->lock.num_waiting;
126 #if defined(INSTRUMENT_LOCKS)
127     a_result->lock.pid_last_reader = tvc->lock.pid_last_reader;
128     a_result->lock.pid_writer = tvc->lock.pid_writer;
129     a_result->lock.src_indicator = tvc->lock.src_indicator;
130 #else
131     /* On osf20 , the vcache does not maintain these three fields */
132     a_result->lock.pid_last_reader = 0;
133     a_result->lock.pid_writer = 0;
134     a_result->lock.src_indicator = 0;
135 #endif /* AFS_OSF20_ENV */
136 #ifdef AFS_64BIT_CLIENT
137     a_result->Length = (afs_int32) tvc->m.Length & 0xffffffff;
138 #else /* AFS_64BIT_CLIENT */
139     a_result->Length = tvc->m.Length;
140 #endif /* AFS_64BIT_CLIENT */
141     a_result->DataVersion = hgetlo(tvc->m.DataVersion);
142     a_result->callback = afs_data_pointer_to_int32(tvc->callback);              /* XXXX Now a pointer; change it XXXX */
143     a_result->cbExpires = tvc->cbExpires;
144     a_result->refCount = VREFCOUNT(tvc);
145     a_result->opens = tvc->opens;
146     a_result->writers = tvc->execsOrWriters;
147     a_result->mvstat = tvc->mvstat;
148     a_result->states = tvc->states;
149     code = 0;
150
151     /*
152      * Return our results.
153      */
154 fcnDone:
155     XSTATS_END_TIME;
156
157     RX_AFS_GUNLOCK();
158
159     return(code);
160
161 } /*SRXAFSCB_GetCE*/
162
163 int SRXAFSCB_GetCE64(struct rx_call *a_call, afs_int32 a_index, struct AFSDBCacheEntry64 *a_result)
164 {
165     register int i;                     /*Loop variable*/
166     register struct vcache *tvc;        /*Ptr to current cache entry*/
167     int code;                           /*Return code*/
168     XSTATS_DECLS;
169
170     RX_AFS_GLOCK();
171
172     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_GETCE);
173
174     AFS_STATCNT(SRXAFSCB_GetCE64);
175     for (i = 0; i < VCSIZE; i++) {
176         for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
177             if (a_index == 0)
178                 goto searchDone;
179             a_index--;
180         } /*Zip through current hash chain*/
181     } /*Zip through hash chains*/
182
183   searchDone:
184     if (tvc == NULL) {
185         /*Past EOF*/
186         code = 1;
187         goto fcnDone;
188     }
189
190     /*
191      * Copy out the located entry.
192      */
193     a_result->addr = afs_data_pointer_to_int32(tvc);
194     a_result->cell = tvc->fid.Cell;
195     a_result->netFid.Volume = tvc->fid.Fid.Volume;
196     a_result->netFid.Vnode = tvc->fid.Fid.Vnode;
197     a_result->netFid.Unique = tvc->fid.Fid.Unique;
198     a_result->lock.waitStates = tvc->lock.wait_states;
199     a_result->lock.exclLocked = tvc->lock.excl_locked;
200     a_result->lock.readersReading = tvc->lock.readers_reading;
201     a_result->lock.numWaiting = tvc->lock.num_waiting;
202 #if defined(INSTRUMENT_LOCKS)
203     a_result->lock.pid_last_reader = tvc->lock.pid_last_reader;
204     a_result->lock.pid_writer = tvc->lock.pid_writer;
205     a_result->lock.src_indicator = tvc->lock.src_indicator;
206 #else
207     /* On osf20 , the vcache does not maintain these three fields */
208     a_result->lock.pid_last_reader = 0;
209     a_result->lock.pid_writer = 0;
210     a_result->lock.src_indicator = 0;
211 #endif /* AFS_OSF20_ENV */
212 #ifdef AFS_64BIT_ENV
213     a_result->Length = tvc->m.Length;
214 #else /* AFS_64BIT_ENV */
215 #ifdef AFS_64BIT_CLIENT
216     a_result->Length = tvc->m.Length;
217 #else /* AFS_64BIT_CLIENT */
218     a_result->Length.high = 0;
219     a_result->Length.low = tvc->m.Length;
220 #endif /* AFS_64BIT_CLIENT */
221 #endif /* AFS_64BIT_ENV */
222     a_result->DataVersion = hgetlo(tvc->m.DataVersion);
223     a_result->callback = afs_data_pointer_to_int32(tvc->callback);              /* XXXX Now a pointer; change it XXXX */
224     a_result->cbExpires = tvc->cbExpires;
225     a_result->refCount = VREFCOUNT(tvc);
226     a_result->opens = tvc->opens;
227     a_result->writers = tvc->execsOrWriters;
228     a_result->mvstat = tvc->mvstat;
229     a_result->states = tvc->states;
230     code = 0;
231
232     /*
233      * Return our results.
234      */
235 fcnDone:
236     XSTATS_END_TIME;
237
238     RX_AFS_GUNLOCK();
239
240     return(code);
241
242 } /*SRXAFSCB_GetCE64*/
243
244
245 /*------------------------------------------------------------------------
246  * EXPORTED SRXAFSCB_GetLock
247  *
248  * Description:
249  *      Routine called by the server-side callback RPC interface to
250  *      implement pulling out the contents of a lock in the lock
251  *      table.
252  *
253  * Arguments:
254  *      a_call   : Ptr to Rx call on which this request came in.
255  *      a_index  : Index of desired lock.
256  *      a_result : Ptr to a buffer for the given lock.
257  *
258  * Returns:
259  *      0 if everything went fine,
260  *      1 if we were given a bad index.
261  *
262  * Environment:
263  *      Nothing interesting.
264  *
265  * Side Effects:
266  *      As advertised.
267  *------------------------------------------------------------------------*/
268
269 int SRXAFSCB_GetLock (struct rx_call *a_call, afs_int32 a_index, struct AFSDBLock *a_result)
270 {
271     struct ltable *tl;          /*Ptr to lock table entry*/
272     int nentries;               /*Num entries in table*/
273     int code;                   /*Return code*/
274     XSTATS_DECLS;
275
276     RX_AFS_GLOCK();
277
278     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_GETLOCK);
279     
280     AFS_STATCNT(SRXAFSCB_GetLock);
281     nentries = sizeof(ltable)/sizeof(struct ltable);
282     if (a_index < 0 || a_index >= nentries) {
283         /*
284           * Past EOF
285           */
286         code = 1;
287     }
288     else {
289         /*
290          * Found it - copy out its contents.
291          */
292         tl = &ltable[a_index];
293         strcpy(a_result->name, tl->name);
294         a_result->lock.waitStates = ((struct afs_lock *)(tl->addr))->wait_states;
295         a_result->lock.exclLocked = ((struct afs_lock *)(tl->addr))->excl_locked;
296         a_result->lock.readersReading = ((struct afs_lock *)(tl->addr))->readers_reading;
297         a_result->lock.numWaiting = ((struct afs_lock *)(tl->addr))->num_waiting;
298 #ifdef INSTRUMENT_LOCKS
299         a_result->lock.pid_last_reader = ((struct afs_lock *)(tl->addr))->pid_last_reader;
300         a_result->lock.pid_writer = ((struct afs_lock *)(tl->addr))->pid_writer;
301         a_result->lock.src_indicator = ((struct afs_lock *)(tl->addr))->src_indicator;
302 #else
303         a_result->lock.pid_last_reader = 0;
304         a_result->lock.pid_writer = 0;
305         a_result->lock.src_indicator = 0;
306 #endif
307         code = 0;
308     }
309
310     XSTATS_END_TIME;
311
312     RX_AFS_GUNLOCK();
313
314     return(code);
315
316 }  /*SRXAFSCB_GetLock*/
317
318
319 /*------------------------------------------------------------------------
320  * static ClearCallBack
321  *
322  * Description:
323  *      Clear out callback information for the specified file, or
324  *      even a whole volume.  Used to worry about callback was from 
325  *      within the particular cell or not.  Now we don't bother with
326  *      that anymore; it's not worth the time.
327  *
328  * Arguments:
329  *      a_conn : Ptr to Rx connection involved.
330  *      a_fid  : Ptr to AFS fid being cleared.
331  *
332  * Returns:
333  *      0 (always)
334  *
335  * Environment:
336  *      Nothing interesting.
337  *
338  * Side Effects:
339  *      As advertised.
340
341 Appears to need to be called with GLOCK held, as the icl_Event4 stuff asserts otherwise
342
343  *------------------------------------------------------------------------*/
344
345 static int ClearCallBack(register struct rx_connection *a_conn, register struct AFSFid *a_fid)
346 {
347     register struct vcache *tvc;
348     register int i;
349     struct VenusFid localFid;
350     struct volume * tv;
351
352     AFS_STATCNT(ClearCallBack);
353
354     AFS_ASSERT_GLOCK();
355
356     /*
357      * XXXX Don't hold any server locks here because of callback protocol XXX
358      */
359     localFid.Cell = 0;
360     localFid.Fid.Volume = a_fid->Volume;
361     localFid.Fid.Vnode = a_fid->Vnode;
362     localFid.Fid.Unique = a_fid->Unique;
363
364     /*
365       * Volume ID of zero means don't do anything.
366       */
367     if (a_fid->Volume != 0) {
368         if (a_fid->Vnode == 0) {
369             /*
370              * Clear callback for the whole volume.  Zip through the
371              * hash chain, nullifying entries whose volume ID matches.
372              */
373             for (i = 0; i < VCSIZE; i++)
374                 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
375                     if (tvc->fid.Fid.Volume == a_fid->Volume) {
376                         tvc->callback = NULL;
377                         tvc->quick.stamp = 0; 
378                         if (!localFid.Cell)
379                             localFid.Cell = tvc->fid.Cell;
380                         tvc->h1.dchint = NULL; /* invalidate hints */
381                         ObtainWriteLock(&afs_xcbhash, 449);
382                         afs_DequeueCallback(tvc);
383                         tvc->states &= ~(CStatd | CUnique | CBulkFetching);
384                         afs_allCBs++;
385                         if (tvc->fid.Fid.Vnode & 1)
386                           afs_oddCBs++; 
387                         else
388                           afs_evenCBs++; 
389                         ReleaseWriteLock(&afs_xcbhash);
390                         if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
391                             osi_dnlc_purgedp(tvc);
392                         afs_Trace3(afs_iclSetp, CM_TRACE_CALLBACK,
393                                    ICL_TYPE_POINTER, tvc, 
394                                    ICL_TYPE_INT32, tvc->states,
395                                    ICL_TYPE_INT32, a_fid->Volume);
396                     } else if ((tvc->states & CMValid) && (tvc->mvid->Fid.Volume == a_fid->Volume)) {
397                         tvc->states &= ~CMValid;
398                         if (!localFid.Cell)
399                             localFid.Cell = tvc->mvid->Cell;
400                     }
401                 }
402
403             /*
404              * XXXX Don't hold any locks here XXXX
405              */
406             tv = afs_FindVolume(&localFid, 0);
407             if (tv) {
408               afs_ResetVolumeInfo(tv);
409               afs_PutVolume(tv, 0);
410               /* invalidate mtpoint? */
411             }
412         } /*Clear callbacks for whole volume*/
413         else {
414             /*
415              * Clear callbacks just for the one file.
416              */
417             afs_allCBs++;
418             if (a_fid->Vnode & 1)
419                 afs_oddCBs++;   /*Could do this on volume basis, too*/
420             else
421                 afs_evenCBs++; /*A particular fid was specified*/
422             i = VCHash(&localFid);
423             for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
424                 if (tvc->fid.Fid.Vnode == a_fid->Vnode
425                     && tvc->fid.Fid.Volume == a_fid->Volume
426                     && tvc->fid.Fid.Unique == a_fid->Unique ) {
427                     tvc->callback = NULL;
428                     tvc->quick.stamp = 0; 
429                     tvc->h1.dchint = NULL; /* invalidate hints */
430                     ObtainWriteLock(&afs_xcbhash, 450);
431                     afs_DequeueCallback(tvc);
432                     tvc->states &= ~(CStatd | CUnique | CBulkFetching);
433                     ReleaseWriteLock(&afs_xcbhash);
434                     if (a_fid->Vnode & 1 || (vType(tvc) == VDIR))
435                         osi_dnlc_purgedp(tvc);
436                     afs_Trace3(afs_iclSetp, CM_TRACE_CALLBACK,
437                                ICL_TYPE_POINTER, tvc, 
438                                ICL_TYPE_INT32, tvc->states, ICL_TYPE_LONG, 0);
439 #ifdef CBDEBUG
440                     lastCallBack_vnode = afid->Vnode;
441                     lastCallBack_dv = tvc->mstat.DataVersion.low;
442                     osi_GetuTime(&lastCallBack_time);
443 #endif /* CBDEBUG */
444                 }
445             } /*Walk through hash table*/
446         } /*Clear callbacks for one file*/
447     } /*Fid has non-zero volume ID*/
448
449     /*
450      * Always return a predictable value.
451      */
452     return(0);
453
454 } /*ClearCallBack*/
455
456
457 /*------------------------------------------------------------------------
458  * EXPORTED SRXAFSCB_CallBack
459  *
460  * Description:
461  *      Routine called by the server-side callback RPC interface to
462  *      implement passing in callback information.
463  *      table.
464  *
465  * Arguments:
466  *      a_call      : Ptr to Rx call on which this request came in.
467  *      a_fids      : Ptr to array of fids involved.
468  *      a_callbacks : Ptr to matching callback info for the fids.
469  *
470  * Returns:
471  *      0 (always).
472  *
473  * Environment:
474  *      Nothing interesting.
475  *
476  * Side Effects:
477  *      As advertised.
478  *------------------------------------------------------------------------*/
479
480 int SRXAFSCB_CallBack(struct rx_call *a_call, register struct AFSCBFids *a_fids, struct AFSCBs *a_callbacks)
481 {
482     register int i;                         /*Loop variable*/
483     struct AFSFid *tfid;                    /*Ptr to current fid*/
484     register struct rx_connection *tconn;   /*Call's connection*/
485     int code=0;
486     XSTATS_DECLS;
487
488     RX_AFS_GLOCK();
489
490     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_CALLBACK);
491
492     AFS_STATCNT(SRXAFSCB_CallBack);
493     if (!(tconn = rx_ConnectionOf(a_call))) return(0);
494     tfid = (struct AFSFid *) a_fids->AFSCBFids_val;
495     
496     /*
497      * For now, we ignore callbacks, since the File Server only *breaks*
498      * callbacks at present.
499      */
500     for (i = 0; i < a_fids->AFSCBFids_len; i++) 
501         ClearCallBack(tconn, &tfid[i]);
502
503     XSTATS_END_TIME;
504
505     RX_AFS_GUNLOCK();
506     
507     return(0);
508
509 } /*SRXAFSCB_CallBack*/
510
511
512 /*------------------------------------------------------------------------
513  * EXPORTED SRXAFSCB_Probe
514  *
515  * Description:
516  *      Routine called by the server-side callback RPC interface to
517  *      implement ``probing'' the Cache Manager, just making sure it's
518  *      still there.
519  *
520  * Arguments:
521  *      a_call : Ptr to Rx call on which this request came in.
522  *
523  * Returns:
524  *      0 (always).
525  *
526  * Environment:
527  *      Nothing interesting.
528  *
529  * Side Effects:
530  *      As advertised.
531  *------------------------------------------------------------------------*/
532
533 int SRXAFSCB_Probe(struct rx_call *a_call)
534 {
535     int code = 0;
536     XSTATS_DECLS;
537
538     RX_AFS_GLOCK();
539     AFS_STATCNT(SRXAFSCB_Probe);
540
541     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_PROBE);
542     XSTATS_END_TIME;
543
544     RX_AFS_GUNLOCK();
545
546     return(0);
547
548 } /*SRXAFSCB_Probe*/
549
550
551 /*------------------------------------------------------------------------
552  * EXPORTED SRXAFSCB_InitCallBackState
553  *
554  * Description:
555  *      Routine called by the server-side callback RPC interface to
556  *      implement clearing all callbacks from this host.
557  *
558  * Arguments:
559  *      a_call : Ptr to Rx call on which this request came in.
560  *
561  * Returns:
562  *      0 (always).
563  *
564  * Environment:
565  *      Nothing interesting.
566  *
567  * Side Effects:
568  *      As advertised.
569  *------------------------------------------------------------------------*/
570
571 int SRXAFSCB_InitCallBackState(struct rx_call *a_call)
572 {
573     register int i;
574     register struct vcache *tvc;
575     register struct rx_connection *tconn;
576     register struct rx_peer *peer;
577     struct server *ts;
578     int code = 0;
579     XSTATS_DECLS;
580
581     RX_AFS_GLOCK();
582
583     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_INITCALLBACKSTATE);
584     AFS_STATCNT(SRXAFSCB_InitCallBackState);
585
586     /*
587      * Find the address of the host making this call
588      */
589     if ((tconn = rx_ConnectionOf(a_call)) && (peer = rx_PeerOf(tconn))) {
590
591         afs_allCBs++;
592         afs_oddCBs++;   /*Including any missed via create race*/
593         afs_evenCBs++;  /*Including any missed via create race*/
594
595         ts = afs_FindServer(rx_HostOf(peer), rx_PortOf(peer), (afsUUID *)0, 0);
596         if (ts) {
597             for (i = 0; i < VCSIZE; i++)
598                 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
599                     if (tvc->callback == ts) {
600                         ObtainWriteLock(&afs_xcbhash, 451);
601                         afs_DequeueCallback(tvc);
602                         tvc->callback = NULL;
603                         tvc->states &= ~(CStatd | CUnique | CBulkFetching);
604                         ReleaseWriteLock(&afs_xcbhash);
605                     }
606                 }
607         }
608
609       
610  
611         /* find any volumes residing on this server and flush their state */
612         {
613             register struct volume *tv;
614             register int j;
615         
616             for (i=0;i<NVOLS;i++) 
617                 for (tv = afs_volumes[i]; tv; tv=tv->next) {
618                     for (j=0; j<MAXHOSTS; j++)
619                         if (tv->serverHost[j] == ts)
620                             afs_ResetVolumeInfo(tv);
621                 }
622         }
623         osi_dnlc_purge(); /* may be a little bit extreme */
624     }
625
626     XSTATS_END_TIME;
627
628     RX_AFS_GUNLOCK();
629
630     return(0);
631
632 } /*SRXAFSCB_InitCallBackState*/
633
634
635 /*------------------------------------------------------------------------
636  * EXPORTED SRXAFSCB_XStatsVersion
637  *
638  * Description:
639  *      Routine called by the server-side callback RPC interface to
640  *      implement pulling out the xstat version number for the Cache
641  *      Manager.
642  *
643  * Arguments:
644  *      a_versionP : Ptr to the version number variable to set.
645  *
646  * Returns:
647  *      0 (always)
648  *
649  * Environment:
650  *      Nothing interesting.
651  *
652  * Side Effects:
653  *      As advertised.
654  *------------------------------------------------------------------------*/
655
656 int SRXAFSCB_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP)
657 {
658    int code=0;
659
660     XSTATS_DECLS;
661
662     RX_AFS_GLOCK();
663     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_XSTATSVERSION);
664
665     *a_versionP = AFSCB_XSTAT_VERSION;
666
667     XSTATS_END_TIME;
668
669     RX_AFS_GUNLOCK();
670
671     return(0);
672 }  /*SRXAFSCB_XStatsVersion*/
673
674
675 /*------------------------------------------------------------------------
676  * EXPORTED SRXAFSCB_GetXStats
677  *
678  * Description:
679  *      Routine called by the server-side callback RPC interface to
680  *      implement getting the given data collection from the extended
681  *      Cache Manager statistics.
682  *
683  * Arguments:
684  *      a_call              : Ptr to Rx call on which this request came in.
685  *      a_clientVersionNum  : Client version number.
686  *      a_opCode            : Desired operation.
687  *      a_serverVersionNumP : Ptr to version number to set.
688  *      a_timeP             : Ptr to time value (seconds) to set.
689  *      a_dataArray         : Ptr to variable array structure to return
690  *                            stuff in.
691  *
692  * Returns:
693  *      0 (always).
694  *
695  * Environment:
696  *      Nothing interesting.
697  *
698  * Side Effects:
699  *      As advertised.
700  *------------------------------------------------------------------------*/
701
702 int SRXAFSCB_GetXStats(struct rx_call *a_call, afs_int32 a_clientVersionNum, 
703         afs_int32 a_collectionNumber, afs_int32 *a_srvVersionNumP, 
704         afs_int32 *a_timeP, AFSCB_CollData *a_dataP)
705 {
706     register int code;          /*Return value*/
707     afs_int32 *dataBuffP;               /*Ptr to data to be returned*/
708     afs_int32 dataBytes;                /*Bytes in data buffer*/
709     XSTATS_DECLS;
710
711     RX_AFS_GLOCK();
712
713     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_GETXSTATS);
714
715     /*
716      * Record the time of day and the server version number.
717      */
718     *a_srvVersionNumP = AFSCB_XSTAT_VERSION;
719     *a_timeP = osi_Time();
720
721     /*
722      * Stuff the appropriate data in there (assume victory)
723      */
724     code = 0;
725
726 #ifdef AFS_NOSTATS
727     /*
728      * We're not keeping stats, so just return successfully with
729      * no data.
730      */
731     a_dataP->AFSCB_CollData_len = 0;
732     a_dataP->AFSCB_CollData_val = NULL;
733 #else
734     switch(a_collectionNumber) {
735       case AFSCB_XSTATSCOLL_CALL_INFO:
736         /*
737          * Pass back all the call-count-related data.
738          *
739          * >>> We are forced to allocate a separate area in which to
740          * >>> put this stuff in by the RPC stub generator, since it
741          * >>> will be freed at the tail end of the server stub code.
742          */
743         dataBytes = sizeof(struct afs_CMStats);
744         dataBuffP = (afs_int32 *)afs_osi_Alloc(dataBytes);
745         memcpy((char *)dataBuffP, (char *)&afs_cmstats, dataBytes);
746         a_dataP->AFSCB_CollData_len = dataBytes>>2;
747         a_dataP->AFSCB_CollData_val = dataBuffP;
748         break;
749
750       case AFSCB_XSTATSCOLL_PERF_INFO:
751         /*
752          * Update and then pass back all the performance-related data.
753          * Note: the only performance fields that need to be computed
754          * at this time are the number of accesses for this collection
755          * and the current server record info.
756          *
757          * >>> We are forced to allocate a separate area in which to
758          * >>> put this stuff in by the RPC stub generator, since it
759          * >>> will be freed at the tail end of the server stub code.
760          */
761         afs_stats_cmperf.numPerfCalls++;
762         afs_CountServers();
763         dataBytes = sizeof(afs_stats_cmperf);
764         dataBuffP = (afs_int32 *)afs_osi_Alloc(dataBytes);
765         memcpy((char *)dataBuffP, (char *)&afs_stats_cmperf, dataBytes);
766         a_dataP->AFSCB_CollData_len = dataBytes>>2;
767         a_dataP->AFSCB_CollData_val = dataBuffP;
768         break;
769
770       case AFSCB_XSTATSCOLL_FULL_PERF_INFO:
771         /*
772          * Pass back the full range of performance and statistical
773          * data available.  We have to bring the normal performance
774          * data collection up to date, then copy that data into
775          * the full collection.
776          *
777          * >>> We are forced to allocate a separate area in which to
778          * >>> put this stuff in by the RPC stub generator, since it
779          * >>> will be freed at the tail end of the server stub code.
780          */
781         afs_stats_cmperf.numPerfCalls++;
782         afs_CountServers();
783         memcpy((char *)(&(afs_stats_cmfullperf.perf)), (char *)(&afs_stats_cmperf), sizeof(struct afs_stats_CMPerf));
784         afs_stats_cmfullperf.numFullPerfCalls++;
785
786         dataBytes = sizeof(afs_stats_cmfullperf);
787         dataBuffP = (afs_int32 *)afs_osi_Alloc(dataBytes);
788         memcpy((char *)dataBuffP, (char *)(&afs_stats_cmfullperf), dataBytes);
789         a_dataP->AFSCB_CollData_len = dataBytes>>2;
790         a_dataP->AFSCB_CollData_val = dataBuffP;
791         break;
792
793       default:
794         /*
795          * Illegal collection number.
796          */
797         a_dataP->AFSCB_CollData_len = 0;
798         a_dataP->AFSCB_CollData_val = NULL;
799         code = 1;
800     } /*Switch on collection number*/
801 #endif /* AFS_NOSTATS */
802
803     XSTATS_END_TIME;
804
805     RX_AFS_GUNLOCK();
806
807     return(code);
808
809 } /*SRXAFSCB_GetXStats*/
810
811
812 /*------------------------------------------------------------------------
813  * EXPORTED afs_RXCallBackServer
814  *
815  * Description:
816  *      Body of the thread supporting callback services.
817  *
818  * Arguments:
819  *      None.
820  *
821  * Returns:
822  *      0 (always).
823  *
824  * Environment:
825  *      Nothing interesting.
826  *
827  * Side Effects:
828  *      As advertised.
829  *------------------------------------------------------------------------*/
830
831 int afs_RXCallBackServer(void)
832 {
833     AFS_STATCNT(afs_RXCallBackServer);
834
835     while (1) {
836         if (afs_server)
837             break;
838         afs_osi_Sleep(&afs_server);
839     }
840
841     /*
842      * Donate this process to Rx.
843      */
844     rx_ServerProc();
845     return(0);
846
847 } /*afs_RXCallBackServer*/
848
849
850 /*------------------------------------------------------------------------
851  * EXPORTED shutdown_CB
852  *
853  * Description:
854  *      Zero out important Cache Manager data structures.
855  *
856  * Arguments:
857  *      None.
858  *
859  * Returns:
860  *      0 (always).
861  *
862  * Environment:
863  *      Nothing interesting.
864  *
865  * Side Effects:
866  *      As advertised.
867  *------------------------------------------------------------------------*/
868
869 int shutdown_CB(void) 
870 {
871   AFS_STATCNT(shutdown_CB);
872
873   if (afs_cold_shutdown) {
874     afs_oddCBs = afs_evenCBs = afs_allCBs = afs_allZaps = afs_oddZaps = afs_evenZaps =
875         afs_connectBacks = 0;
876   }
877
878   return(0);
879
880 } /*shutdown_CB*/
881
882 /*------------------------------------------------------------------------
883  * EXPORTED SRXAFSCB_InitCallBackState2
884  *
885  * Description:
886  *      This routine was used in the AFS 3.5 beta release, but not anymore.
887  *      It has since been replaced by SRXAFSCB_InitCallBackState3.
888  *
889  * Arguments:
890  *      a_call : Ptr to Rx call on which this request came in.
891  *
892  * Returns:
893  *      RXGEN_OPCODE (always). 
894  *
895  * Environment:
896  *      Nothing interesting.
897  *
898  * Side Effects:
899  *      None
900  *------------------------------------------------------------------------*/
901
902 int SRXAFSCB_InitCallBackState2(struct rx_call *a_call, struct interfaceAddr *addr)
903 {
904         return RXGEN_OPCODE;
905 }
906
907 /*------------------------------------------------------------------------
908  * EXPORTED SRXAFSCB_WhoAreYou
909  *
910  * Description:
911  *      Routine called by the server-side callback RPC interface to
912  *      obtain a unique identifier for the client. The server uses
913  *      this identifier to figure out whether or not two RX connections
914  *      are from the same client, and to find out which addresses go
915  *      with which clients.
916  *
917  * Arguments:
918  *      a_call : Ptr to Rx call on which this request came in.
919  *      addr: Ptr to return the list of interfaces for this client.
920  *
921  * Returns:
922  *      0 (Always)
923  *
924  * Environment:
925  *      Nothing interesting.
926  *
927  * Side Effects:
928  *      As advertised.
929  *------------------------------------------------------------------------*/
930
931 int SRXAFSCB_WhoAreYou(struct rx_call *a_call, struct interfaceAddr *addr)
932 {
933     int i;
934     int code = 0;
935
936     RX_AFS_GLOCK();
937
938     AFS_STATCNT(SRXAFSCB_WhoAreYou);
939
940     ObtainReadLock(&afs_xinterface);
941
942     /* return all network interface addresses */
943     addr->numberOfInterfaces = afs_cb_interface.numberOfInterfaces;
944     addr->uuid = afs_cb_interface.uuid;
945     for ( i=0; i < afs_cb_interface.numberOfInterfaces; i++) {
946         addr->addr_in[i] = ntohl(afs_cb_interface.addr_in[i]);
947         addr->subnetmask[i] = ntohl(afs_cb_interface.subnetmask[i]);
948         addr->mtu[i] = ntohl(afs_cb_interface.mtu[i]);
949     }
950
951     ReleaseReadLock(&afs_xinterface);
952
953     RX_AFS_GUNLOCK();
954
955     return code;
956 }
957
958
959 /*------------------------------------------------------------------------
960  * EXPORTED SRXAFSCB_InitCallBackState3
961  *
962  * Description:
963  *      Routine called by the server-side callback RPC interface to
964  *      implement clearing all callbacks from this host.
965  *
966  * Arguments:
967  *      a_call : Ptr to Rx call on which this request came in.
968  *
969  * Returns:
970  *      0 (always).
971  *
972  * Environment:
973  *      Nothing interesting.
974  *
975  * Side Effects:
976  *      As advertised.
977  *------------------------------------------------------------------------*/
978
979 int SRXAFSCB_InitCallBackState3(struct rx_call *a_call, afsUUID *a_uuid)
980 {
981     int code;
982
983     /*
984      * TBD: Lookup the server by the UUID instead of its IP address.
985      */
986     code = SRXAFSCB_InitCallBackState(a_call);
987
988     return code;
989 }
990  
991
992 /*------------------------------------------------------------------------
993  * EXPORTED SRXAFSCB_ProbeUuid
994  *
995  * Description:
996  *      Routine called by the server-side callback RPC interface to
997  *      implement ``probing'' the Cache Manager, just making sure it's
998  *      still there is still the same client it used to be.
999  *
1000  * Arguments:
1001  *      a_call : Ptr to Rx call on which this request came in.
1002  *      a_uuid : Ptr to UUID that must match the client's UUID.
1003  *
1004  * Returns:
1005  *      0 if a_uuid matches the UUID for this client
1006  *      Non-zero otherwize
1007  *
1008  * Environment:
1009  *      Nothing interesting.
1010  *
1011  * Side Effects:
1012  *      As advertised.
1013  *------------------------------------------------------------------------*/
1014
1015 int SRXAFSCB_ProbeUuid(struct rx_call *a_call, afsUUID *a_uuid)
1016 {
1017     int code = 0;
1018     XSTATS_DECLS;
1019
1020     RX_AFS_GLOCK();
1021     AFS_STATCNT(SRXAFSCB_Probe);
1022
1023     XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_PROBE);
1024     if (!afs_uuid_equal(a_uuid, &afs_cb_interface.uuid))
1025         code = 1; /* failure */
1026     XSTATS_END_TIME;
1027
1028     RX_AFS_GUNLOCK();
1029
1030     return code;
1031 }
1032  
1033
1034 /*------------------------------------------------------------------------
1035  * EXPORTED SRXAFSCB_GetServerPrefs
1036  *
1037  * Description:
1038  *      Routine to list server preferences used by this client.
1039  *
1040  * Arguments:
1041  *      a_call  : Ptr to Rx call on which this request came in.
1042  *      a_index : Input server index
1043  *      a_srvr_addr  : Output server address in host byte order
1044  *                     (0xffffffff on last server)
1045  *      a_srvr_rank  : Output server rank
1046  *
1047  * Returns:
1048  *      0 on success
1049  *
1050  * Environment:
1051  *      Nothing interesting.
1052  *
1053  * Side Effects:
1054  *      As advertised.
1055  *------------------------------------------------------------------------*/
1056
1057 int SRXAFSCB_GetServerPrefs(struct rx_call *a_call, afs_int32 a_index,
1058         afs_int32 *a_srvr_addr, afs_int32 *a_srvr_rank)
1059 {
1060     int i, j;
1061     struct srvAddr *sa;
1062
1063     RX_AFS_GLOCK();
1064     AFS_STATCNT(SRXAFSCB_GetServerPrefs);
1065
1066     ObtainReadLock(&afs_xserver);
1067
1068     /* Search the hash table for the server with this index */
1069     *a_srvr_addr = 0xffffffff;
1070     *a_srvr_rank = 0xffffffff;
1071     for (i=0, j=0; j < NSERVERS && i <= a_index; j++) {
1072         for (sa = afs_srvAddrs[j]; sa && i <= a_index; sa = sa->next_bkt, i++) {
1073             if (i == a_index) {
1074                 *a_srvr_addr = ntohl(sa->sa_ip);
1075                 *a_srvr_rank = sa->sa_iprank;
1076             }
1077         }
1078     }
1079
1080     ReleaseReadLock(&afs_xserver);
1081
1082     RX_AFS_GUNLOCK();
1083
1084     return 0;
1085 }
1086  
1087
1088 /*------------------------------------------------------------------------
1089  * EXPORTED SRXAFSCB_GetCellServDB
1090  *
1091  * Description:
1092  *      Routine to list cells configured for this client
1093  *
1094  * Arguments:
1095  *      a_call  : Ptr to Rx call on which this request came in.
1096  *      a_index : Input cell index
1097  *      a_name  : Output cell name ("" on last cell)
1098  *      a_hosts : Output cell database servers in host byte order.
1099  *
1100  * Returns:
1101  *      0 on success
1102  *
1103  * Environment:
1104  *      Nothing interesting.
1105  *
1106  * Side Effects:
1107  *      As advertised.
1108  *------------------------------------------------------------------------*/
1109
1110 int SRXAFSCB_GetCellServDB(struct rx_call *a_call, afs_int32 a_index,
1111     char **a_name, serverList *a_hosts)
1112 {
1113     afs_int32 i, j = 0;
1114     struct cell *tcell;
1115     char *t_name, *p_name = NULL;
1116
1117     RX_AFS_GLOCK();
1118     AFS_STATCNT(SRXAFSCB_GetCellServDB);
1119
1120     tcell = afs_GetCellByIndex(a_index, READ_LOCK);
1121
1122     if (!tcell) {
1123         i = 0;
1124         a_hosts->serverList_val = 0;
1125         a_hosts->serverList_len = 0;
1126     } else {
1127         p_name = tcell->cellName;
1128         for (j = 0 ; j < AFSMAXCELLHOSTS && tcell->cellHosts[j] ; j++) 
1129           ;
1130         i = strlen(p_name);
1131         a_hosts->serverList_val = (afs_int32 *)afs_osi_Alloc(j*sizeof(afs_int32));
1132         a_hosts->serverList_len = j;
1133         for (j = 0 ; j < AFSMAXCELLHOSTS && tcell->cellHosts[j] ; j++) 
1134             a_hosts->serverList_val[j] = ntohl(tcell->cellHosts[j]->addr->sa_ip);
1135         afs_PutCell(tcell, READ_LOCK);
1136     }
1137
1138     t_name = (char *)afs_osi_Alloc(i+1);
1139     if (t_name == NULL) {
1140         afs_osi_Free(a_hosts->serverList_val, (j*sizeof(afs_int32)));
1141         RX_AFS_GUNLOCK();
1142         return ENOMEM;
1143     }
1144
1145     t_name[i] = '\0';
1146     if (p_name)
1147         memcpy(t_name, p_name, i);
1148
1149     RX_AFS_GUNLOCK();
1150
1151     *a_name = t_name;
1152     return 0;
1153 }
1154  
1155
1156 /*------------------------------------------------------------------------
1157  * EXPORTED SRXAFSCB_GetLocalCell
1158  *
1159  * Description:
1160  *      Routine to return name of client's local cell
1161  *
1162  * Arguments:
1163  *      a_call  : Ptr to Rx call on which this request came in.
1164  *      a_name  : Output cell name
1165  *
1166  * Returns:
1167  *      0 on success
1168  *
1169  * Environment:
1170  *      Nothing interesting.
1171  *
1172  * Side Effects:
1173  *      As advertised.
1174  *------------------------------------------------------------------------*/
1175
1176 int SRXAFSCB_GetLocalCell(struct rx_call *a_call, char **a_name)
1177 {
1178     int plen;
1179     struct cell *tcell;
1180     char *t_name, *p_name = NULL;
1181
1182     RX_AFS_GLOCK();
1183     AFS_STATCNT(SRXAFSCB_GetLocalCell);
1184
1185     /* Search the list for the primary cell. Cell number 1 is only
1186      * the primary cell is when no other cell is explicitly marked as
1187      * the primary cell.  */
1188     tcell = afs_GetPrimaryCell(READ_LOCK);
1189     if (tcell)
1190         p_name = tcell->cellName;
1191     if (p_name)
1192         plen = strlen(p_name);
1193     else
1194         plen = 0;
1195     t_name = (char *)afs_osi_Alloc(plen+1);
1196     if (t_name == NULL) {
1197         if (tcell) afs_PutCell(tcell, READ_LOCK);
1198         RX_AFS_GUNLOCK();
1199         return ENOMEM;
1200     }
1201
1202     t_name[plen] = '\0';
1203     if (p_name)
1204         memcpy(t_name, p_name, plen);
1205
1206     RX_AFS_GUNLOCK();
1207
1208     *a_name = t_name;
1209     if (tcell) afs_PutCell(tcell, READ_LOCK);
1210     return 0;
1211 }
1212
1213
1214 /*
1215  * afs_MarshallCacheConfig - marshall client cache configuration
1216  *
1217  * PARAMETERS
1218  *
1219  * IN callerVersion - the rpc stat version of the caller.
1220  *
1221  * IN config - client cache configuration.
1222  *
1223  * OUT ptr - buffer where configuration is marshalled.
1224  *
1225  * RETURN CODES
1226  *
1227  * Returns void.
1228  */
1229 static void afs_MarshallCacheConfig(afs_uint32 callerVersion,
1230         cm_initparams_v1 *config, afs_uint32 *ptr)
1231 {
1232     AFS_STATCNT(afs_MarshallCacheConfig);
1233     /*
1234      * We currently only support version 1.
1235      */
1236     *(ptr++) = config->nChunkFiles;
1237     *(ptr++) = config->nStatCaches;
1238     *(ptr++) = config->nDataCaches;
1239     *(ptr++) = config->nVolumeCaches;
1240     *(ptr++) = config->firstChunkSize;
1241     *(ptr++) = config->otherChunkSize;
1242     *(ptr++) = config->cacheSize;
1243     *(ptr++) = config->setTime;
1244     *(ptr++) = config->memCache;
1245 }
1246  
1247
1248 /*------------------------------------------------------------------------
1249  * EXPORTED SRXAFSCB_GetCacheConfig
1250  *
1251  * Description:
1252  *      Routine to return parameters used to initialize client cache.
1253  *      Client may request any format version. Server may not return
1254  *      format version greater than version requested by client.
1255  *
1256  * Arguments:
1257  *      a_call:        Ptr to Rx call on which this request came in.
1258  *      callerVersion: Data format version desired by the client.
1259  *      serverVersion: Data format version of output data.
1260  *      configCount:   Number bytes allocated for output data.
1261  *      config:        Client cache configuration.
1262  *
1263  * Returns:
1264  *      0 on success
1265  *
1266  * Environment:
1267  *      Nothing interesting.
1268  *
1269  * Side Effects:
1270  *      As advertised.
1271  *------------------------------------------------------------------------*/
1272
1273 int SRXAFSCB_GetCacheConfig(struct rx_call *a_call, afs_uint32 callerVersion,
1274         afs_uint32 *serverVersion, afs_uint32 *configCount, cacheConfig *config)
1275 {
1276     afs_uint32 *t_config;
1277     size_t allocsize;
1278     cm_initparams_v1 cm_config;
1279
1280     RX_AFS_GLOCK();
1281     AFS_STATCNT(SRXAFSCB_GetCacheConfig);
1282
1283     /*
1284      * Currently only support version 1
1285      */
1286     allocsize = sizeof(cm_initparams_v1);
1287     t_config = (afs_uint32 *)afs_osi_Alloc(allocsize);
1288     if (t_config == NULL) {
1289         RX_AFS_GUNLOCK();
1290         return ENOMEM;
1291     }
1292
1293     cm_config.nChunkFiles = cm_initParams.cmi_nChunkFiles;
1294     cm_config.nStatCaches = cm_initParams.cmi_nStatCaches;
1295     cm_config.nDataCaches = cm_initParams.cmi_nDataCaches;
1296     cm_config.nVolumeCaches = cm_initParams.cmi_nVolumeCaches;
1297     cm_config.firstChunkSize = cm_initParams.cmi_firstChunkSize;
1298     cm_config.otherChunkSize = cm_initParams.cmi_otherChunkSize;
1299     cm_config.cacheSize = cm_initParams.cmi_cacheSize;
1300     cm_config.setTime = cm_initParams.cmi_setTime;
1301     cm_config.memCache = cm_initParams.cmi_memCache;
1302
1303     afs_MarshallCacheConfig(callerVersion, &cm_config, t_config);
1304
1305     *serverVersion = AFS_CLIENT_RETRIEVAL_FIRST_EDITION;
1306     *configCount = allocsize;
1307     config->cacheConfig_val = t_config;
1308     config->cacheConfig_len = allocsize/sizeof(afs_uint32);
1309
1310     RX_AFS_GUNLOCK();
1311
1312     return 0;
1313 }
1314
1315 /*------------------------------------------------------------------------
1316  * EXPORTED SRXAFSCB_FetchData
1317  *
1318  * Description:
1319  *      Routine to do third party move from a remioserver to the original
1320  *      issuer of an ArchiveData request. Presently supported only by the
1321  *      "fs" command, not by the AFS client.
1322  *
1323  * Arguments:
1324  *      rxcall:        Ptr to Rx call on which this request came in.
1325  *      Fid:           pointer to AFSFid structure.
1326  *      Fd:            File descriptor inside fs command.
1327  *      Position:      Offset in the file.
1328  *      Length:        Data length to transfer.
1329  *      TotalLength:   Pointer to total file length field
1330  *
1331  * Returns:
1332  *      0 on success
1333  *
1334  * Environment:
1335  *      Nothing interesting.
1336  *
1337  * Side Effects:
1338  *------------------------------------------------------------------------*/
1339 int SRXAFSCB_FetchData(struct rx_call *rxcall, struct AFSFid *Fid, afs_int32 Fd, 
1340         afs_int64 Position, afs_int64 Length, afs_int64 *TotalLength)
1341 {
1342     return ENOSYS;
1343 }
1344
1345 /*------------------------------------------------------------------------
1346  * EXPORTED SRXAFSCB_StoreData
1347  *
1348  * Description:
1349  *      Routine to do third party move from a remioserver to the original
1350  *      issuer of a RetrieveData request. Presently supported only by the
1351  *      "fs" command, not by the AFS client.
1352  *
1353  * Arguments:
1354  *      rxcall:        Ptr to Rx call on which this request came in.
1355  *      Fid:           pointer to AFSFid structure.
1356  *      Fd:            File descriptor inside fs command.
1357  *      Position:      Offset in the file.
1358  *      Length:        Data length to transfer.
1359  *      TotalLength:   Pointer to total file length field
1360  *
1361  * Returns:
1362  *      0 on success
1363  *
1364  * Environment:
1365  *      Nothing interesting.
1366  *
1367  * Side Effects:
1368  *      As advertised.
1369  *------------------------------------------------------------------------*/
1370 int SRXAFSCB_StoreData(struct rx_call *rxcall, struct AFSFid *Fid, afs_int32 Fd, 
1371         afs_int64 Position, afs_int64 Length, afs_int64 *TotalLength)
1372 {
1373     return ENOSYS;
1374 }
1375
1376 /*------------------------------------------------------------------------
1377  * EXPORTED SRXAFSCB_GetCellByNum
1378  *
1379  * Description:
1380  *      Routine to get information about a cell specified by its
1381  *      cell number (returned by GetCE/GetCE64).
1382  *
1383  * Arguments:
1384  *      a_call    : Ptr to Rx call on which this request came in.
1385  *      a_cellnum : Input cell number
1386  *      a_name    : Output cell name (one zero byte when no such cell).
1387  *      a_hosts   : Output cell database servers in host byte order.
1388  *
1389  * Returns:
1390  *      0 on success
1391  *
1392  * Environment:
1393  *      Nothing interesting.
1394  *
1395  * Side Effects:
1396  *      As advertised.
1397  *------------------------------------------------------------------------*/
1398
1399 int SRXAFSCB_GetCellByNum(struct rx_call *a_call, afs_int32 a_cellnum,
1400     char **a_name, serverList *a_hosts)
1401 {
1402     afs_int32 i, sn;
1403     struct cell *tcell;
1404
1405     RX_AFS_GLOCK();
1406     AFS_STATCNT(SRXAFSCB_GetCellByNum);
1407
1408     a_hosts->serverList_val = 0;
1409     a_hosts->serverList_len = 0;
1410
1411     tcell = afs_GetCellStale(a_cellnum, READ_LOCK);
1412     if (!tcell) {
1413         *a_name = afs_strdup("");
1414         RX_AFS_GUNLOCK();
1415         return 0;
1416     }
1417
1418     ObtainReadLock(&tcell->lock);
1419     *a_name = afs_strdup(tcell->cellName);
1420
1421     for (sn = 0; sn < AFSMAXCELLHOSTS && tcell->cellHosts[sn]; sn++) 
1422         ;
1423     a_hosts->serverList_len = sn;
1424     a_hosts->serverList_val = (afs_int32 *) afs_osi_Alloc(sn*sizeof(afs_int32));
1425
1426     for (i = 0; i < sn; i++)
1427         a_hosts->serverList_val[i] = ntohl(tcell->cellHosts[i]->addr->sa_ip);
1428     ReleaseReadLock(&tcell->lock);
1429     afs_PutCell(tcell, READ_LOCK);
1430
1431     RX_AFS_GUNLOCK();
1432     return 0;
1433 }
1434