e16ad0746600bdc29d5c249f0ea656c842088f65
[openafs.git] / src / xstat / xstat_fs.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  * Description:
12  *      Implementation of the client side of the AFS File Server extended
13  *      statistics facility.
14  *
15  *------------------------------------------------------------------------*/
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 RCSID
21     ("$Header$");
22
23 #include "xstat_fs.h"           /*Interface for this module */
24 #include <lwp.h>                /*Lightweight process package */
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #endif
33
34 #define LWP_STACK_SIZE  (16 * 1024)
35
36 /*
37  * Routines we need that don't have explicit include file definitions.
38  */
39 extern int RXAFSCB_ExecuteRequest();    /*AFS callback dispatcher */
40 extern char *hostutil_GetNameByINet();  /*Host parsing utility */
41
42 /*
43  * Help out the linker by explicitly importing the callback routines
44  * File Servers may be lobbing at us.
45  */
46 extern afs_int32 SRXAFSCB_CallBack();
47 extern afs_int32 SRXAFSCB_InitCallBackState3();
48 extern afs_int32 SRXAFSCB_Probe();
49 extern afs_int32 SRXAFSCB_GetCE();
50 extern afs_int32 SRXAFSCB_GetLock();
51
52 /*
53  * Exported variables.
54  */
55 int xstat_fs_numServers;        /*Num connected servers */
56 struct xstat_fs_ConnectionInfo
57  *xstat_fs_ConnInfo;            /*Ptr to connection array */
58 int numCollections;             /*Number of data collections */
59 struct xstat_fs_ProbeResults xstat_fs_Results;  /*Latest probe results */
60 char terminationEvent;          /*One-shot termination event */
61
62 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS];    /*Buffer for collected data */
63
64 /*
65  * Private globals.
66  */
67 static int xstat_fs_ProbeFreqInSecs;    /*Probe freq. in seconds */
68 static int xstat_fs_initflag = 0;       /*Was init routine called? */
69 static int xstat_fs_debug = 0;  /*Debugging output enabled? */
70 static int xstat_fs_oneShot = 0;        /*One-shot operation? */
71 static int (*xstat_fs_Handler) ();      /*Probe handler routine */
72 static PROCESS probeLWP_ID;     /*Probe LWP process ID */
73 static int xstat_fs_numCollections;     /*Number of desired collections */
74 static afs_int32 *xstat_fs_collIDP;     /*Ptr to collection IDs desired */
75
76 /*
77  * We have to pass a port to Rx to start up our callback listener
78  * service, but 7001 is already taken up by the Cache Manager.  So,
79  * we make up our own.
80  */
81 #define XSTAT_FS_CBPORT 7101
82
83
84 /*------------------------------------------------------------------------
85  * [private] xstat_fs_CleanupInit
86  *
87  * Description:
88  *      Set up for recovery after an error in initialization (i.e.,
89  *      during a call to xstat_fs_Init.
90  *
91  * Arguments:
92  *      None.
93  *
94  * Returns:
95  *      0 on success,
96  *      Error value otherwise.
97  *
98  * Environment:
99  *      This routine is private to the module.
100  *
101  * Side Effects:
102  *      Zeros out basic data structures.
103  *------------------------------------------------------------------------*/
104
105 static int
106 xstat_fs_CleanupInit()
107 {
108     afs_int32 code;             /*Return code from callback stubs */
109     struct rx_call *rxcall;     /*Bogus param */
110     AFSCBFids *Fids_Array;      /*Bogus param */
111     AFSCBs *CallBack_Array;     /*Bogus param */
112
113     xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
114     xstat_fs_Results.probeNum = 0;
115     xstat_fs_Results.probeTime = 0;
116     xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
117     xstat_fs_Results.collectionNumber = 0;
118     xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
119     xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *) xstat_fsData;
120     xstat_fs_Results.probeOK = 0;
121
122     rxcall = (struct rx_call *)0;
123     Fids_Array = (AFSCBFids *) 0;
124     CallBack_Array = (AFSCBs *) 0;
125
126     /*
127      * Call each of the callback routines our module provides (in
128      * xstat_fs_callback.c) to make sure they're all there.
129      */
130     code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
131     if (code)
132         return (code);
133     code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
134     if (code)
135         return (code);
136     code = SRXAFSCB_Probe(rxcall);
137     return (code);
138 }
139
140
141 /*------------------------------------------------------------------------
142  * [exported] xstat_fs_Cleanup
143  *
144  * Description:
145  *      Clean up our memory and connection state.
146  *
147  * Arguments:
148  *      int a_releaseMem : Should we free up malloc'ed areas?
149  *
150  * Returns:
151  *      0 on total success,
152  *      -1 if the module was never initialized, or there was a problem
153  *              with the xstat_fs connection array.
154  *
155  * Environment:
156  *      xstat_fs_numServers should be properly set.  We don't do anything
157  *      unless xstat_fs_Init() has already been called.
158  *
159  * Side Effects:
160  *      Shuts down Rx connections gracefully, frees allocated space
161  *      (if so directed).
162  *------------------------------------------------------------------------*/
163
164 int
165 xstat_fs_Cleanup(int a_releaseMem)
166 {
167     static char rn[] = "xstat_fs_Cleanup";      /*Routine name */
168     int code;                   /*Return code */
169     int conn_idx;               /*Current connection index */
170     struct xstat_fs_ConnectionInfo *curr_conn;  /*Ptr to xstat_fs connection */
171
172     /*
173      * Assume the best, but check the worst.
174      */
175     if (!xstat_fs_initflag) {
176         fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
177         return (-1);
178     } else
179         code = 0;
180
181     /*
182      * Take care of all Rx connections first.  Check to see that the
183      * server count is a legal value.
184      */
185     if (xstat_fs_numServers <= 0) {
186         fprintf(stderr,
187                 "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
188                 rn, xstat_fs_numServers);
189         code = -1;
190     } else {
191         if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
192             /*
193              * The xstat_fs connection structure array exists.  Go through
194              * it and close up any Rx connections it holds.
195              */
196             curr_conn = xstat_fs_ConnInfo;
197             for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
198                 if (curr_conn->rxconn != (struct rx_connection *)0) {
199                     rx_DestroyConnection(curr_conn->rxconn);
200                     curr_conn->rxconn = (struct rx_connection *)0;
201                 }
202                 curr_conn++;
203             }                   /*for each xstat_fs connection */
204         }                       /*xstat_fs connection structure exists */
205     }                           /*Legal number of servers */
206
207     /*
208      * If asked to, release the space we've allocated.
209      */
210     if (a_releaseMem) {
211         if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0)
212             free(xstat_fs_ConnInfo);
213     }
214
215     /*
216      * Return the news, whatever it is.
217      */
218     return (code);
219 }
220
221
222 /*------------------------------------------------------------------------
223  * [private] xstat_fs_LWP
224  *
225  * Description:
226  *      This LWP iterates over the server connections and gathers up
227  *      the desired statistics from each one on a regular basis.  When
228  *      the sweep is done, the associated handler function is called
229  *      to process the new data.
230  *
231  * Arguments:
232  *      None.
233  *
234  * Returns:
235  *      Nothing.
236  *
237  * Environment:
238  *      Started by xstat_fs_Init(), uses global structures and the
239  *      global private xstat_fs_oneShot variable.
240  *
241  * Side Effects:
242  *      Nothing interesting.
243  *------------------------------------------------------------------------*/
244
245 static void
246 xstat_fs_LWP()
247 {
248     static char rn[] = "xstat_fs_LWP";  /*Routine name */
249     register afs_int32 code;    /*Results of calls */
250     int oneShotCode;            /*Result of one-shot signal */
251     struct timeval tv;          /*Time structure */
252     int conn_idx;               /*Connection index */
253     struct xstat_fs_ConnectionInfo *curr_conn;  /*Current connection */
254     afs_int32 srvVersionNumber; /*Xstat version # */
255     afs_int32 clientVersionNumber;      /*Client xstat version */
256     afs_int32 numColls;         /*Number of collections to get */
257     afs_int32 *currCollIDP;     /*Curr collection ID desired */
258
259     static afs_int32 xstat_VersionNumber;       /*Version # of server */
260
261     /*
262      * Set up some numbers we'll need.
263      */
264     clientVersionNumber = AFS_XSTAT_VERSION;
265
266     while (1) {                 /*Service loop */
267         /*
268          * Iterate through the server connections, gathering data.
269          * Don't forget to bump the probe count and zero the statistics
270          * areas before calling the servers.
271          */
272         if (xstat_fs_debug)
273             printf("[%s] Waking up, getting data from %d server(s)\n", rn,
274                    xstat_fs_numServers);
275         curr_conn = xstat_fs_ConnInfo;
276         xstat_fs_Results.probeNum++;
277
278         for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
279             /*
280              * Grab the statistics for the current File Server, if the
281              * connection is valid.
282              */
283             if (xstat_fs_debug)
284                 printf("[%s] Getting collections from File Server '%s'\n", rn,
285                        curr_conn->hostName);
286             if (curr_conn->rxconn != (struct rx_connection *)0) {
287                 if (xstat_fs_debug)
288                     printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
289                            rn);
290
291                 currCollIDP = xstat_fs_collIDP;
292                 for (numColls = 0; numColls < xstat_fs_numCollections;
293                      numColls++, currCollIDP++) {
294                     /*
295                      * Initialize the per-probe values.
296                      */
297                     if (xstat_fs_debug)
298                         printf("[%s] Asking for data collection %d\n", rn,
299                                *currCollIDP);
300                     xstat_fs_Results.collectionNumber = *currCollIDP;
301                     xstat_fs_Results.data.AFS_CollData_len =
302                         AFS_MAX_XSTAT_LONGS;
303                     memset(xstat_fs_Results.data.AFS_CollData_val, 0,
304                            AFS_MAX_XSTAT_LONGS * 4);
305
306                     xstat_fs_Results.connP = curr_conn;
307
308                     if (xstat_fs_debug) {
309                         printf
310                             ("%s: Calling RXAFS_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
311                              rn, curr_conn->rxconn, clientVersionNumber,
312                              *currCollIDP, &srvVersionNumber,
313                              &(xstat_fs_Results.probeTime),
314                              &(xstat_fs_Results.data));
315                         printf("%s: [bufflen=%d, buffer at 0x%x]\n", rn,
316                                xstat_fs_Results.data.AFS_CollData_len,
317                                xstat_fs_Results.data.AFS_CollData_val);
318                     }
319
320                     xstat_fs_Results.probeOK =
321                         RXAFS_GetXStats(curr_conn->rxconn,
322                                         clientVersionNumber, *currCollIDP,
323                                         &srvVersionNumber,
324                                         &(xstat_fs_Results.probeTime),
325                                         &(xstat_fs_Results.data));
326
327                     /*
328                      * Now that we (may) have the data for this connection,
329                      * call the associated handler function.  The handler does
330                      * not take any explicit parameters, but rather gets to the
331                      * goodies via some of the objects exported by this module.
332                      */
333                     if (xstat_fs_debug)
334                         printf("[%s] Calling handler routine.\n", rn);
335                     code = xstat_fs_Handler();
336                     if (code)
337                         fprintf(stderr,
338                                 "[%s] Handler returned error code %d\n", rn,
339                                 code);
340
341                 }               /*For each collection */
342             }
343
344             /*Valid Rx connection */
345             /*
346              * Advance the xstat_fs connection pointer.
347              */
348             curr_conn++;
349
350         }                       /*For each xstat_fs connection */
351
352         /*
353          * All (valid) connections have been probed.  Fall asleep for the
354          * prescribed number of seconds, unless we're a one-shot.  In
355          * that case, we need to signal our caller that we're done.
356          */
357         if (xstat_fs_debug)
358             printf("[%s] Polling complete for probe round %d.\n", rn,
359                    xstat_fs_Results.probeNum);
360
361         if (xstat_fs_oneShot) {
362             /*
363              * One-shot execution desired.  Signal our main procedure
364              * that we've finished our collection round.
365              */
366             if (xstat_fs_debug)
367                 printf("[%s] Signalling main process at 0x%x\n", rn,
368                        &terminationEvent);
369             oneShotCode = LWP_SignalProcess(&terminationEvent);
370             if (oneShotCode)
371                 fprintf(stderr, "[%s] Error %d from LWP_SignalProcess()", rn,
372                         oneShotCode);
373             break;              /*from the perpetual while loop */
374         } /*One-shot execution */
375         else {
376             /*
377              * Continuous execution desired.  Sleep for the required
378              * number of seconds.
379              */
380             tv.tv_sec = xstat_fs_ProbeFreqInSecs;
381             tv.tv_usec = 0;
382             if (xstat_fs_debug)
383                 printf("[%s] Falling asleep for %d seconds\n", rn,
384                        xstat_fs_ProbeFreqInSecs);
385             code = IOMGR_Select(0,      /*Num fids */
386                                 0,      /*Descs ready for reading */
387                                 0,      /*Descs ready for writing */
388                                 0,      /*Descs w/exceptional conditions */
389                                 &tv);   /*Ptr to timeout structure */
390             if (code)
391                 fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn,
392                         code);
393         }                       /*Continuous execution */
394     }                           /*Service loop */
395 }
396
397 /*------------------------------------------------------------------------
398  * [exported] xstat_fs_Init
399  *
400  * Description:
401  *      Initialize the xstat_fs module: set up Rx connections to the
402  *      given set of File Servers, start up the probe and callback LWPs,
403  *      and associate the routine to be called when a probe completes.
404  *      Also, let it know which collections you're interested in.
405  *
406  * Arguments:
407  *      int a_numServers                  : Num. servers to connect to.
408  *      struct sockaddr_in *a_socketArray : Array of server sockets.
409  *      int a_ProbeFreqInSecs             : Probe frequency in seconds.
410  *      int (*a_ProbeHandler)()           : Ptr to probe handler fcn.
411  *      int a_flags                       : Various flags.
412  *      int a_numCollections              : Number of collections desired.
413  *      afs_int32 *a_collIDP                      : Ptr to collection IDs.
414  *
415  * Returns:
416  *      0 on success,
417  *      -2 for (at least one) connection error,
418  *      LWP process creation code, if it failed,
419  *      -1 for other fatal errors.
420  *
421  * Environment:
422  *      *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
423  *      Also, the server security object CBsecobj MUST be a static,
424  *      since it has to stick around after this routine exits.
425  *
426  * Side Effects:
427  *      Sets up just about everything.
428  *------------------------------------------------------------------------*/
429
430 int
431 xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
432               int a_ProbeFreqInSecs, int (*a_ProbeHandler) (), int a_flags,
433               int a_numCollections, afs_int32 * a_collIDP)
434 {
435     static char rn[] = "xstat_fs_Init"; /*Routine name */
436     register afs_int32 code;    /*Return value */
437     static struct rx_securityClass *CBsecobj;   /*Callback security object */
438     struct rx_securityClass *secobj;    /*Client security object */
439     struct rx_service *rxsrv_afsserver; /*Server for AFS */
440     int arg_errfound;           /*Argument error found? */
441     int curr_srv;               /*Current server idx */
442     struct xstat_fs_ConnectionInfo *curr_conn;  /*Ptr to current conn */
443     char *hostNameFound;        /*Ptr to returned host name */
444     int conn_err;               /*Connection error? */
445     int PortToUse;              /*Callback port to use */
446     int collIDBytes;            /*Num bytes in coll ID array */
447
448     /*
449      * If we've already been called, snicker at the bozo, gently
450      * remind him of his doubtful heritage, and return success.
451      */
452     if (xstat_fs_initflag) {
453         fprintf(stderr, "[%s] Called multiple times!\n", rn);
454         return (0);
455     } else
456         xstat_fs_initflag = 1;
457
458     /*
459      * Check the parameters for bogosities.
460      */
461     arg_errfound = 0;
462     if (a_numServers <= 0) {
463         fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
464                 a_numServers);
465         arg_errfound = 1;
466     }
467     if (a_socketArray == (struct sockaddr_in *)0) {
468         fprintf(stderr, "[%s] Null server socket array argument\n", rn);
469         arg_errfound = 1;
470     }
471     if (a_ProbeFreqInSecs <= 0) {
472         fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
473                 a_ProbeFreqInSecs);
474         arg_errfound = 1;
475     }
476     if (a_ProbeHandler == (int (*)())0) {
477         fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
478         arg_errfound = 1;
479     }
480     if (a_numCollections <= 0) {
481         fprintf(stderr, "[%s] Illegal collection count argument: %d\n", rn,
482                 a_numServers);
483         arg_errfound = 1;
484     }
485     if (a_collIDP == NULL) {
486         fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
487         arg_errfound = 1;
488     }
489     if (arg_errfound)
490         return (-1);
491
492     /*
493      * Record our passed-in info.
494      */
495     xstat_fs_debug = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
496     xstat_fs_oneShot = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
497     xstat_fs_numServers = a_numServers;
498     xstat_fs_Handler = a_ProbeHandler;
499     xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
500     xstat_fs_numCollections = a_numCollections;
501     collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
502     xstat_fs_collIDP = (afs_int32 *) (malloc(collIDBytes));
503     memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
504     if (xstat_fs_debug) {
505         printf("[%s] Asking for %d collection(s): ", rn,
506                xstat_fs_numCollections);
507         for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
508             printf("%d ", *(xstat_fs_collIDP + curr_srv));
509         printf("\n");
510     }
511
512     /*
513      * Get ready in case we have to do a cleanup - basically, zero
514      * everything out.
515      */
516     code = xstat_fs_CleanupInit();
517     if (code)
518         return (code);
519
520     /*
521      * Allocate the necessary data structures and initialize everything
522      * else.
523      */
524     xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)
525         malloc(a_numServers * sizeof(struct xstat_fs_ConnectionInfo));
526     if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
527         fprintf(stderr,
528                 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
529                 rn, a_numServers,
530                 (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
531         return (-1);            /*No cleanup needs to be done yet */
532     }
533
534     /*
535      * Initialize the Rx subsystem, just in case nobody's done it.
536      */
537     if (xstat_fs_debug)
538         printf("[%s] Initializing Rx\n", rn);
539     PortToUse = XSTAT_FS_CBPORT;
540
541     do {
542         code = rx_Init(htons(PortToUse));
543         if (code) {
544             if (code == RX_ADDRINUSE) {
545                 if (xstat_fs_debug)
546                     fprintf(stderr,
547                             "[%s] Callback port %d in use, advancing\n", rn,
548                             PortToUse);
549                 PortToUse++;
550             } else {
551                 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
552                 return (-1);
553             }
554         }
555     } while (code);
556     if (xstat_fs_debug)
557         printf("[%s] Rx initialized on port %d\n", rn, PortToUse);
558
559     /*
560      * Create a null Rx server security object, to be used by the
561      * Callback listener.
562      */
563     CBsecobj = (struct rx_securityClass *)
564         rxnull_NewServerSecurityObject();
565     if (CBsecobj == (struct rx_securityClass *)0) {
566         fprintf(stderr,
567                 "[%s] Can't create callback listener's security object.\n",
568                 rn);
569         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
570         return (-1);
571     }
572     if (xstat_fs_debug)
573         printf("[%s] Callback server security object created\n", rn);
574
575     /*
576      * Create a null Rx client security object, to be used by the
577      * probe LWP.
578      */
579     secobj = rxnull_NewClientSecurityObject();
580     if (secobj == (struct rx_securityClass *)0) {
581         fprintf(stderr,
582                 "[%s] Can't create probe LWP client security object.\n", rn);
583         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
584         return (-1);
585     }
586     if (xstat_fs_debug)
587         printf("[%s] Probe LWP client security object created\n", rn);
588
589     curr_conn = xstat_fs_ConnInfo;
590     conn_err = 0;
591     for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
592         /*
593          * Copy in the socket info for the current server, resolve its
594          * printable name if possible.
595          */
596         if (xstat_fs_debug) {
597             printf("[%s] Copying in the following socket info:\n", rn);
598             printf("[%s] IP addr 0x%lx, port %d\n", rn,
599                    (a_socketArray + curr_srv)->sin_addr.s_addr,
600                    (a_socketArray + curr_srv)->sin_port);
601         }
602         memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
603                sizeof(struct sockaddr_in));
604
605         hostNameFound =
606             hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
607         if (hostNameFound == NULL) {
608             fprintf(stderr,
609                     "[%s] Can't map Internet address %lu to a string name\n",
610                     rn, curr_conn->skt.sin_addr.s_addr);
611             curr_conn->hostName[0] = '\0';
612         } else {
613             strcpy(curr_conn->hostName, hostNameFound);
614             if (xstat_fs_debug)
615                 printf("[%s] Host name for server index %d is %s\n", rn,
616                        curr_srv, curr_conn->hostName);
617         }
618
619         /*
620          * Make an Rx connection to the current server.
621          */
622         if (xstat_fs_debug)
623             printf
624                 ("[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
625                  rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
626                  curr_conn->skt.sin_port);
627
628         curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr,    /*Server addr */
629                                              curr_conn->skt.sin_port,   /*Server port */
630                                              1, /*AFS service # */
631                                              secobj,    /*Security obj */
632                                              0);        /*# of above */
633         if (curr_conn->rxconn == (struct rx_connection *)0) {
634             fprintf(stderr,
635                     "[%s] Can't create Rx connection to server '%s' (%lu)\n",
636                     rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
637             conn_err = 1;
638         }
639         if (xstat_fs_debug)
640             printf("[%s] New connection at 0x%lx\n", rn, curr_conn->rxconn);
641
642         /*
643          * Bump the current xstat_fs connection to set up.
644          */
645         curr_conn++;
646
647     }                           /*for curr_srv */
648
649     /*
650      * Create the AFS callback service (listener).
651      */
652     if (xstat_fs_debug)
653         printf("[%s] Creating AFS callback listener\n", rn);
654     rxsrv_afsserver = rx_NewService(0,  /*Use default port */
655                                     1,  /*Service ID */
656                                     "afs",      /*Service name */
657                                     &CBsecobj,  /*Ptr to security object(s) */
658                                     1,  /*# of security objects */
659                                     RXAFSCB_ExecuteRequest);    /*Dispatcher */
660     if (rxsrv_afsserver == (struct rx_service *)0) {
661         fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
662                 rn);
663         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
664         return (-1);
665     }
666     if (xstat_fs_debug)
667         printf("[%s] Callback listener created\n", rn);
668
669     /*
670      * Start up the AFS callback service.
671      */
672     if (xstat_fs_debug)
673         printf("[%s] Starting up callback listener.\n", rn);
674     rx_StartServer(0);          /*Don't donate yourself to LWP pool */
675
676     /*
677      * Start up the probe LWP.
678      */
679     if (xstat_fs_debug)
680         printf("[%s] Creating the probe LWP\n", rn);
681     code = LWP_CreateProcess(xstat_fs_LWP,      /*Function to start up */
682                              LWP_STACK_SIZE,    /*Stack size in bytes */
683                              1, /*Priority */
684                              (void *)0, /*Parameters */
685                              "xstat_fs Worker", /*Name to use */
686                              &probeLWP_ID);     /*Returned LWP process ID */
687     if (code) {
688         fprintf(stderr, "[%s] Can't create xstat_fs LWP!  Error is %d\n", rn,
689                 code);
690         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
691         return (code);
692     }
693     if (xstat_fs_debug)
694         printf("[%s] Probe LWP process structure located at 0x%x\n", rn,
695                probeLWP_ID);
696
697     /*
698      * Return the final results.
699      */
700     if (conn_err)
701         return (-2);
702     else
703         return (0);
704 }
705
706
707 /*------------------------------------------------------------------------
708  * [exported] xstat_fs_ForceProbeNow
709  *
710  * Description:
711  *      Wake up the probe LWP, forcing it to execute a probe immediately.
712  *
713  * Arguments:
714  *      None.
715  *
716  * Returns:
717  *      0 on success,
718  *      Error value otherwise.
719  *
720  * Environment:
721  *      The module must have been initialized.
722  *
723  * Side Effects:
724  *      As advertised.
725  *------------------------------------------------------------------------*/
726
727 int
728 xstat_fs_ForceProbeNow()
729 {
730     static char rn[] = "xstat_fs_ForceProbeNow";        /*Routine name */
731
732     /*
733      * There isn't a prayer unless we've been initialized.
734      */
735     if (!xstat_fs_initflag) {
736         fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
737         return (-1);
738     }
739
740     /*
741      * Kick the sucker in the side.
742      */
743     IOMGR_Cancel(probeLWP_ID);
744
745     /*
746      * We did it, so report the happy news.
747      */
748     return (0);
749 }