2 * Copyright 2000, International Business Machines Corporation and others.
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
12 * Implementation of the client side of the AFS File Server extended
13 * statistics facility.
15 *------------------------------------------------------------------------*/
17 #include <afsconfig.h>
18 #include <afs/param.h>
23 #include "xstat_fs.h" /*Interface for this module */
24 #include <lwp.h> /*Lightweight process package */
26 #include <afs/afsutil.h>
29 #define LWP_STACK_SIZE (16 * 1024)
32 * Routines we need that don't have explicit include file definitions.
34 extern int RXAFSCB_ExecuteRequest(); /*AFS callback dispatcher */
35 extern char *hostutil_GetNameByINet(); /*Host parsing utility */
38 * Help out the linker by explicitly importing the callback routines
39 * File Servers may be lobbing at us.
41 extern afs_int32 SRXAFSCB_CallBack();
42 extern afs_int32 SRXAFSCB_InitCallBackState3();
43 extern afs_int32 SRXAFSCB_Probe();
44 extern afs_int32 SRXAFSCB_ProbeUUID();
45 extern afs_int32 SRXAFSCB_GetCE();
46 extern afs_int32 SRXAFSCB_GetLock();
51 int xstat_fs_numServers; /*Num connected servers */
52 struct xstat_fs_ConnectionInfo
53 *xstat_fs_ConnInfo; /*Ptr to connection array */
54 int numCollections; /*Number of data collections */
55 struct xstat_fs_ProbeResults xstat_fs_Results; /*Latest probe results */
56 char terminationEvent; /*One-shot termination event */
58 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS]; /*Buffer for collected data */
63 static int xstat_fs_ProbeFreqInSecs; /*Probe freq. in seconds */
64 static int xstat_fs_initflag = 0; /*Was init routine called? */
65 static int xstat_fs_debug = 0; /*Debugging output enabled? */
66 static int xstat_fs_oneShot = 0; /*One-shot operation? */
67 static int (*xstat_fs_Handler) (); /*Probe handler routine */
68 static PROCESS probeLWP_ID; /*Probe LWP process ID */
69 static int xstat_fs_numCollections; /*Number of desired collections */
70 static afs_int32 *xstat_fs_collIDP; /*Ptr to collection IDs desired */
73 * We have to pass a port to Rx to start up our callback listener
74 * service, but 7001 is already taken up by the Cache Manager. So,
77 #define XSTAT_FS_CBPORT 7101
80 /*------------------------------------------------------------------------
81 * [private] xstat_fs_CleanupInit
84 * Set up for recovery after an error in initialization (i.e.,
85 * during a call to xstat_fs_Init.
92 * Error value otherwise.
95 * This routine is private to the module.
98 * Zeros out basic data structures.
99 *------------------------------------------------------------------------*/
102 xstat_fs_CleanupInit()
104 afs_int32 code; /*Return code from callback stubs */
105 struct rx_call *rxcall; /*Bogus param */
106 AFSCBFids *Fids_Array; /*Bogus param */
107 AFSCBs *CallBack_Array; /*Bogus param */
109 xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
110 xstat_fs_Results.probeNum = 0;
111 xstat_fs_Results.probeTime = 0;
112 xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
113 xstat_fs_Results.collectionNumber = 0;
114 xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
115 xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *) xstat_fsData;
116 xstat_fs_Results.probeOK = 0;
118 rxcall = (struct rx_call *)0;
119 Fids_Array = (AFSCBFids *) 0;
120 CallBack_Array = (AFSCBs *) 0;
123 * Call each of the callback routines our module provides (in
124 * xstat_fs_callback.c) to make sure they're all there.
126 code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
129 code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
132 code = SRXAFSCB_Probe(rxcall);
137 /*------------------------------------------------------------------------
138 * [exported] xstat_fs_Cleanup
141 * Clean up our memory and connection state.
144 * int a_releaseMem : Should we free up malloc'ed areas?
147 * 0 on total success,
148 * -1 if the module was never initialized, or there was a problem
149 * with the xstat_fs connection array.
152 * xstat_fs_numServers should be properly set. We don't do anything
153 * unless xstat_fs_Init() has already been called.
156 * Shuts down Rx connections gracefully, frees allocated space
158 *------------------------------------------------------------------------*/
161 xstat_fs_Cleanup(int a_releaseMem)
163 static char rn[] = "xstat_fs_Cleanup"; /*Routine name */
164 int code; /*Return code */
165 int conn_idx; /*Current connection index */
166 struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to xstat_fs connection */
169 * Assume the best, but check the worst.
171 if (!xstat_fs_initflag) {
172 fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
178 * Take care of all Rx connections first. Check to see that the
179 * server count is a legal value.
181 if (xstat_fs_numServers <= 0) {
183 "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
184 rn, xstat_fs_numServers);
187 if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
189 * The xstat_fs connection structure array exists. Go through
190 * it and close up any Rx connections it holds.
192 curr_conn = xstat_fs_ConnInfo;
193 for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
194 if (curr_conn->rxconn != (struct rx_connection *)0) {
195 rx_DestroyConnection(curr_conn->rxconn);
196 curr_conn->rxconn = (struct rx_connection *)0;
199 } /*for each xstat_fs connection */
200 } /*xstat_fs connection structure exists */
201 } /*Legal number of servers */
204 * If asked to, release the space we've allocated.
207 if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0)
208 free(xstat_fs_ConnInfo);
212 * Return the news, whatever it is.
218 /*------------------------------------------------------------------------
219 * [private] xstat_fs_LWP
222 * This LWP iterates over the server connections and gathers up
223 * the desired statistics from each one on a regular basis. When
224 * the sweep is done, the associated handler function is called
225 * to process the new data.
234 * Started by xstat_fs_Init(), uses global structures and the
235 * global private xstat_fs_oneShot variable.
238 * Nothing interesting.
239 *------------------------------------------------------------------------*/
242 xstat_fs_LWP(void *unused)
244 static char rn[] = "xstat_fs_LWP"; /*Routine name */
245 register afs_int32 code; /*Results of calls */
246 int oneShotCode; /*Result of one-shot signal */
247 struct timeval tv; /*Time structure */
248 int conn_idx; /*Connection index */
249 struct xstat_fs_ConnectionInfo *curr_conn; /*Current connection */
250 afs_int32 srvVersionNumber; /*Xstat version # */
251 afs_int32 clientVersionNumber; /*Client xstat version */
252 afs_int32 numColls; /*Number of collections to get */
253 afs_int32 *currCollIDP; /*Curr collection ID desired */
255 static afs_int32 xstat_VersionNumber; /*Version # of server */
258 * Set up some numbers we'll need.
260 clientVersionNumber = AFS_XSTAT_VERSION;
262 while (1) { /*Service loop */
264 * Iterate through the server connections, gathering data.
265 * Don't forget to bump the probe count and zero the statistics
266 * areas before calling the servers.
269 printf("[%s] Waking up, getting data from %d server(s)\n", rn,
270 xstat_fs_numServers);
271 curr_conn = xstat_fs_ConnInfo;
272 xstat_fs_Results.probeNum++;
274 for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
276 * Grab the statistics for the current File Server, if the
277 * connection is valid.
280 printf("[%s] Getting collections from File Server '%s'\n", rn,
281 curr_conn->hostName);
282 if (curr_conn->rxconn != (struct rx_connection *)0) {
284 printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
287 currCollIDP = xstat_fs_collIDP;
288 for (numColls = 0; numColls < xstat_fs_numCollections;
289 numColls++, currCollIDP++) {
291 * Initialize the per-probe values.
294 printf("[%s] Asking for data collection %d\n", rn,
296 xstat_fs_Results.collectionNumber = *currCollIDP;
297 xstat_fs_Results.data.AFS_CollData_len =
299 memset(xstat_fs_Results.data.AFS_CollData_val, 0,
300 AFS_MAX_XSTAT_LONGS * 4);
302 xstat_fs_Results.connP = curr_conn;
304 if (xstat_fs_debug) {
306 ("%s: Calling RXAFS_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
307 rn, curr_conn->rxconn, clientVersionNumber,
308 *currCollIDP, &srvVersionNumber,
309 &(xstat_fs_Results.probeTime),
310 &(xstat_fs_Results.data));
311 printf("%s: [bufflen=%d, buffer at 0x%x]\n", rn,
312 xstat_fs_Results.data.AFS_CollData_len,
313 xstat_fs_Results.data.AFS_CollData_val);
316 xstat_fs_Results.probeOK =
317 RXAFS_GetXStats(curr_conn->rxconn,
318 clientVersionNumber, *currCollIDP,
320 &(xstat_fs_Results.probeTime),
321 &(xstat_fs_Results.data));
324 * Now that we (may) have the data for this connection,
325 * call the associated handler function. The handler does
326 * not take any explicit parameters, but rather gets to the
327 * goodies via some of the objects exported by this module.
330 printf("[%s] Calling handler routine.\n", rn);
331 code = xstat_fs_Handler();
334 "[%s] Handler returned error code %d\n", rn,
337 } /*For each collection */
340 /*Valid Rx connection */
342 * Advance the xstat_fs connection pointer.
346 } /*For each xstat_fs connection */
349 * All (valid) connections have been probed. Fall asleep for the
350 * prescribed number of seconds, unless we're a one-shot. In
351 * that case, we need to signal our caller that we're done.
354 printf("[%s] Polling complete for probe round %d.\n", rn,
355 xstat_fs_Results.probeNum);
357 if (xstat_fs_oneShot) {
359 * One-shot execution desired. Signal our main procedure
360 * that we've finished our collection round.
363 printf("[%s] Signalling main process at 0x%x\n", rn,
365 oneShotCode = LWP_SignalProcess(&terminationEvent);
367 fprintf(stderr, "[%s] Error %d from LWP_SignalProcess()", rn,
369 break; /*from the perpetual while loop */
370 } /*One-shot execution */
373 * Continuous execution desired. Sleep for the required
376 tv.tv_sec = xstat_fs_ProbeFreqInSecs;
379 printf("[%s] Falling asleep for %d seconds\n", rn,
380 xstat_fs_ProbeFreqInSecs);
381 code = IOMGR_Select(0, /*Num fids */
382 0, /*Descs ready for reading */
383 0, /*Descs ready for writing */
384 0, /*Descs w/exceptional conditions */
385 &tv); /*Ptr to timeout structure */
387 fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn,
389 } /*Continuous execution */
394 /*------------------------------------------------------------------------
395 * [exported] xstat_fs_Init
398 * Initialize the xstat_fs module: set up Rx connections to the
399 * given set of File Servers, start up the probe and callback LWPs,
400 * and associate the routine to be called when a probe completes.
401 * Also, let it know which collections you're interested in.
404 * int a_numServers : Num. servers to connect to.
405 * struct sockaddr_in *a_socketArray : Array of server sockets.
406 * int a_ProbeFreqInSecs : Probe frequency in seconds.
407 * int (*a_ProbeHandler)() : Ptr to probe handler fcn.
408 * int a_flags : Various flags.
409 * int a_numCollections : Number of collections desired.
410 * afs_int32 *a_collIDP : Ptr to collection IDs.
414 * -2 for (at least one) connection error,
415 * LWP process creation code, if it failed,
416 * -1 for other fatal errors.
419 * *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
420 * Also, the server security object CBsecobj MUST be a static,
421 * since it has to stick around after this routine exits.
424 * Sets up just about everything.
425 *------------------------------------------------------------------------*/
428 xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
429 int a_ProbeFreqInSecs, int (*a_ProbeHandler) (), int a_flags,
430 int a_numCollections, afs_int32 * a_collIDP)
432 static char rn[] = "xstat_fs_Init"; /*Routine name */
433 register afs_int32 code; /*Return value */
434 static struct rx_securityClass *CBsecobj; /*Callback security object */
435 struct rx_securityClass *secobj; /*Client security object */
436 struct rx_service *rxsrv_afsserver; /*Server for AFS */
437 int arg_errfound; /*Argument error found? */
438 int curr_srv; /*Current server idx */
439 struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to current conn */
440 char *hostNameFound; /*Ptr to returned host name */
441 int conn_err; /*Connection error? */
442 int PortToUse; /*Callback port to use */
443 int collIDBytes; /*Num bytes in coll ID array */
447 * If we've already been called, snicker at the bozo, gently
448 * remind him of his doubtful heritage, and return success.
450 if (xstat_fs_initflag) {
451 fprintf(stderr, "[%s] Called multiple times!\n", rn);
454 xstat_fs_initflag = 1;
457 * Check the parameters for bogosities.
460 if (a_numServers <= 0) {
461 fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
465 if (a_socketArray == (struct sockaddr_in *)0) {
466 fprintf(stderr, "[%s] Null server socket array argument\n", rn);
469 if (a_ProbeFreqInSecs <= 0) {
470 fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
474 if (a_ProbeHandler == (int (*)())0) {
475 fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
478 if (a_numCollections <= 0) {
479 fprintf(stderr, "[%s] Illegal collection count argument: %d\n", rn,
483 if (a_collIDP == NULL) {
484 fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
491 * Record our passed-in info.
493 xstat_fs_debug = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
494 xstat_fs_oneShot = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
495 xstat_fs_numServers = a_numServers;
496 xstat_fs_Handler = a_ProbeHandler;
497 xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
498 xstat_fs_numCollections = a_numCollections;
499 collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
500 xstat_fs_collIDP = (afs_int32 *) (malloc(collIDBytes));
501 memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
502 if (xstat_fs_debug) {
503 printf("[%s] Asking for %d collection(s): ", rn,
504 xstat_fs_numCollections);
505 for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
506 printf("%d ", *(xstat_fs_collIDP + curr_srv));
511 * Get ready in case we have to do a cleanup - basically, zero
514 code = xstat_fs_CleanupInit();
519 * Allocate the necessary data structures and initialize everything
522 xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)
523 malloc(a_numServers * sizeof(struct xstat_fs_ConnectionInfo));
524 if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
526 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
528 (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
529 return (-1); /*No cleanup needs to be done yet */
533 * Initialize the Rx subsystem, just in case nobody's done it.
536 printf("[%s] Initializing Rx\n", rn);
537 PortToUse = XSTAT_FS_CBPORT;
540 code = rx_Init(htons(PortToUse));
542 if (code == RX_ADDRINUSE) {
545 "[%s] Callback port %d in use, advancing\n", rn,
549 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
555 printf("[%s] Rx initialized on port %d\n", rn, PortToUse);
558 * Create a null Rx server security object, to be used by the
561 CBsecobj = (struct rx_securityClass *)
562 rxnull_NewServerSecurityObject();
563 if (CBsecobj == (struct rx_securityClass *)0) {
565 "[%s] Can't create callback listener's security object.\n",
567 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
571 printf("[%s] Callback server security object created\n", rn);
574 * Create a null Rx client security object, to be used by the
577 secobj = rxnull_NewClientSecurityObject();
578 if (secobj == (struct rx_securityClass *)0) {
580 "[%s] Can't create probe LWP client security object.\n", rn);
581 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
585 printf("[%s] Probe LWP client security object created\n", rn);
587 curr_conn = xstat_fs_ConnInfo;
589 for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
591 * Copy in the socket info for the current server, resolve its
592 * printable name if possible.
594 if (xstat_fs_debug) {
596 printf("[%s] Copying in the following socket info:\n", rn);
597 printf("[%s] IP addr %s, port %d\n", rn,
598 afs_inet_ntoa_r((a_socketArray + curr_srv)->sin_addr.s_addr,hoststr),
599 ntohs((a_socketArray + curr_srv)->sin_port));
601 memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
602 sizeof(struct sockaddr_in));
605 hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
606 if (hostNameFound == NULL) {
608 "[%s] Can't map Internet address %s to a string name\n",
609 rn, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
610 curr_conn->hostName[0] = '\0';
612 strcpy(curr_conn->hostName, hostNameFound);
614 printf("[%s] Host name for server index %d is %s\n", rn,
615 curr_srv, curr_conn->hostName);
619 * Make an Rx connection to the current server.
623 ("[%s] Connecting to srv idx %d, IP addr %s, port %d, service 1\n",
624 rn, curr_srv, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr),
625 ntohs(curr_conn->skt.sin_port));
627 curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
628 curr_conn->skt.sin_port, /*Server port */
629 1, /*AFS service # */
630 secobj, /*Security obj */
632 if (curr_conn->rxconn == (struct rx_connection *)0) {
634 "[%s] Can't create Rx connection to server '%s' (%s)\n",
635 rn, curr_conn->hostName, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
639 printf("[%s] New connection at 0x%lx\n", rn, curr_conn->rxconn);
642 * Bump the current xstat_fs connection to set up.
649 * Create the AFS callback service (listener).
652 printf("[%s] Creating AFS callback listener\n", rn);
653 rxsrv_afsserver = rx_NewService(0, /*Use default port */
655 "afs", /*Service name */
656 &CBsecobj, /*Ptr to security object(s) */
657 1, /*# of security objects */
658 RXAFSCB_ExecuteRequest); /*Dispatcher */
659 if (rxsrv_afsserver == (struct rx_service *)0) {
660 fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
662 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
666 printf("[%s] Callback listener created\n", rn);
669 * Start up the AFS callback service.
672 printf("[%s] Starting up callback listener.\n", rn);
673 rx_StartServer(0); /*Don't donate yourself to LWP pool */
676 * Start up the probe LWP.
679 printf("[%s] Creating the probe LWP\n", rn);
680 code = LWP_CreateProcess(xstat_fs_LWP, /*Function to start up */
681 LWP_STACK_SIZE, /*Stack size in bytes */
683 (void *)0, /*Parameters */
684 "xstat_fs Worker", /*Name to use */
685 &probeLWP_ID); /*Returned LWP process ID */
687 fprintf(stderr, "[%s] Can't create xstat_fs LWP! Error is %d\n", rn,
689 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
693 printf("[%s] Probe LWP process structure located at 0x%x\n", rn,
697 * Return the final results.
706 /*------------------------------------------------------------------------
707 * [exported] xstat_fs_ForceProbeNow
710 * Wake up the probe LWP, forcing it to execute a probe immediately.
717 * Error value otherwise.
720 * The module must have been initialized.
724 *------------------------------------------------------------------------*/
727 xstat_fs_ForceProbeNow()
729 static char rn[] = "xstat_fs_ForceProbeNow"; /*Routine name */
732 * There isn't a prayer unless we've been initialized.
734 if (!xstat_fs_initflag) {
735 fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
740 * Kick the sucker in the side.
742 IOMGR_Cancel(probeLWP_ID);
745 * We did it, so report the happy news.