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 #include <afs/afsutil.h>
26 #include <afs/afscbint.h>
28 #define LWP_STACK_SIZE (16 * 1024)
33 int xstat_fs_numServers
; /*Num connected servers */
34 struct xstat_fs_ConnectionInfo
35 *xstat_fs_ConnInfo
; /*Ptr to connection array */
36 int numCollections
; /*Number of data collections */
37 struct xstat_fs_ProbeResults xstat_fs_Results
; /*Latest probe results */
38 char terminationEvent
; /*One-shot termination event */
40 afs_int32 xstat_fsData
[AFS_MAX_XSTAT_LONGS
]; /*Buffer for collected data */
45 static int xstat_fs_ProbeFreqInSecs
; /*Probe freq. in seconds */
46 static int xstat_fs_initflag
= 0; /*Was init routine called? */
47 static int xstat_fs_debug
= 0; /*Debugging output enabled? */
48 static int xstat_fs_oneShot
= 0; /*One-shot operation? */
49 static int (*xstat_fs_Handler
) (void); /*Probe handler routine */
50 static PROCESS probeLWP_ID
; /*Probe LWP process ID */
51 static int xstat_fs_numCollections
; /*Number of desired collections */
52 static afs_int32
*xstat_fs_collIDP
; /*Ptr to collection IDs desired */
55 /*------------------------------------------------------------------------
56 * [private] xstat_fs_CleanupInit
59 * Set up for recovery after an error in initialization (i.e.,
60 * during a call to xstat_fs_Init.
67 * Error value otherwise.
70 * This routine is private to the module.
73 * Zeros out basic data structures.
74 *------------------------------------------------------------------------*/
77 xstat_fs_CleanupInit(void)
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 */
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;
93 rxcall
= (struct rx_call
*)0;
94 Fids_Array
= (AFSCBFids
*) 0;
95 CallBack_Array
= (AFSCBs
*) 0;
98 * Call each of the callback routines our module provides (in
99 * xstat_fs_callback.c) to make sure they're all there.
101 code
= SRXAFSCB_CallBack(rxcall
, Fids_Array
, CallBack_Array
);
104 code
= SRXAFSCB_InitCallBackState3(rxcall
, (afsUUID
*) 0);
107 code
= SRXAFSCB_Probe(rxcall
);
112 /*------------------------------------------------------------------------
113 * [exported] xstat_fs_Cleanup
116 * Clean up our memory and connection state.
119 * int a_releaseMem : Should we free up malloc'ed areas?
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.
127 * xstat_fs_numServers should be properly set. We don't do anything
128 * unless xstat_fs_Init() has already been called.
131 * Shuts down Rx connections gracefully, frees allocated space
133 *------------------------------------------------------------------------*/
136 xstat_fs_Cleanup(int a_releaseMem
)
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 */
144 * Assume the best, but check the worst.
146 if (!xstat_fs_initflag
) {
147 fprintf(stderr
, "[%s] Refused; module not initialized\n", rn
);
153 * Take care of all Rx connections first. Check to see that the
154 * server count is a legal value.
156 if (xstat_fs_numServers
<= 0) {
158 "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
159 rn
, xstat_fs_numServers
);
162 if (xstat_fs_ConnInfo
!= (struct xstat_fs_ConnectionInfo
*)0) {
164 * The xstat_fs connection structure array exists. Go through
165 * it and close up any Rx connections it holds.
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;
174 } /*for each xstat_fs connection */
175 } /*xstat_fs connection structure exists */
176 } /*Legal number of servers */
179 * If asked to, release the space we've allocated.
182 if (xstat_fs_ConnInfo
!= (struct xstat_fs_ConnectionInfo
*)0)
183 free(xstat_fs_ConnInfo
);
187 * Return the news, whatever it is.
193 /*------------------------------------------------------------------------
194 * [private] xstat_fs_LWP
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.
209 * Started by xstat_fs_Init(), uses global structures and the
210 * global private xstat_fs_oneShot variable.
213 * Nothing interesting.
214 *------------------------------------------------------------------------*/
217 xstat_fs_LWP(void *unused
)
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 */
231 * Set up some numbers we'll need.
233 clientVersionNumber
= AFS_XSTAT_VERSION
;
235 while (1) { /*Service loop */
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.
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
++;
247 for (conn_idx
= 0; conn_idx
< xstat_fs_numServers
; conn_idx
++) {
249 * Grab the statistics for the current File Server, if the
250 * connection is valid.
253 printf("[%s] Getting collections from File Server '%s'\n", rn
,
254 curr_conn
->hostName
);
255 if (curr_conn
->rxconn
!= (struct rx_connection
*)0) {
257 printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
260 currCollIDP
= xstat_fs_collIDP
;
261 for (numColls
= 0; numColls
< xstat_fs_numCollections
;
262 numColls
++, currCollIDP
++) {
264 * Initialize the per-probe values.
267 printf("[%s] Asking for data collection %d\n", rn
,
269 xstat_fs_Results
.collectionNumber
= *currCollIDP
;
270 xstat_fs_Results
.data
.AFS_CollData_len
=
272 memset(xstat_fs_Results
.data
.AFS_CollData_val
, 0,
273 AFS_MAX_XSTAT_LONGS
* 4);
275 xstat_fs_Results
.connP
= curr_conn
;
277 if (xstat_fs_debug
) {
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
);
289 xstat_fs_Results
.probeOK
=
290 RXAFS_GetXStats(curr_conn
->rxconn
,
291 clientVersionNumber
, *currCollIDP
,
293 &(xstat_fs_Results
.probeTime
),
294 &(xstat_fs_Results
.data
));
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.
303 printf("[%s] Calling handler routine.\n", rn
);
304 code
= xstat_fs_Handler();
307 "[%s] Handler returned error code %d\n", rn
,
310 } /*For each collection */
313 /*Valid Rx connection */
315 * Advance the xstat_fs connection pointer.
319 } /*For each xstat_fs connection */
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.
327 printf("[%s] Polling complete for probe round %d.\n", rn
,
328 xstat_fs_Results
.probeNum
);
330 if (xstat_fs_oneShot
) {
332 * One-shot execution desired. Signal our main procedure
333 * that we've finished our collection round.
336 printf("[%s] Signalling main process at %" AFS_PTR_FMT
"\n", rn
,
338 oneShotCode
= LWP_SignalProcess(&terminationEvent
);
340 fprintf(stderr
, "[%s] Error %d from LWP_SignalProcess()", rn
,
342 break; /*from the perpetual while loop */
343 } /*One-shot execution */
346 * Continuous execution desired. Sleep for the required
349 tv
.tv_sec
= xstat_fs_ProbeFreqInSecs
;
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 */
360 fprintf(stderr
, "[%s] IOMGR_Select returned code %d\n", rn
,
362 } /*Continuous execution */
367 /*------------------------------------------------------------------------
368 * [exported] xstat_fs_Init
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.
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.
387 * -2 for (at least one) connection error,
388 * LWP process creation code, if it failed,
389 * -1 for other fatal errors.
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.
397 * Sets up just about everything.
398 *------------------------------------------------------------------------*/
401 xstat_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
)
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 */
419 * If we've already been called, snicker at the bozo, gently
420 * remind him of his doubtful heritage, and return success.
422 if (xstat_fs_initflag
) {
423 fprintf(stderr
, "[%s] Called multiple times!\n", rn
);
426 xstat_fs_initflag
= 1;
429 * Check the parameters for bogosities.
432 if (a_numServers
<= 0) {
433 fprintf(stderr
, "[%s] Illegal number of servers: %d\n", rn
,
437 if (a_socketArray
== (struct sockaddr_in
*)0) {
438 fprintf(stderr
, "[%s] Null server socket array argument\n", rn
);
441 if (a_ProbeFreqInSecs
<= 0) {
442 fprintf(stderr
, "[%s] Illegal probe frequency: %d\n", rn
,
446 if (a_ProbeHandler
== (int (*)())0) {
447 fprintf(stderr
, "[%s] Null probe handler function argument\n", rn
);
450 if (a_numCollections
<= 0) {
451 fprintf(stderr
, "[%s] Illegal collection count argument: %d\n", rn
,
455 if (a_collIDP
== NULL
) {
456 fprintf(stderr
, "[%s] Null collection ID array argument\n", rn
);
463 * Record our passed-in info.
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
));
483 * Get ready in case we have to do a cleanup - basically, zero
486 code
= xstat_fs_CleanupInit();
491 * Allocate the necessary data structures and initialize everything
494 xstat_fs_ConnInfo
= malloc(a_numServers
495 * sizeof(struct xstat_fs_ConnectionInfo
));
496 if (xstat_fs_ConnInfo
== (struct xstat_fs_ConnectionInfo
*)0) {
498 "[%s] Can't allocate %d connection info structs (%" AFS_SIZET_FMT
" bytes)\n",
500 (a_numServers
* sizeof(struct xstat_fs_ConnectionInfo
)));
501 return (-1); /*No cleanup needs to be done yet */
505 * Initialize the Rx subsystem, just in case nobody's done it.
508 printf("[%s] Initializing Rx\n", rn
);
511 fprintf(stderr
, "[%s] Fatal error in rx_Init()\n", rn
);
515 printf("[%s] Rx initialized\n", rn
);
518 * Create a null Rx server security object, to be used by the
521 CBsecobj
= (struct rx_securityClass
*)
522 rxnull_NewServerSecurityObject();
523 if (CBsecobj
== (struct rx_securityClass
*)0) {
525 "[%s] Can't create callback listener's security object.\n",
527 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
531 printf("[%s] Callback server security object created\n", rn
);
534 * Create a null Rx client security object, to be used by the
537 secobj
= rxnull_NewClientSecurityObject();
538 if (secobj
== (struct rx_securityClass
*)0) {
540 "[%s] Can't create probe LWP client security object.\n", rn
);
541 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
545 printf("[%s] Probe LWP client security object created\n", rn
);
547 curr_conn
= xstat_fs_ConnInfo
;
549 for (curr_srv
= 0; curr_srv
< a_numServers
; curr_srv
++) {
551 * Copy in the socket info for the current server, resolve its
552 * printable name if possible.
554 if (xstat_fs_debug
) {
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
));
561 memcpy(&(curr_conn
->skt
), a_socketArray
+ curr_srv
,
562 sizeof(struct sockaddr_in
));
565 hostutil_GetNameByINet(curr_conn
->skt
.sin_addr
.s_addr
);
566 if (hostNameFound
== NULL
) {
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';
572 strcpy(curr_conn
->hostName
, hostNameFound
);
574 printf("[%s] Host name for server index %d is %s\n", rn
,
575 curr_srv
, curr_conn
->hostName
);
579 * Make an Rx connection to the current server.
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
));
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 */
592 if (curr_conn
->rxconn
== (struct rx_connection
*)0) {
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
));
599 printf("[%s] New connection at %" AFS_PTR_FMT
"\n", rn
, curr_conn
->rxconn
);
602 * Bump the current xstat_fs connection to set up.
609 * Create the AFS callback service (listener).
612 printf("[%s] Creating AFS callback listener\n", rn
);
613 rxsrv_afsserver
= rx_NewService(0, /*Use default port */
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",
622 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
626 printf("[%s] Callback listener created\n", rn
);
629 * Start up the AFS callback service.
632 printf("[%s] Starting up callback listener.\n", rn
);
633 rx_StartServer(0); /*Don't donate yourself to LWP pool */
636 * Start up the probe LWP.
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 */
643 (void *)0, /*Parameters */
644 "xstat_fs Worker", /*Name to use */
645 &probeLWP_ID
); /*Returned LWP process ID */
647 fprintf(stderr
, "[%s] Can't create xstat_fs LWP! Error is %d\n", rn
,
649 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
653 printf("[%s] Probe LWP process structure located at %" AFS_PTR_FMT
"\n", rn
,
657 * Return the final results.
666 /*------------------------------------------------------------------------
667 * [exported] xstat_fs_ForceProbeNow
670 * Wake up the probe LWP, forcing it to execute a probe immediately.
677 * Error value otherwise.
680 * The module must have been initialized.
684 *------------------------------------------------------------------------*/
687 xstat_fs_ForceProbeNow(void)
689 static char rn
[] = "xstat_fs_ForceProbeNow"; /*Routine name */
692 * There isn't a prayer unless we've been initialized.
694 if (!xstat_fs_initflag
) {
695 fprintf(stderr
, "[%s] Must call xstat_fs_Init first!\n", rn
);
700 * Kick the sucker in the side.
702 IOMGR_Cancel(probeLWP_ID
);
705 * We did it, so report the happy news.
711 * Fill the xstat full perf data structure from the data collection array.
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.
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.
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
726 * @return 0 on success
729 xstat_fs_DecodeFullPerfStats(struct fs_stats_FullPerfStats
**aout
,
732 struct fs_stats_FullPerfStats
*abuf
)
736 int snbo
= -2; /* detected remote site has network-byte ordering */
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) */
742 #define DECODE_TV(t) \
744 if (alen == XSTAT_FPS_SMALL) { \
746 (t).tv_usec = *p++; \
752 (t).tv_usec = *p++; \
756 (t).tv_usec = *p++; \
762 if (alen
!= XSTAT_FPS_SMALL
&& alen
!= XSTAT_FPS_LARGE
) {
763 return -1; /* unrecognized size */
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
;
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) {
779 } else if (epoch
[0] != 0 && epoch
[1] == 0) {
782 return -2; /* failed to detect server word ordering */
786 if (alen
== XSTAT_FPS_LEN
&& alen
== XSTAT_FPS_LARGE
787 #if defined(WORDS_BIGENDIAN)
789 #else /* WORDS_BIGENDIAN */
791 #endif /* WORDS_BIGENDIAN */
793 /* Same size and order; no decoding needed. */
794 *aout
= (struct fs_stats_FullPerfStats
*)ain
;
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"));
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
);
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
;
818 td
->numSuccesses
= *p
++;
819 DECODE_TV(td
->sumTime
);
820 DECODE_TV(td
->sqrTime
);
821 DECODE_TV(td
->minTime
);
822 DECODE_TV(td
->maxTime
);
824 for (i
= 0; i
< FS_STATS_NUM_XFER_OPS
; i
++) {
825 struct fs_stats_xferData
*xd
= abuf
->det
.xferOpTimes
+ i
;
827 xd
->numSuccesses
= *p
++;
828 DECODE_TV(xd
->sumTime
);
829 DECODE_TV(xd
->sqrTime
);
830 DECODE_TV(xd
->minTime
);
831 DECODE_TV(xd
->maxTime
);
835 memcpy((void *)xd
->count
, (void *)p
,
836 sizeof(afs_int32
) * FS_STATS_NUM_XFER_BUCKETS
);
837 p
+= FS_STATS_NUM_XFER_BUCKETS
;