Commit | Line | Data |
---|---|---|
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 | */ | |
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 */ | |
39 | ||
40 | afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS]; /*Buffer for collected data */ | |
41 | ||
42 | /* | |
43 | * Private globals. | |
44 | */ | |
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 */ | |
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 | ||
76 | static int | |
77 | xstat_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 | ||
135 | int | |
136 | xstat_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 | ||
216 | static void * | |
217 | xstat_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 | ||
400 | int | |
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) | |
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 | ||
686 | int | |
687 | xstat_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 | */ | |
728 | int | |
729 | xstat_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 | } |