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