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