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