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