opr: Assert opr_cv_timedwait return codes
[openafs.git] / src / fsprobe / fsprobe.c
index 863a043..7690992 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
-
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
+#include <roken.h>
 
-#include <fsprobe.h>           /*Interface for this module */
-#include <lwp.h>               /*Lightweight process package */
+#include <pthread.h>
 #include <afs/cellconfig.h>
+#include <afs/afsint.h>
+#include <afs/afsutil.h>
+#include <afs/volser.h>
+#include <afs/volser_prototypes.h>
+#define FSINT_COMMON_XG
+#include <afs/afscbint.h>
 
-#define LWP_STACK_SIZE (16 * 1024)
-
-/*
- * Routines we need that don't have explicit include file definitions.
- */
-extern int RXAFSCB_ExecuteRequest();   /*AFS callback dispatcher */
-extern char *hostutil_GetNameByINet(); /*Host parsing utility */
-
-/*
- * Help out the linker by explicitly importing the callback routines.
- */
-extern afs_int32 SRXAFSCB_CallBack();
-extern afs_int32 SRXAFSCB_InitCallBackState2();
-extern afs_int32 SRXAFSCB_Probe();
+#include "fsprobe.h"           /*Interface for this module */
 
 /*
  * Exported variables.
@@ -60,18 +42,12 @@ int fsprobe_ProbeFreqInSecs;        /*Probe freq. in seconds */
  */
 static int fsprobe_initflag = 0;       /*Was init routine called? */
 static int fsprobe_debug = 0;  /*Debugging output enabled? */
-static int (*fsprobe_Handler) ();      /*Probe handler routine */
-static PROCESS probeLWP_ID;    /*Probe LWP process ID */
+static int (*fsprobe_Handler) (void);  /*Probe handler routine */
+static pthread_t fsprobe_thread;       /*Probe thread */
 static int fsprobe_statsBytes; /*Num bytes in stats block */
 static int fsprobe_probeOKBytes;       /*Num bytes in probeOK block */
-
-/*
- * We have to pass a port to Rx to start up our callback listener
- * service, but 7001 is already taken up by the Cache Manager.  So,
- * we make up our own.
- */
-#define FSPROBE_CBPORT 7101
-
+static opr_mutex_t fsprobe_force_lock; /*Lock to force probe */
+static opr_cv_t fsprobe_force_cv;      /*Condvar to force probe */
 
 /*------------------------------------------------------------------------
  * [private] fsprobe_CleanupInit
@@ -95,7 +71,7 @@ static int fsprobe_probeOKBytes;      /*Num bytes in probeOK block */
  *------------------------------------------------------------------------*/
 
 static int
-fsprobe_CleanupInit()
+fsprobe_CleanupInit(void)
 {                              /*fsprobe_CleanupInit */
 
     afs_int32 code;            /*Return code from callback stubs */
@@ -148,9 +124,7 @@ fsprobe_CleanupInit()
  *------------------------------------------------------------------------*/
 
 int
-fsprobe_Cleanup(a_releaseMem)
-     int a_releaseMem;
-
+fsprobe_Cleanup(int a_releaseMem)
 {                              /*fsprobe_Cleanup */
 
     static char rn[] = "fsprobe_Cleanup";      /*Routine name */
@@ -220,7 +194,7 @@ fsprobe_Cleanup(a_releaseMem)
  * [private] fsprobe_LWP
  *
  * Description:
- *     This LWP iterates over the server connections and gathers up
+ *     This thread iterates over the server connections and gathers up
  *     the desired statistics from each one on a regular basis.  When
  *     the sweep is done, the associated handler function is called
  *     to process the new data.
@@ -237,18 +211,21 @@ fsprobe_Cleanup(a_releaseMem)
  * Side Effects:
  *     As advertised.
  *------------------------------------------------------------------------*/
-static void
-fsprobe_LWP()
+static void *
+fsprobe_LWP(void *unused)
 {                              /*fsprobe_LWP */
 
     static char rn[] = "fsprobe_LWP";  /*Routine name */
-    register afs_int32 code;   /*Results of calls */
+    afs_int32 code;    /*Results of calls */
     struct timeval tv;         /*Time structure */
+    struct timespec wait;      /*Time to wait */
     int conn_idx;              /*Connection index */
     struct fsprobe_ConnectionInfo *curr_conn;  /*Current connection */
     struct ProbeViceStatistics *curr_stats;    /*Current stats region */
     int *curr_probeOK;         /*Current probeOK field */
-
+    ViceStatistics64 stats64;      /*Current stats region */
+    stats64.ViceStatistics64_val = malloc(STATS64_VERSION *
+                                         sizeof(afs_uint64));
     while (1) {                        /*Service loop */
        /*
         * Iterate through the server connections, gathering data.
@@ -280,8 +257,19 @@ fsprobe_LWP()
                            "[%s] Connection valid, calling RXAFS_GetStatistics\n",
                            rn);
                *curr_probeOK =
-                   RXAFS_GetStatistics(curr_conn->rxconn, curr_stats);
-
+                   RXAFS_GetStatistics64(curr_conn->rxconn, STATS64_VERSION, &stats64);
+               if (*curr_probeOK == RXGEN_OPCODE)
+                   *curr_probeOK =
+                       RXAFS_GetStatistics(curr_conn->rxconn, (ViceStatistics *)curr_stats);
+               else if (*curr_probeOK == 0) {
+                   curr_stats->CurrentTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_CURRENTTIME]);
+                   curr_stats->BootTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_BOOTTIME]);
+                   curr_stats->StartTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_STARTTIME]);
+                   curr_stats->CurrentConnections = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_CURRENTCONNECTIONS]);
+                   curr_stats->TotalFetchs = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_TOTALFETCHES]);
+                   curr_stats->TotalStores = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_TOTALSTORES]);
+                   curr_stats->WorkStations = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_WORKSTATIONS]);
+               }
            }
 
            /*Valid Rx connection */
@@ -295,6 +283,8 @@ fsprobe_LWP()
                int i, code;
                char pname[10];
                struct diskPartition partition;
+               struct diskPartition64 *partition64p =
+                   malloc(sizeof(struct diskPartition64));
 
                if (fsprobe_debug)
                    fprintf(stderr,
@@ -305,22 +295,36 @@ fsprobe_LWP()
                        MapPartIdIntoName(curr_conn->partList.partId[i],
                                          pname);
                        code =
-                           AFSVolPartitionInfo(curr_conn->rxVolconn, pname,
-                                               &partition);
+                           AFSVolPartitionInfo64(curr_conn->rxVolconn, pname,
+                                                 partition64p);
+
+                       if (!code) {
+                           curr_stats->Disk[i].BlocksAvailable =
+                               RoundInt64ToInt31(partition64p->free);
+                           curr_stats->Disk[i].TotalBlocks =
+                               RoundInt64ToInt31(partition64p->minFree);
+                           strcpy(curr_stats->Disk[i].Name, pname);
+                       }
+                       if (code == RXGEN_OPCODE) {
+                           code =
+                               AFSVolPartitionInfo(curr_conn->rxVolconn,
+                                                   pname, &partition);
+                           if (!code) {
+                               curr_stats->Disk[i].BlocksAvailable =
+                                   partition.free;
+                               curr_stats->Disk[i].TotalBlocks =
+                                   partition.minFree;
+                               strcpy(curr_stats->Disk[i].Name, pname);
+                           }
+                       }
                        if (code) {
                            fprintf(stderr,
                                    "Could not get information on server %s partition %s\n",
                                    curr_conn->hostName, pname);
-                       } else {
-                           curr_stats->Disk[i].BlocksAvailable =
-                               partition.free;
-                           curr_stats->Disk[i].TotalBlocks =
-                               partition.minFree;
-                           strcpy(curr_stats->Disk[i].Name, pname);
                        }
                    }
-
                }
+               free(partition64p);
            }
 
 
@@ -349,34 +353,30 @@ fsprobe_LWP()
                    rn, code);
 
        /*
-        * Fall asleep for the prescribed number of seconds.
+        * Fall asleep for the prescribed number of seconds or wakeup
+        * sooner if forced.
         */
-       tv.tv_sec = fsprobe_ProbeFreqInSecs;
-       tv.tv_usec = 0;
-       if (fsprobe_debug)
-           fprintf(stderr, "[%s] Falling asleep for %d seconds\n", rn,
-                   fsprobe_ProbeFreqInSecs);
-       code = IOMGR_Select(0,  /*Num fids */
-                           0,  /*Descriptors ready for reading */
-                           0,  /*Descriptors ready for writing */
-                           0,  /*Descriptors w/exceptional conditions */
-                           &tv);       /*Ptr to timeout structure */
-       if (code)
-           fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn, code);
+       gettimeofday(&tv, NULL);
+       wait.tv_sec = tv.tv_sec + fsprobe_ProbeFreqInSecs;
+       wait.tv_nsec = tv.tv_usec * 1000;
+       opr_mutex_enter(&fsprobe_force_lock);
+       code = opr_cv_timedwait(&fsprobe_force_cv, &fsprobe_force_lock, &wait);
+       opr_mutex_exit(&fsprobe_force_lock);
     }                          /*Service loop */
-
+    AFS_UNREACHED(free(stats64.ViceStatistics64_val));
+    AFS_UNREACHED(return(NULL));
 }                              /*fsprobe_LWP */
 
 /*list all the partitions on <aserver> */
 static int newvolserver = 0;
-XListPartitions(aconn, ptrPartList, cntp)
-     struct rx_connection *aconn;
-     struct partList *ptrPartList;
-     afs_int32 *cntp;
+
+int
+XListPartitions(struct rx_connection *aconn, struct partList *ptrPartList,
+               afs_int32 *cntp)
 {
     struct pIDs partIds;
     struct partEntries partEnts;
-    register int i, j = 0, code;
+    int i, j = 0, code;
 
     *cntp = 0;
     if (newvolserver == 1) {
@@ -435,7 +435,7 @@ XListPartitions(aconn, ptrPartList, cntp)
  *
  * Description:
  *     Initialize the fsprobe module: set up Rx connections to the
- *     given set of servers, start up the probe and callback LWPs,
+ *     given set of servers, start up the probe and callback threads,
  *     and associate the routine to be called when a probe completes.
  *
  * Arguments:
@@ -448,7 +448,7 @@ XListPartitions(aconn, ptrPartList, cntp)
  * Returns:
  *     0 on success,
  *     -2 for (at least one) connection error,
- *     LWP process creation code, if it failed,
+ *     thread process creation code, if it failed,
  *     -1 for other fatal errors.
  *
  * Environment:
@@ -461,18 +461,13 @@ XListPartitions(aconn, ptrPartList, cntp)
  *------------------------------------------------------------------------*/
 
 int
-fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
-            a_debug)
-     int a_numServers;
-     struct sockaddr_in *a_socketArray;
-     int a_ProbeFreqInSecs;
-     int (*a_ProbeHandler) ();
-     int a_debug;
-
+fsprobe_Init(int a_numServers, struct sockaddr_in *a_socketArray,
+            int a_ProbeFreqInSecs, int (*a_ProbeHandler)(void),
+            int a_debug)
 {                              /*fsprobe_Init */
 
     static char rn[] = "fsprobe_Init"; /*Routine name */
-    register afs_int32 code;   /*Return value */
+    afs_int32 code;    /*Return value */
     static struct rx_securityClass *CBsecobj;  /*Callback security object */
     struct rx_securityClass *secobj;   /*Client security object */
     struct rx_service *rxsrv_afsserver;        /*Server for AFS */
@@ -481,7 +476,6 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
     struct fsprobe_ConnectionInfo *curr_conn;  /*Ptr to current conn */
     char *hostNameFound;       /*Ptr to returned host name */
     int conn_err;              /*Connection error? */
-    int PortToUse;             /*Callback port to use */
 
     /*
      * If we've already been called, snicker at the bozo, gently
@@ -493,6 +487,9 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
     } else
        fsprobe_initflag = 1;
 
+    opr_mutex_init(&fsprobe_force_lock);
+    opr_cv_init(&fsprobe_force_cv);
+
     /*
      * Check the parameters for bogosities.
      */
@@ -511,7 +508,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
                a_ProbeFreqInSecs);
        arg_errfound = 1;
     }
-    if (a_ProbeHandler == (int (*)())0) {
+    if (a_ProbeHandler == NULL) {
        fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
        arg_errfound = 1;
     }
@@ -540,16 +537,11 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
        malloc(a_numServers * sizeof(struct fsprobe_ConnectionInfo));
     if (fsprobe_ConnInfo == (struct fsprobe_ConnectionInfo *)0) {
        fprintf(stderr,
-               "[%s] Can't allocate %d connection info structs (%d bytes)\n",
+               "[%s] Can't allocate %d connection info structs (%"AFS_SIZET_FMT" bytes)\n",
                rn, a_numServers,
                (a_numServers * sizeof(struct fsprobe_ConnectionInfo)));
        return (-1);            /*No cleanup needs to be done yet */
     }
-#if 0
-    else
-       fprintf(stderr, "[%s] fsprobe_ConnInfo allocated (%d bytes)\n", rn,
-               a_numServers * sizeof(struct fsprobe_ConnectionInfo));
-#endif /* 0 */
 
     fsprobe_statsBytes = a_numServers * sizeof(struct ProbeViceStatistics);
     fsprobe_Results.stats = (struct ProbeViceStatistics *)
@@ -565,7 +557,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
                rn, fsprobe_statsBytes);
 
     fsprobe_probeOKBytes = a_numServers * sizeof(int);
-    fsprobe_Results.probeOK = (int *)malloc(fsprobe_probeOKBytes);
+    fsprobe_Results.probeOK = malloc(fsprobe_probeOKBytes);
     if (fsprobe_Results.probeOK == (int *)0) {
        fprintf(stderr,
                "[%s] Can't allocate %d probeOK array entries (%d bytes)\n",
@@ -586,24 +578,13 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
      */
     if (fsprobe_debug)
        fprintf(stderr, "[%s] Initializing Rx\n", rn);
-    PortToUse = FSPROBE_CBPORT;
-    do {
-       code = rx_Init(htons(PortToUse));
-       if (code) {
-           if (code == RX_ADDRINUSE) {
-               if (fsprobe_debug)
-                   fprintf(stderr,
-                           "[%s] Callback port %d in use, advancing\n", rn,
-                           PortToUse);
-               PortToUse++;
-           } else {
-               fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
-               return (-1);
-           }
-       }
-    } while (code);
+    code = rx_Init(0);
+    if (code) {
+       fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
+       return (-1);
+    }
     if (fsprobe_debug)
-       fprintf(stderr, "[%s] Rx initialized on port %d\n", rn, PortToUse);
+       fprintf(stderr, "[%s] Rx initialized.\n", rn);
 
     /*
      * Create a null Rx server security object, to be used by the
@@ -622,18 +603,18 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
 
     /*
      * Create a null Rx client security object, to be used by the
-     * probe LWP.
+     * probe thread.
      */
     secobj = rxnull_NewClientSecurityObject();
     if (secobj == (struct rx_securityClass *)0) {
        fprintf(stderr,
-               "[%s] Can't create client security object for probe LWP.\n",
+               "[%s] Can't create client security object for probe thread.\n",
                rn);
        fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
        return (-1);
     }
     if (fsprobe_debug)
-       fprintf(stderr, "[%s] Probe LWP client security object created\n",
+       fprintf(stderr, "[%s] Probe thread client security object created\n",
                rn);
 
     curr_conn = fsprobe_ConnInfo;
@@ -646,7 +627,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
        if (fsprobe_debug) {
            fprintf(stderr, "[%s] Copying in the following socket info:\n",
                    rn);
-           fprintf(stderr, "[%s] IP addr 0x%lx, port %d\n", rn,
+           fprintf(stderr, "[%s] IP addr 0x%x, port %d\n", rn,
                    (a_socketArray + curr_srv)->sin_addr.s_addr,
                    (a_socketArray + curr_srv)->sin_port);
        }
@@ -657,7 +638,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
            hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
        if (hostNameFound == NULL) {
            fprintf(stderr,
-                   "[%s] Can't map Internet address %lu to a string name\n",
+                   "[%s] Can't map Internet address %u to a string name\n",
                    rn, curr_conn->skt.sin_addr.s_addr);
            curr_conn->hostName[0] = '\0';
        } else {
@@ -672,7 +653,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
         */
        if (fsprobe_debug)
            fprintf(stderr,
-                   "[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
+                   "[%s] Connecting to srv idx %d, IP addr 0x%x, port %d, service 1\n",
                    rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
                    curr_conn->skt.sin_port);
        curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr,    /*Server addr */
@@ -682,12 +663,12 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
                                             0);        /*Number of above */
        if (curr_conn->rxconn == (struct rx_connection *)0) {
            fprintf(stderr,
-                   "[%s] Can't create Rx connection to server %s (%lu)\n",
+                   "[%s] Can't create Rx connection to server %s (%u)\n",
                    rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
            conn_err = 1;
        }
        if (fsprobe_debug)
-           fprintf(stderr, "[%s] New connection at 0x%lx\n", rn,
+           fprintf(stderr, "[%s] New connection at %p\n", rn,
                    curr_conn->rxconn);
 
        /*
@@ -695,7 +676,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
         */
        if (fsprobe_debug)
            fprintf(stderr,
-                   "[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
+                   "[%s] Connecting to srv idx %d, IP addr 0x%x, port %d, service 1\n",
                    rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
                    htons(7005));
        curr_conn->rxVolconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
@@ -705,7 +686,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
                                                0);     /*Number of above */
        if (curr_conn->rxVolconn == (struct rx_connection *)0) {
            fprintf(stderr,
-                   "[%s] Can't create Rx connection to volume server %s (%lu)\n",
+                   "[%s] Can't create Rx connection to volume server %s (%u)\n",
                    rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
            conn_err = 1;
        } else {
@@ -720,7 +701,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
            }
        }
        if (fsprobe_debug)
-           fprintf(stderr, "[%s] New connection at 0x%lx\n", rn,
+           fprintf(stderr, "[%s] New connection at %p\n", rn,
                    curr_conn->rxVolconn);
 
 
@@ -756,37 +737,20 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
      */
     if (fsprobe_debug)
        fprintf(stderr, "[%s] Starting up callback listener.\n", rn);
-    rx_StartServer(0 /*Don't donate yourself to LWP pool */ );
+    rx_StartServer(0 /*Don't donate yourself to thread pool */ );
 
     /*
-     * Start up the probe LWP.
+     * Start up the probe thread.
      */
     if (fsprobe_debug)
-       fprintf(stderr, "[%s] Creating the probe LWP\n", rn);
-    code = LWP_CreateProcess(fsprobe_LWP,      /*Function to start up */
-                            LWP_STACK_SIZE,    /*Stack size in bytes */
-                            1, /*Priority */
-                            (void *)0, /*Parameters */
-                            "fsprobe Worker",  /*Name to use */
-                            &probeLWP_ID);     /*Returned LWP process ID */
+       fprintf(stderr, "[%s] Creating the probe thread\n", rn);
+    code = pthread_create(&fsprobe_thread, NULL, fsprobe_LWP, NULL);
     if (code) {
-       fprintf(stderr, "[%s] Can't create fsprobe LWP!  Error is %d\n", rn,
+       fprintf(stderr, "[%s] Can't create fsprobe thread!  Error is %d\n", rn,
                code);
        fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
        return (code);
     }
-    if (fsprobe_debug)
-       fprintf(stderr, "[%s] Probe LWP process structure located at 0x%x\n",
-               rn, probeLWP_ID);
-
-#if 0
-    /*
-     * Do I need to do this?
-     */
-    if (fsprobe_debug)
-       fprintf(stderr, "[%s] Calling osi_Wakeup()\n", rn);
-    osi_Wakeup(&rxsrv_afsserver);      /*Wake up anyone waiting for it */
-#endif /* 0 */
 
     /*
      * Return the final results.
@@ -803,7 +767,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
  * [exported] fsprobe_ForceProbeNow
  *
  * Description:
- *     Wake up the probe LWP, forcing it to execute a probe immediately.
+ *     Wake up the probe thread, forcing it to execute a probe immediately.
  *
  * Arguments:
  *     None.
@@ -820,7 +784,7 @@ fsprobe_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
  *------------------------------------------------------------------------*/
 
 int
-fsprobe_ForceProbeNow()
+fsprobe_ForceProbeNow(void)
 {                              /*fsprobe_ForceProbeNow */
 
     static char rn[] = "fsprobe_ForceProbeNow";        /*Routine name */
@@ -836,7 +800,9 @@ fsprobe_ForceProbeNow()
     /*
      * Kick the sucker in the side.
      */
-    IOMGR_Cancel(probeLWP_ID);
+    opr_mutex_enter(&fsprobe_force_lock);
+    opr_cv_signal(&fsprobe_force_cv);
+    opr_mutex_exit(&fsprobe_force_lock);
 
     /*
      * We did it, so report the happy news.
@@ -844,3 +810,44 @@ fsprobe_ForceProbeNow()
     return (0);
 
 }                              /*fsprobe_ForceProbeNow */
+
+/*------------------------------------------------------------------------
+ * [exported] fsprobe_Wait
+ *
+ * Description:
+ *     Wait for the collection to complete.
+ *
+ * Arguments:
+ *    int sleep_secs : time to wait in seconds. 0 means sleep forever.
+ *
+ * Returns:
+ *     0 on success,
+ *     Error value otherwise.
+ *
+ * Environment:
+ *     The module must have been initialized.
+ *
+ * Side Effects:
+ *     As advertised.
+ *------------------------------------------------------------------------*/
+int
+fsprobe_Wait(int sleep_secs)
+{
+    int code;
+    struct timeval tv;
+
+    if (sleep_secs == 0) {
+       while (1) {
+           tv.tv_sec = 30;
+           tv.tv_usec = 0;
+           code = select(0, 0, 0, 0, &tv);
+           if (code < 0)
+               break;
+       }
+    } else {
+       tv.tv_sec = sleep_secs;
+       tv.tv_usec = 0;
+       code = select(0, 0, 0, 0, &tv);
+    }
+    return code;
+}