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 AFS FileServer probe facility.
14 *------------------------------------------------------------------------*/
16 #include <afsconfig.h>
17 #include <afs/param.h>
25 #include <fsprobe.h> /*Interface for this module */
26 #include <lwp.h> /*Lightweight process package */
27 #include <afs/cellconfig.h>
28 #include <afs/afsint.h>
30 #define LWP_STACK_SIZE (16 * 1024)
33 * Routines we need that don't have explicit include file definitions.
35 extern int RXAFSCB_ExecuteRequest(); /*AFS callback dispatcher */
36 extern char *hostutil_GetNameByINet(); /*Host parsing utility */
39 * Help out the linker by explicitly importing the callback routines.
41 extern afs_int32 SRXAFSCB_CallBack();
42 extern afs_int32 SRXAFSCB_InitCallBackState2();
43 extern afs_int32 SRXAFSCB_Probe();
48 int fsprobe_numServers; /*Num servers connected */
49 struct fsprobe_ConnectionInfo *fsprobe_ConnInfo; /*Ptr to connection array */
50 struct fsprobe_ProbeResults fsprobe_Results; /*Latest probe results */
51 int fsprobe_ProbeFreqInSecs; /*Probe freq. in seconds */
56 static int fsprobe_initflag = 0; /*Was init routine called? */
57 static int fsprobe_debug = 0; /*Debugging output enabled? */
58 static int (*fsprobe_Handler) (); /*Probe handler routine */
59 static PROCESS probeLWP_ID; /*Probe LWP process ID */
60 static int fsprobe_statsBytes; /*Num bytes in stats block */
61 static int fsprobe_probeOKBytes; /*Num bytes in probeOK block */
64 * We have to pass a port to Rx to start up our callback listener
65 * service, but 7001 is already taken up by the Cache Manager. So,
68 #define FSPROBE_CBPORT 7101
71 /*------------------------------------------------------------------------
72 * [private] fsprobe_CleanupInit
75 * Set up for recovery after an error in initialization (i.e.,
76 * during a call to fsprobe_Init.
83 * Error value otherwise.
86 * This routine is private to the module.
89 * Zeros out basic data structures.
90 *------------------------------------------------------------------------*/
94 { /*fsprobe_CleanupInit */
96 afs_int32 code; /*Return code from callback stubs */
97 struct rx_call *rxcall; /*Bogus param */
98 AFSCBFids *Fids_Array; /*Bogus param */
99 AFSCBs *CallBack_Array; /*Bogus param */
100 struct interfaceAddr *interfaceAddr; /*Bogus param */
102 fsprobe_ConnInfo = (struct fsprobe_ConnectionInfo *)0;
103 memset(&fsprobe_Results, 0, sizeof(struct fsprobe_ProbeResults));
105 rxcall = (struct rx_call *)0;
106 Fids_Array = (AFSCBFids *) 0;
107 CallBack_Array = (AFSCBs *) 0;
108 interfaceAddr = NULL;
110 code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
113 code = SRXAFSCB_InitCallBackState2(rxcall, interfaceAddr);
116 code = SRXAFSCB_Probe(rxcall);
119 } /*fsprobe_CleanupInit */
122 /*------------------------------------------------------------------------
123 * [exported] fsprobe_Cleanup
126 * Clean up our memory and connection state.
129 * int a_releaseMem : Should we free up malloc'ed areas?
132 * 0 on total success,
133 * -1 if the module was never initialized, or there was a problem
134 * with the fsprobe connection array.
137 * fsprobe_numServers should be properly set. We don't do anything
138 * unless fsprobe_Init() has already been called.
141 * Shuts down Rx connections gracefully, frees allocated space
143 *------------------------------------------------------------------------*/
146 fsprobe_Cleanup(a_releaseMem)
149 { /*fsprobe_Cleanup */
151 static char rn[] = "fsprobe_Cleanup"; /*Routine name */
152 int code; /*Return code */
153 int conn_idx; /*Current connection index */
154 struct fsprobe_ConnectionInfo *curr_conn; /*Ptr to fsprobe connection */
157 * Assume the best, but check the worst.
159 if (!fsprobe_initflag) {
160 fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
166 * Take care of all Rx connections first. Check to see that the
167 * server count is a legal value.
169 if (fsprobe_numServers <= 0) {
171 "[%s] Illegal number of servers to clean up (fsprobe_numServers = %d)\n",
172 rn, fsprobe_numServers);
175 if (fsprobe_ConnInfo != (struct fsprobe_ConnectionInfo *)0) {
177 * The fsprobe connection structure array exists. Go through it
178 * and close up any Rx connections it holds.
180 curr_conn = fsprobe_ConnInfo;
181 for (conn_idx = 0; conn_idx < fsprobe_numServers; conn_idx++) {
182 if (curr_conn->rxconn != (struct rx_connection *)0) {
183 rx_DestroyConnection(curr_conn->rxconn);
184 curr_conn->rxconn = (struct rx_connection *)0;
186 if (curr_conn->rxVolconn != (struct rx_connection *)0) {
187 rx_DestroyConnection(curr_conn->rxVolconn);
188 curr_conn->rxVolconn = (struct rx_connection *)0;
191 } /*for each fsprobe connection */
192 } /*fsprobe connection structure exists */
193 } /*Legal number of servers */
196 * Now, release all the space we've allocated, if asked to.
199 if (fsprobe_ConnInfo != (struct fsprobe_ConnectionInfo *)0)
200 free(fsprobe_ConnInfo);
201 if (fsprobe_Results.stats != NULL)
202 free(fsprobe_Results.stats);
203 if (fsprobe_Results.probeOK != (int *)0)
204 free(fsprobe_Results.probeOK);
208 * Return the news, whatever it is.
212 } /*fsprobe_Cleanup */
214 /*------------------------------------------------------------------------
215 * [private] fsprobe_LWP
218 * This LWP iterates over the server connections and gathers up
219 * the desired statistics from each one on a regular basis. When
220 * the sweep is done, the associated handler function is called
221 * to process the new data.
230 * Started by fsprobe_Init(), uses global sturctures.
234 *------------------------------------------------------------------------*/
239 static char rn[] = "fsprobe_LWP"; /*Routine name */
240 register afs_int32 code; /*Results of calls */
241 struct timeval tv; /*Time structure */
242 int conn_idx; /*Connection index */
243 struct fsprobe_ConnectionInfo *curr_conn; /*Current connection */
244 struct ProbeViceStatistics *curr_stats; /*Current stats region */
245 int *curr_probeOK; /*Current probeOK field */
246 ViceStatistics64 stats64; /*Current stats region */
247 stats64.ViceStatistics64_val = (afs_uint64 *)malloc(STATS64_VERSION *
249 while (1) { /*Service loop */
251 * Iterate through the server connections, gathering data.
252 * Don't forget to bump the probe count and zero the statistics
253 * areas before calling the servers.
257 "[%s] Waking up, collecting data from %d connected servers\n",
258 rn, fsprobe_numServers);
259 curr_conn = fsprobe_ConnInfo;
260 curr_stats = fsprobe_Results.stats;
261 curr_probeOK = fsprobe_Results.probeOK;
262 fsprobe_Results.probeNum++;
263 memset(fsprobe_Results.stats, 0, fsprobe_statsBytes);
264 memset(fsprobe_Results.probeOK, 0, fsprobe_probeOKBytes);
266 for (conn_idx = 0; conn_idx < fsprobe_numServers; conn_idx++) {
268 * Grab the statistics for the current FileServer, if the
269 * connection is valid.
272 fprintf(stderr, "[%s] Contacting server %s\n", rn,
273 curr_conn->hostName);
274 if (curr_conn->rxconn != (struct rx_connection *)0) {
277 "[%s] Connection valid, calling RXAFS_GetStatistics\n",
280 RXAFS_GetStatistics64(curr_conn->rxconn, STATS64_VERSION, &stats64);
281 if (*curr_probeOK == RXGEN_OPCODE)
283 RXAFS_GetStatistics(curr_conn->rxconn, curr_stats);
284 else if (*curr_probeOK == 0) {
285 curr_stats->CurrentTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_CURRENTTIME]);
286 curr_stats->BootTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_BOOTTIME]);
287 curr_stats->StartTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_STARTTIME]);
288 curr_stats->CurrentConnections = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_CURRENTCONNECTIONS]);
289 curr_stats->TotalFetchs = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_TOTALFETCHES]);
290 curr_stats->TotalStores = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_TOTALSTORES]);
291 curr_stats->WorkStations = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_WORKSTATIONS]);
295 /*Valid Rx connection */
297 * Call the Volume Server too to get additional stats
300 fprintf(stderr, "[%s] Contacting volume server %s\n", rn,
301 curr_conn->hostName);
302 if (curr_conn->rxVolconn != (struct rx_connection *)0) {
305 struct diskPartition partition;
306 struct diskPartition64 *partition64p =
307 (struct diskPartition64 *)malloc(sizeof(struct diskPartition64));
311 "[%s] Connection valid, calling RXAFS_GetStatistics\n",
313 for (i = 0; i < curr_conn->partCnt; i++) {
314 if (curr_conn->partList.partFlags[i] & PARTVALID) {
315 MapPartIdIntoName(curr_conn->partList.partId[i],
318 AFSVolPartitionInfo64(curr_conn->rxVolconn, pname,
322 curr_stats->Disk[i].BlocksAvailable =
323 RoundInt64ToInt31(partition64p->free);
324 curr_stats->Disk[i].TotalBlocks =
325 RoundInt64ToInt31(partition64p->minFree);
326 strcpy(curr_stats->Disk[i].Name, pname);
328 if (code == RXGEN_OPCODE) {
330 AFSVolPartitionInfo(curr_conn->rxVolconn,
333 curr_stats->Disk[i].BlocksAvailable =
335 curr_stats->Disk[i].TotalBlocks =
337 strcpy(curr_stats->Disk[i].Name, pname);
342 "Could not get information on server %s partition %s\n",
343 curr_conn->hostName, pname);
352 * Advance the fsprobe connection pointer & stats pointer.
358 } /*For each fsprobe connection */
361 * All (valid) connections have been probed. Now, call the
362 * associated handler function. The handler does not take
363 * any explicit parameters, rather gets to the goodies via
364 * some of the objects exported by this module.
368 "[%s] Polling complete, calling associated handler routine.\n",
370 code = fsprobe_Handler();
372 fprintf(stderr, "[%s] Handler routine returned error code %d\n",
376 * Fall asleep for the prescribed number of seconds.
378 tv.tv_sec = fsprobe_ProbeFreqInSecs;
381 fprintf(stderr, "[%s] Falling asleep for %d seconds\n", rn,
382 fsprobe_ProbeFreqInSecs);
383 code = IOMGR_Select(0, /*Num fids */
384 0, /*Descriptors ready for reading */
385 0, /*Descriptors ready for writing */
386 0, /*Descriptors w/exceptional conditions */
387 &tv); /*Ptr to timeout structure */
389 fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn, code);
391 free(stats64.ViceStatistics64_val);
394 /*list all the partitions on <aserver> */
395 static int newvolserver = 0;
396 XListPartitions(aconn, ptrPartList, cntp)
397 struct rx_connection *aconn;
398 struct partList *ptrPartList;
402 struct partEntries partEnts;
403 register int i, j = 0, code;
406 if (newvolserver == 1) {
407 for (i = 0; i < 26; i++)
408 partIds.partIds[i] = -1;
410 code = AFSVolListPartitions(aconn, &partIds);
412 for (i = 0; i < 26; i++) {
413 if ((partIds.partIds[i]) != -1) {
414 ptrPartList->partId[j] = partIds.partIds[i];
415 ptrPartList->partFlags[j] = PARTVALID;
418 ptrPartList->partFlags[i] = 0;
424 partEnts.partEntries_len = 0;
425 partEnts.partEntries_val = NULL;
426 code = AFSVolXListPartitions(aconn, &partEnts);
428 if (code == RXGEN_OPCODE) {
429 newvolserver = 1; /* Doesn't support new interface */
436 *cntp = partEnts.partEntries_len;
437 if (*cntp > VOLMAXPARTS) {
439 "Warning: number of partitions on the server too high %d (process only %d)\n",
443 for (i = 0; i < *cntp; i++) {
444 ptrPartList->partId[i] = partEnts.partEntries_val[i];
445 ptrPartList->partFlags[i] = PARTVALID;
447 free(partEnts.partEntries_val);
452 "Could not fetch the list of partitions from the server\n");
457 /*------------------------------------------------------------------------
458 * [exported] fsprobe_Init
461 * Initialize the fsprobe module: set up Rx connections to the
462 * given set of servers, start up the probe and callback LWPs,
463 * and associate the routine to be called when a probe completes.
466 * int a_numServers : Num. servers to connect to.
467 * struct sockaddr_in *a_socketArray : Array of server sockets.
468 * int a_ProbeFreqInSecs : Probe frequency in seconds.
469 * int (*a_ProbeHandler)() : Ptr to probe handler fcn.
470 * int a_debug; : Turn debugging output on?
474 * -2 for (at least one) connection error,
475 * LWP process creation code, if it failed,
476 * -1 for other fatal errors.
479 * *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
480 * Also, the server security object CBsecobj MUST be a static,
481 * since it has to stick around after this routine exits.
484 * Sets up just about everything.
485 *------------------------------------------------------------------------*/
488 fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
491 struct sockaddr_in *a_socketArray;
492 int a_ProbeFreqInSecs;
493 int (*a_ProbeHandler) ();
498 static char rn[] = "fsprobe_Init"; /*Routine name */
499 register afs_int32 code; /*Return value */
500 static struct rx_securityClass *CBsecobj; /*Callback security object */
501 struct rx_securityClass *secobj; /*Client security object */
502 struct rx_service *rxsrv_afsserver; /*Server for AFS */
503 int arg_errfound; /*Argument error found? */
504 int curr_srv; /*Current server idx */
505 struct fsprobe_ConnectionInfo *curr_conn; /*Ptr to current conn */
506 char *hostNameFound; /*Ptr to returned host name */
507 int conn_err; /*Connection error? */
508 int PortToUse; /*Callback port to use */
511 * If we've already been called, snicker at the bozo, gently
512 * remind him of his doubtful heritage, and return success.
514 if (fsprobe_initflag) {
515 fprintf(stderr, "[%s] Called multiple times!\n", rn);
518 fsprobe_initflag = 1;
521 * Check the parameters for bogosities.
524 if (a_numServers <= 0) {
525 fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
529 if (a_socketArray == (struct sockaddr_in *)0) {
530 fprintf(stderr, "[%s] Null server socket array argument\n", rn);
533 if (a_ProbeFreqInSecs <= 0) {
534 fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
538 if (a_ProbeHandler == (int (*)())0) {
539 fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
546 * Record our passed-in info.
548 fsprobe_debug = a_debug;
549 fsprobe_numServers = a_numServers;
550 fsprobe_Handler = a_ProbeHandler;
551 fsprobe_ProbeFreqInSecs = a_ProbeFreqInSecs;
554 * Get ready in case we have to do a cleanup - basically, zero
557 fsprobe_CleanupInit();
560 * Allocate the necessary data structures and initialize everything
563 fsprobe_ConnInfo = (struct fsprobe_ConnectionInfo *)
564 malloc(a_numServers * sizeof(struct fsprobe_ConnectionInfo));
565 if (fsprobe_ConnInfo == (struct fsprobe_ConnectionInfo *)0) {
567 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
569 (a_numServers * sizeof(struct fsprobe_ConnectionInfo)));
570 return (-1); /*No cleanup needs to be done yet */
574 fprintf(stderr, "[%s] fsprobe_ConnInfo allocated (%d bytes)\n", rn,
575 a_numServers * sizeof(struct fsprobe_ConnectionInfo));
578 fsprobe_statsBytes = a_numServers * sizeof(struct ProbeViceStatistics);
579 fsprobe_Results.stats = (struct ProbeViceStatistics *)
580 malloc(fsprobe_statsBytes);
581 if (fsprobe_Results.stats == NULL) {
583 "[%s] Can't allocate %d statistics structs (%d bytes)\n", rn,
584 a_numServers, fsprobe_statsBytes);
585 fsprobe_Cleanup(1); /*Delete already-malloc'ed areas */
587 } else if (fsprobe_debug)
588 fprintf(stderr, "[%s] fsprobe_Results.stats allocated (%d bytes)\n",
589 rn, fsprobe_statsBytes);
591 fsprobe_probeOKBytes = a_numServers * sizeof(int);
592 fsprobe_Results.probeOK = (int *)malloc(fsprobe_probeOKBytes);
593 if (fsprobe_Results.probeOK == (int *)0) {
595 "[%s] Can't allocate %d probeOK array entries (%d bytes)\n",
596 rn, a_numServers, fsprobe_probeOKBytes);
597 fsprobe_Cleanup(1); /*Delete already-malloc'ed areas */
599 } else if (fsprobe_debug)
600 fprintf(stderr, "[%s] fsprobe_Results.probeOK allocated (%d bytes)\n",
601 rn, fsprobe_probeOKBytes);
603 fsprobe_Results.probeNum = 0;
604 fsprobe_Results.probeTime = 0;
605 memset(fsprobe_Results.stats, 0,
606 (a_numServers * sizeof(struct ProbeViceStatistics)));
609 * Initialize the Rx subsystem, just in case nobody's done it.
612 fprintf(stderr, "[%s] Initializing Rx\n", rn);
613 PortToUse = FSPROBE_CBPORT;
615 code = rx_Init(htons(PortToUse));
617 if (code == RX_ADDRINUSE) {
620 "[%s] Callback port %d in use, advancing\n", rn,
624 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
630 fprintf(stderr, "[%s] Rx initialized on port %d\n", rn, PortToUse);
633 * Create a null Rx server security object, to be used by the
636 CBsecobj = rxnull_NewServerSecurityObject();
637 if (CBsecobj == (struct rx_securityClass *)0) {
639 "[%s] Can't create null security object for the callback listener.\n",
641 fsprobe_Cleanup(1); /*Delete already-malloc'ed areas */
645 fprintf(stderr, "[%s] Callback server security object created\n", rn);
648 * Create a null Rx client security object, to be used by the
651 secobj = rxnull_NewClientSecurityObject();
652 if (secobj == (struct rx_securityClass *)0) {
654 "[%s] Can't create client security object for probe LWP.\n",
656 fsprobe_Cleanup(1); /*Delete already-malloc'ed areas */
660 fprintf(stderr, "[%s] Probe LWP client security object created\n",
663 curr_conn = fsprobe_ConnInfo;
665 for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
667 * Copy in the socket info for the current server, resolve its
668 * printable name if possible.
671 fprintf(stderr, "[%s] Copying in the following socket info:\n",
673 fprintf(stderr, "[%s] IP addr 0x%lx, port %d\n", rn,
674 (a_socketArray + curr_srv)->sin_addr.s_addr,
675 (a_socketArray + curr_srv)->sin_port);
677 memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
678 sizeof(struct sockaddr_in));
681 hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
682 if (hostNameFound == NULL) {
684 "[%s] Can't map Internet address %lu to a string name\n",
685 rn, curr_conn->skt.sin_addr.s_addr);
686 curr_conn->hostName[0] = '\0';
688 strcpy(curr_conn->hostName, hostNameFound);
690 fprintf(stderr, "[%s] Host name for server index %d is %s\n",
691 rn, curr_srv, curr_conn->hostName);
695 * Make an Rx connection to the current server.
699 "[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
700 rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
701 curr_conn->skt.sin_port);
702 curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
703 curr_conn->skt.sin_port, /*Server port */
704 1, /*AFS service num */
705 secobj, /*Security object */
706 0); /*Number of above */
707 if (curr_conn->rxconn == (struct rx_connection *)0) {
709 "[%s] Can't create Rx connection to server %s (%lu)\n",
710 rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
714 fprintf(stderr, "[%s] New connection at 0x%lx\n", rn,
718 * Make an Rx connection to the current volume server.
722 "[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
723 rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
725 curr_conn->rxVolconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
726 htons(AFSCONF_VOLUMEPORT), /*Volume Server port */
727 VOLSERVICE_ID, /*AFS service num */
728 secobj, /*Security object */
729 0); /*Number of above */
730 if (curr_conn->rxVolconn == (struct rx_connection *)0) {
732 "[%s] Can't create Rx connection to volume server %s (%lu)\n",
733 rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
738 memset(&curr_conn->partList, 0, sizeof(struct partList));
739 curr_conn->partCnt = 0;
740 i = XListPartitions(curr_conn->rxVolconn, &curr_conn->partList,
743 curr_conn->partCnt = cnt;
747 fprintf(stderr, "[%s] New connection at 0x%lx\n", rn,
748 curr_conn->rxVolconn);
752 * Bump the current fsprobe connection to set up.
759 * Create the AFS callback service (listener).
762 fprintf(stderr, "[%s] Creating AFS callback listener\n", rn);
763 rxsrv_afsserver = rx_NewService(0, /*Use default port */
765 "afs", /*Service name */
766 &CBsecobj, /*Ptr to security object(s) */
767 1, /*Number of security objects */
768 RXAFSCB_ExecuteRequest); /*Dispatcher */
769 if (rxsrv_afsserver == (struct rx_service *)0) {
770 fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
772 fsprobe_Cleanup(1); /*Delete already-malloc'ed areas */
776 fprintf(stderr, "[%s] Callback listener created\n", rn);
779 * Start up the AFS callback service.
782 fprintf(stderr, "[%s] Starting up callback listener.\n", rn);
783 rx_StartServer(0 /*Don't donate yourself to LWP pool */ );
786 * Start up the probe LWP.
789 fprintf(stderr, "[%s] Creating the probe LWP\n", rn);
790 code = LWP_CreateProcess(fsprobe_LWP, /*Function to start up */
791 LWP_STACK_SIZE, /*Stack size in bytes */
793 (void *)0, /*Parameters */
794 "fsprobe Worker", /*Name to use */
795 &probeLWP_ID); /*Returned LWP process ID */
797 fprintf(stderr, "[%s] Can't create fsprobe LWP! Error is %d\n", rn,
799 fsprobe_Cleanup(1); /*Delete already-malloc'ed areas */
803 fprintf(stderr, "[%s] Probe LWP process structure located at 0x%x\n",
808 * Do I need to do this?
811 fprintf(stderr, "[%s] Calling osi_Wakeup()\n", rn);
812 osi_Wakeup(&rxsrv_afsserver); /*Wake up anyone waiting for it */
816 * Return the final results.
826 /*------------------------------------------------------------------------
827 * [exported] fsprobe_ForceProbeNow
830 * Wake up the probe LWP, forcing it to execute a probe immediately.
837 * Error value otherwise.
840 * The module must have been initialized.
844 *------------------------------------------------------------------------*/
847 fsprobe_ForceProbeNow()
848 { /*fsprobe_ForceProbeNow */
850 static char rn[] = "fsprobe_ForceProbeNow"; /*Routine name */
853 * There isn't a prayer unless we've been initialized.
855 if (!fsprobe_initflag) {
856 fprintf(stderr, "[%s] Must call fsprobe_Init first!\n", rn);
861 * Kick the sucker in the side.
863 IOMGR_Cancel(probeLWP_ID);
866 * We did it, so report the happy news.
870 } /*fsprobe_ForceProbeNow */