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>
22 #include "xstat_fs.h" /*Interface for this module*/
23 #include <lwp.h> /*Lightweight process package*/
25 #define LWP_STACK_SIZE (16 * 1024)
28 * Routines we need that don't have explicit include file definitions.
30 extern int RXAFSCB_ExecuteRequest(); /*AFS callback dispatcher*/
31 extern char *hostutil_GetNameByINet(); /*Host parsing utility*/
34 * Help out the linker by explicitly importing the callback routines
35 * File Servers may be lobbing at us.
37 extern afs_int32 SRXAFSCB_CallBack();
38 extern afs_int32 SRXAFSCB_InitCallBackState3();
39 extern afs_int32 SRXAFSCB_Probe();
40 extern afs_int32 SRXAFSCB_GetCE();
41 extern afs_int32 SRXAFSCB_GetLock();
46 int xstat_fs_numServers; /*Num connected servers*/
47 struct xstat_fs_ConnectionInfo
48 *xstat_fs_ConnInfo; /*Ptr to connection array*/
49 int numCollections; /*Number of data collections*/
50 struct xstat_fs_ProbeResults xstat_fs_Results; /*Latest probe results*/
51 char terminationEvent; /*One-shot termination event*/
53 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS]; /*Buffer for collected data*/
58 static int xstat_fs_ProbeFreqInSecs; /*Probe freq. in seconds*/
59 static int xstat_fs_initflag = 0; /*Was init routine called?*/
60 static int xstat_fs_debug = 0; /*Debugging output enabled?*/
61 static int xstat_fs_oneShot = 0; /*One-shot operation?*/
62 static int (*xstat_fs_Handler)(); /*Probe handler routine*/
63 static PROCESS probeLWP_ID; /*Probe LWP process ID*/
64 static int xstat_fs_numCollections; /*Number of desired collections*/
65 static afs_int32 *xstat_fs_collIDP; /*Ptr to collection IDs desired*/
68 * We have to pass a port to Rx to start up our callback listener
69 * service, but 7001 is already taken up by the Cache Manager. So,
72 #define XSTAT_FS_CBPORT 7101
75 /*------------------------------------------------------------------------
76 * [private] xstat_fs_CleanupInit
79 * Set up for recovery after an error in initialization (i.e.,
80 * during a call to xstat_fs_Init.
87 * Error value otherwise.
90 * This routine is private to the module.
93 * Zeros out basic data structures.
94 *------------------------------------------------------------------------*/
96 static int xstat_fs_CleanupInit()
98 { /*xstat_fs_CleanupInit*/
100 afs_int32 code; /*Return code from callback stubs*/
101 struct rx_call *rxcall; /*Bogus param*/
102 AFSCBFids *Fids_Array; /*Bogus param*/
103 AFSCBs *CallBack_Array; /*Bogus param*/
105 xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
106 xstat_fs_Results.probeNum = 0;
107 xstat_fs_Results.probeTime = 0;
108 xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
109 xstat_fs_Results.collectionNumber = 0;
110 xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
111 xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *)xstat_fsData;
112 xstat_fs_Results.probeOK = 0;
114 rxcall = (struct rx_call *)0;
115 Fids_Array = (AFSCBFids *)0;
116 CallBack_Array = (AFSCBs *)0;
119 * Call each of the callback routines our module provides (in
120 * xstat_fs_callback.c) to make sure they're all there.
122 code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
125 code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
128 code = SRXAFSCB_Probe(rxcall);
131 } /*xstat_fs_CleanupInit*/
134 /*------------------------------------------------------------------------
135 * [exported] xstat_fs_Cleanup
138 * Clean up our memory and connection state.
141 * int a_releaseMem : Should we free up malloc'ed areas?
144 * 0 on total success,
145 * -1 if the module was never initialized, or there was a problem
146 * with the xstat_fs connection array.
149 * xstat_fs_numServers should be properly set. We don't do anything
150 * unless xstat_fs_Init() has already been called.
153 * Shuts down Rx connections gracefully, frees allocated space
155 *------------------------------------------------------------------------*/
157 int xstat_fs_Cleanup(a_releaseMem)
160 { /*xstat_fs_Cleanup*/
162 static char rn[] = "xstat_fs_Cleanup"; /*Routine name*/
163 int code; /*Return code*/
164 int conn_idx; /*Current connection index*/
165 struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to xstat_fs connection*/
168 * Assume the best, but check the worst.
170 if (!xstat_fs_initflag) {
171 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);
188 if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
190 * The xstat_fs connection structure array exists. Go through
191 * it and close up any Rx connections it holds.
193 curr_conn = xstat_fs_ConnInfo;
194 for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
195 if (curr_conn->rxconn != (struct rx_connection *)0) {
196 rx_DestroyConnection(curr_conn->rxconn);
197 curr_conn->rxconn = (struct rx_connection *)0;
200 } /*for each xstat_fs connection*/
201 } /*xstat_fs connection structure exists*/
202 } /*Legal number of servers*/
205 * If asked to, release the space we've allocated.
208 if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0)
209 free(xstat_fs_ConnInfo);
213 * Return the news, whatever it is.
217 } /*xstat_fs_Cleanup*/
220 /*------------------------------------------------------------------------
221 * [private] xstat_fs_LWP
224 * This LWP iterates over the server connections and gathers up
225 * the desired statistics from each one on a regular basis. When
226 * the sweep is done, the associated handler function is called
227 * to process the new data.
236 * Started by xstat_fs_Init(), uses global structures and the
237 * global private xstat_fs_oneShot variable.
240 * Nothing interesting.
241 *------------------------------------------------------------------------*/
243 static void xstat_fs_LWP()
247 static char rn[] = "xstat_fs_LWP"; /*Routine name*/
248 register afs_int32 code; /*Results of calls*/
249 int oneShotCode; /*Result of one-shot signal*/
250 struct timeval tv; /*Time structure*/
251 int conn_idx; /*Connection index*/
252 struct xstat_fs_ConnectionInfo *curr_conn; /*Current connection*/
253 afs_int32 srvVersionNumber; /*Xstat version #*/
254 afs_int32 clientVersionNumber; /*Client xstat version*/
255 afs_int32 numColls; /*Number of collections to get*/
256 afs_int32 *currCollIDP; /*Curr collection ID desired*/
258 static afs_int32 xstat_VersionNumber; /*Version # of server*/
261 * Set up some numbers we'll need.
263 clientVersionNumber = AFS_XSTAT_VERSION;
265 while (1) { /*Service loop*/
267 * Iterate through the server connections, gathering data.
268 * Don't forget to bump the probe count and zero the statistics
269 * areas before calling the servers.
272 printf("[%s] Waking up, getting data from %d server(s)\n",
273 rn, xstat_fs_numServers);
274 curr_conn = xstat_fs_ConnInfo;
275 xstat_fs_Results.probeNum++;
277 for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
279 * Grab the statistics for the current File Server, if the
280 * connection is valid.
283 printf("[%s] Getting collections from File Server '%s'\n",
284 rn, curr_conn->hostName);
285 if (curr_conn->rxconn != (struct rx_connection *)0) {
287 printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
290 currCollIDP = xstat_fs_collIDP;
292 numColls < xstat_fs_numCollections;
293 numColls++, currCollIDP++) {
295 * Initialize the per-probe values.
298 printf("[%s] Asking for data collection %d\n",
300 xstat_fs_Results.collectionNumber = *currCollIDP;
301 xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
302 memset(xstat_fs_Results.data.AFS_CollData_val, 0, AFS_MAX_XSTAT_LONGS * 4);
304 xstat_fs_Results.connP = curr_conn;
306 if (xstat_fs_debug) {
307 printf("%s: Calling RXAFS_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
308 rn, curr_conn->rxconn,
312 &(xstat_fs_Results.probeTime),
313 &(xstat_fs_Results.data));
314 printf("%s: [bufflen=%d, buffer at 0x%x]\n",
316 xstat_fs_Results.data.AFS_CollData_len,
317 xstat_fs_Results.data.AFS_CollData_val);
320 xstat_fs_Results.probeOK =
321 RXAFS_GetXStats(curr_conn->rxconn,
325 &(xstat_fs_Results.probeTime),
326 &(xstat_fs_Results.data));
329 * Now that we (may) have the data for this connection,
330 * call the associated handler function. The handler does
331 * not take any explicit parameters, but rather gets to the
332 * goodies via some of the objects exported by this module.
335 printf("[%s] Calling handler routine.\n", rn);
336 code = xstat_fs_Handler();
339 "[%s] Handler returned error code %d\n",
342 } /*For each collection*/
343 } /*Valid Rx connection*/
346 * Advance the xstat_fs connection pointer.
350 } /*For each xstat_fs connection*/
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.
358 printf("[%s] Polling complete for probe round %d.\n",
359 rn, xstat_fs_Results.probeNum);
361 if (xstat_fs_oneShot) {
363 * One-shot execution desired. Signal our main procedure
364 * that we've finished our collection round.
367 printf("[%s] Signalling main process at 0x%x\n",
368 rn, &terminationEvent);
369 oneShotCode = LWP_SignalProcess(&terminationEvent);
372 "[%s] Error %d from LWP_SignalProcess()",
374 break; /*from the perpetual while loop*/
375 } /*One-shot execution*/
378 * Continuous execution desired. Sleep for the required
381 tv.tv_sec = xstat_fs_ProbeFreqInSecs;
384 printf("[%s] Falling asleep for %d seconds\n",
385 rn, xstat_fs_ProbeFreqInSecs);
386 code = IOMGR_Select(0, /*Num fids*/
387 0, /*Descs ready for reading*/
388 0, /*Descs ready for writing*/
389 0, /*Descs w/exceptional conditions*/
390 &tv); /*Ptr to timeout structure*/
393 "[%s] IOMGR_Select returned code %d\n",
395 } /*Continuous execution*/
401 /*------------------------------------------------------------------------
402 * [exported] xstat_fs_Init
405 * Initialize the xstat_fs module: set up Rx connections to the
406 * given set of File Servers, start up the probe and callback LWPs,
407 * and associate the routine to be called when a probe completes.
408 * Also, let it know which collections you're interested in.
411 * int a_numServers : Num. servers to connect to.
412 * struct sockaddr_in *a_socketArray : Array of server sockets.
413 * int a_ProbeFreqInSecs : Probe frequency in seconds.
414 * int (*a_ProbeHandler)() : Ptr to probe handler fcn.
415 * int a_flags : Various flags.
416 * int a_numCollections : Number of collections desired.
417 * afs_int32 *a_collIDP : Ptr to collection IDs.
421 * -2 for (at least one) connection error,
422 * LWP process creation code, if it failed,
423 * -1 for other fatal errors.
426 * *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
427 * Also, the server security object CBsecobj MUST be a static,
428 * since it has to stick around after this routine exits.
431 * Sets up just about everything.
432 *------------------------------------------------------------------------*/
434 int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
435 a_flags, a_numCollections, a_collIDP)
437 struct sockaddr_in *a_socketArray;
438 int a_ProbeFreqInSecs;
439 int (*a_ProbeHandler)();
441 int a_numCollections;
442 afs_int32 *a_collIDP;
446 static char rn[] = "xstat_fs_Init"; /*Routine name*/
447 register afs_int32 code; /*Return value*/
448 static struct rx_securityClass *CBsecobj; /*Callback security object*/
449 struct rx_securityClass *secobj; /*Client security object*/
450 struct rx_service *rxsrv_afsserver; /*Server for AFS*/
451 int arg_errfound; /*Argument error found?*/
452 int curr_srv; /*Current server idx*/
453 struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to current conn*/
454 char *hostNameFound; /*Ptr to returned host name*/
455 int conn_err; /*Connection error?*/
456 int PortToUse; /*Callback port to use*/
457 int collIDBytes; /*Num bytes in coll ID array*/
460 * If we've already been called, snicker at the bozo, gently
461 * remind him of his doubtful heritage, and return success.
463 if (xstat_fs_initflag) {
464 fprintf(stderr, "[%s] Called multiple times!\n", rn);
468 xstat_fs_initflag = 1;
471 * Check the parameters for bogosities.
474 if (a_numServers <= 0) {
475 fprintf(stderr, "[%s] Illegal number of servers: %d\n",
479 if (a_socketArray == (struct sockaddr_in *)0) {
480 fprintf(stderr, "[%s] Null server socket array argument\n", rn);
483 if (a_ProbeFreqInSecs <= 0) {
484 fprintf(stderr, "[%s] Illegal probe frequency: %d\n",
485 rn, a_ProbeFreqInSecs);
488 if (a_ProbeHandler == (int (*)())0) {
489 fprintf(stderr, "[%s] Null probe handler function argument\n",
493 if (a_numCollections <= 0) {
494 fprintf(stderr, "[%s] Illegal collection count argument: %d\n",
498 if (a_collIDP == (afs_int32 *)0) {
499 fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
506 * Record our passed-in info.
508 xstat_fs_debug = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
509 xstat_fs_oneShot = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
510 xstat_fs_numServers = a_numServers;
511 xstat_fs_Handler = a_ProbeHandler;
512 xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
513 xstat_fs_numCollections = a_numCollections;
514 collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
515 xstat_fs_collIDP = (afs_int32 *)(malloc(collIDBytes));
516 memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
517 if (xstat_fs_debug) {
518 printf("[%s] Asking for %d collection(s): ", rn, xstat_fs_numCollections);
519 for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
520 printf("%d ", *(xstat_fs_collIDP+curr_srv));
525 * Get ready in case we have to do a cleanup - basically, zero
528 code = xstat_fs_CleanupInit();
533 * Allocate the necessary data structures and initialize everything
537 (struct xstat_fs_ConnectionInfo *)
538 malloc(a_numServers * sizeof(struct xstat_fs_ConnectionInfo));
539 if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
541 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
543 (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
544 return(-1); /*No cleanup needs to be done yet*/
548 * Initialize the Rx subsystem, just in case nobody's done it.
551 printf("[%s] Initializing Rx\n", rn);
552 PortToUse = XSTAT_FS_CBPORT;
555 code = rx_Init(htons(PortToUse));
557 if (code == RX_ADDRINUSE) {
560 "[%s] Callback port %d in use, advancing\n",
565 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
571 printf("[%s] Rx initialized on port %d\n", rn, PortToUse);
574 * Create a null Rx server security object, to be used by the
577 CBsecobj = (struct rx_securityClass *)
578 rxnull_NewServerSecurityObject();
579 if (CBsecobj == (struct rx_securityClass *)0) {
581 "[%s] Can't create callback listener's security object.\n",
583 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
587 printf("[%s] Callback server security object created\n", rn);
590 * Create a null Rx client security object, to be used by the
593 secobj = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
594 if (secobj == (struct rx_securityClass *)0) {
596 "[%s] Can't create probe LWP client security object.\n",
598 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
602 printf("[%s] Probe LWP client security object created\n", rn);
604 curr_conn = xstat_fs_ConnInfo;
606 for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
608 * Copy in the socket info for the current server, resolve its
609 * printable name if possible.
611 if (xstat_fs_debug) {
612 printf("[%s] Copying in the following socket info:\n",
614 printf("[%s] IP addr 0x%lx, port %d\n", rn,
615 (a_socketArray + curr_srv)->sin_addr.s_addr,
616 (a_socketArray + curr_srv)->sin_port);
618 memcpy(&(curr_conn->skt), a_socketArray + curr_srv, sizeof(struct sockaddr_in));
621 hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
622 if (hostNameFound == (char *)0) {
624 "[%s] Can't map Internet address %lu to a string name\n",
625 rn, curr_conn->skt.sin_addr.s_addr);
626 curr_conn->hostName[0] = '\0';
629 strcpy(curr_conn->hostName, hostNameFound);
631 printf("[%s] Host name for server index %d is %s\n",
632 rn, curr_srv, curr_conn->hostName);
636 * Make an Rx connection to the current server.
639 printf("[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
640 rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
641 curr_conn->skt.sin_port);
644 rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr*/
645 curr_conn->skt.sin_port, /*Server port*/
647 secobj, /*Security obj*/
649 if (curr_conn->rxconn == (struct rx_connection *)0) {
651 "[%s] Can't create Rx connection to server '%s' (%lu)\n",
652 rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
656 printf("[%s] New connection at 0x%lx\n",
657 rn, curr_conn->rxconn);
660 * Bump the current xstat_fs connection to set up.
667 * Create the AFS callback service (listener).
670 printf("[%s] Creating AFS callback listener\n", rn);
672 rx_NewService(0, /*Use default port*/
674 "afs", /*Service name*/
675 &CBsecobj, /*Ptr to security object(s)*/
676 1, /*# of security objects*/
677 RXAFSCB_ExecuteRequest); /*Dispatcher*/
678 if (rxsrv_afsserver == (struct rx_service *)0) {
680 "[%s] Can't create callback Rx service/listener\n",
682 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
686 printf("[%s] Callback listener created\n", rn);
689 * Start up the AFS callback service.
692 printf("[%s] Starting up callback listener.\n", rn);
693 rx_StartServer(0); /*Don't donate yourself to LWP pool*/
696 * Start up the probe LWP.
699 printf("[%s] Creating the probe LWP\n", rn);
701 LWP_CreateProcess(xstat_fs_LWP, /*Function to start up*/
702 LWP_STACK_SIZE, /*Stack size in bytes*/
705 "xstat_fs Worker", /*Name to use*/
706 &probeLWP_ID); /*Returned LWP process ID*/
709 "[%s] Can't create xstat_fs LWP! Error is %d\n",
711 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
715 printf("[%s] Probe LWP process structure located at 0x%x\n",
719 * Return the final results.
729 /*------------------------------------------------------------------------
730 * [exported] xstat_fs_ForceProbeNow
733 * Wake up the probe LWP, forcing it to execute a probe immediately.
740 * Error value otherwise.
743 * The module must have been initialized.
747 *------------------------------------------------------------------------*/
749 int xstat_fs_ForceProbeNow()
751 { /*xstat_fs_ForceProbeNow*/
753 static char rn[] = "xstat_fs_ForceProbeNow"; /*Routine name*/
756 * There isn't a prayer unless we've been initialized.
758 if (!xstat_fs_initflag) {
759 fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
764 * Kick the sucker in the side.
766 IOMGR_Cancel(probeLWP_ID);
769 * We did it, so report the happy news.
773 } /*xstat_fs_ForceProbeNow*/