Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / sfs_c_mnt.c
diff --git a/TBBT/trace_play/sfs_c_mnt.c b/TBBT/trace_play/sfs_c_mnt.c
new file mode 100644 (file)
index 0000000..8f60387
--- /dev/null
@@ -0,0 +1,573 @@
+#ifndef lint
+static char sfs_c_mntSid[] = "@(#)sfs_c_mnt.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_mnt.c ---------------------
+ *
+ *      The sfs child.  Routines to handle mount points.
+ *
+ *.Exported_Routines
+ *     void init_mount_point(int, char *, CLIENT *)
+ *
+ *.Local_Routines
+ *     int pseudo_mount(char *, int, char *, CLIENT *)
+ *
+ *.Revision_History
+ *     2-Jul-92        Teelucksingh    Added code for OSF/1
+ *                                     use of getmntinfo().
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include <fcntl.h>
+
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+
+struct hostent   *Server_hostent;
+
+/*
+ * -------------------------  Constants  -------------------------
+ */
+
+/*
+ * Number of times a load generating process will retry amount.
+ * Each load generating process also picks a client shifted
+ * mount start time, and executes a backoff on retry time on
+ * failure.
+ */
+#define NUMBER_MOUNT_RETRIES   10
+
+/*
+ * -------------------------  External Definitions  -------------------------
+ */
+
+/* forward definitions for local routines */
+CLIENT * lad_getmnt_hand(char *);
+static int pseudo_mount(char *, int, char *, CLIENT *);
+
+/*
+ * Mounts are retried when an RPC timeout occurs, in the mainline
+ * code. They are not retried by the RPC clnt_call routine, as the
+ * timeout values are set now.
+ */
+static struct timeval Mount_timer = {  10,  0 };
+
+
+/*
+ * -------------------------  Mount Point Routines  -------------------------
+ */
+
+
+/*
+ * mount the testdir 'dirnum' under the parent directory 'parentdir'.
+ */
+void
+init_mount_point(
+    int                dirnum,
+    char *     parentdir,
+    CLIENT *   mount_client_ptr)
+{
+    char       pnt_dir[SFS_MAXPATHLEN];      /* test dir component name */
+    char       testdirname[SFS_MAXPATHLEN];  /* test dir component name */
+    char       export_fsname[SFS_MAXPATHLEN]; /* "host:path" exported fs */
+    sfs_fh_type file_handle;
+    char       *fh_ptr;
+    char       *cp;
+    int                ret;
+    sfs_fh_data *fh_datap, *Ex_fh_datap;
+
+    fh_datap= calloc(1,sizeof(sfs_fh_data));
+    (void) memset((char *)fh_datap, 0, sizeof(sfs_fh_data));
+    (void) memset((char *)&file_handle, 0, sizeof(file_handle));
+    file_handle.fh_data = fh_datap;
+    file_handle.dir = &Export_dir;
+
+    Ex_fh_datap = (sfs_fh_data *) calloc(1,sizeof(sfs_fh_data));
+    Export_dir.fh_data = Ex_fh_datap;
+
+    (void) strcpy(pnt_dir, parentdir);
+
+    cp = strchr(pnt_dir, ':');
+    if (cp == NULL) {
+       (void) fprintf(stderr, "%s: malformed fsname %s\n",
+                       sfs_Myname, parentdir);
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(86);
+    }
+
+    *cp++ = '\0';
+
+    /*
+     * Now we have the parent directory in the form:
+     *         host:host_path
+     *
+     * First we get the file handle for parent directory
+     *
+     * Verify that the server is running the correct version of
+     * the NFS protocol specification and then proceed to get
+     * the exported fh from the server.
+     */
+    (void) strcpy(testdirname, pnt_dir);
+    (void) strcat(testdirname, ":");
+    (void) strcat(testdirname, cp);
+    (void) strcpy(export_fsname, testdirname);
+
+    if (nfs_version == NFS_VERSION) {
+       (void) memset((char *) &Export_dir.fh2, '\0', sizeof (Export_dir.fh2));
+       fh_ptr = (char *)&Export_dir.fh2;
+    } else if (nfs_version == NFS_V3) {
+       (void) memset((char *) &Export_dir.fh3, '\0', sizeof (Export_dir.fh3));
+       fh_ptr = (char *)&Export_dir.fh3;
+    }
+
+    ret = pseudo_mount(export_fsname, nfs_version,
+                                       fh_ptr, mount_client_ptr);
+    if (ret < 0) {
+       if (ret == -2)  {
+           (void) fprintf(stderr,
+               "%s: NFS Protocol Version %lu verification failed.\n",
+               sfs_Myname, (uint32_t)nfs_version);
+       }
+       else  {
+           (void) fprintf(stderr, "%s: can't pseudo mount %s\n",
+                       sfs_Myname, export_fsname);
+       }
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(87);
+    }
+
+    /*
+     * Setup initial state of export directory
+     */
+    Export_dir.state = Exists;
+    (void) strcpy(Export_dir.file_name, testdirname);
+    Export_dir.dir = &Export_dir;
+
+#ifndef RFS
+    /*
+     * Check for and create the client directory. Stat it first, if not
+     * there then mkdir, if that fails with EEXIST we lost the race but
+     * that's OK.
+     */
+    if (Validate) {
+       (void) sprintf(testdirname, "%s", "validatedir");
+    } else {
+       (void) sprintf(testdirname, "CL%d", Client_num);
+    }
+
+    if ((ret = lad_lookup(&file_handle, testdirname)) == -1) {
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(88);
+    }
+
+    if (ret == 1) {
+       /*
+        * Directory doesn't exist so create it
+        * if it already exists thats OK
+        */
+        if ((ret = lad_mkdir(&file_handle, testdirname)) == -1) {
+           if (!Validate)
+               (void) generic_kill(0, SIGINT);
+           exit(89);
+        }
+       /*
+        * If someone else created this out from underneath us simply
+        * lookup the result and continue on.
+        */
+        if (ret != 0 && (ret = lad_lookup(&file_handle, testdirname)) == -1) {
+           if (!Validate)
+               (void) generic_kill(0, SIGINT);
+           exit(90);
+        }
+    }
+
+    /* testdirname now exists, verify it is a directory and writeable */
+    if (!fh_isdir(&file_handle) ||
+               (check_fh_access(&file_handle) == -1)) {
+       (void) fprintf(stderr,
+               "%s: %s is either not a directory or not accessible\n",
+                       sfs_Myname, testdirname);
+       if (!Validate)
+           (void) generic_kill(0, SIGINT);
+       exit(91);
+    }
+
+    /*
+     * logically chdir into CL directory
+     */
+   /*  Export_dir = file_handle; Implied bcopy here */
+    (void) memmove(&Export_dir,&file_handle,sizeof(sfs_fh_type));
+    Export_dir.fh_data = Ex_fh_datap;
+    (void ) memmove(Export_dir.fh_data, file_handle.fh_data, 
+                       sizeof(sfs_fh_data));
+    (void) memset((char *)&file_handle, 0, sizeof(file_handle));
+    (void) memset((char *)fh_datap, 0, sizeof(sfs_fh_data));
+    file_handle.fh_data = fh_datap;
+    file_handle.dir = &Export_dir;
+
+    /*
+     * Validation only occurs one directory deep so we can exit early
+     */
+    if (Validate)
+        return;
+
+    (void) sprintf(testdirname, "testdir%d", dirnum);
+
+    if ((ret = lad_lookup(&file_handle, testdirname)) == -1) {
+       (void) generic_kill(0, SIGINT);
+       exit(92);
+    }
+
+    if (ret == 1) {
+       /*
+        * Directory doesn't exist so create it
+        */
+        if (lad_mkdir(&file_handle, testdirname) != 0) {
+           (void) fprintf(stderr, "%s: Unable to create %s\n",
+                       sfs_Myname, testdirname);
+           (void) generic_kill(0, SIGINT);
+           exit(93);
+        }
+    }
+
+    /* testdirname now exists, verify it is a directory and writeable */
+    if (!fh_isdir(&file_handle) ||
+               (check_fh_access(&file_handle) == -1)) {
+       (void) fprintf(stderr,
+               "%s: %s is either not a directory or not accessible\n",
+                       sfs_Myname, testdirname);
+       (void) generic_kill(0, SIGINT);
+       exit(94);
+    }
+
+    /*
+     * logically chdir into testdir directory
+     */
+    /* Export_dir = file_handle;*/
+    (void) memmove(&Export_dir, &file_handle, sizeof(struct sfs_fh_type));
+    Export_dir.fh_data = Ex_fh_datap; /* Put pointer back */
+    (void) memmove(Export_dir.fh_data, file_handle.fh_data, sizeof
+                       (sfs_fh_data));
+#endif
+} /* init_mount_point */
+
+/*
+ * Get the filehandle for 'mount_fsname', and return it
+ * Returns NULL for error ... not mounted || no NFS client.
+ *
+ * Children should only call this routine 1 time.
+ */
+CLIENT *
+lad_getmnt_hand(
+    char *             mount_point)
+{
+    char               mnt_pnt[SFS_MAXPATHLEN];    /* working buffer */
+    char               host[SFS_MAXPATHLEN];     /* host with exported fs */
+    static struct hostent      hp;
+    struct hostent     *thp;
+    CLIENT             *mount_client_ptr;      /* Mount client handle */
+    char               *cp;
+    int                        rpc_result;             /* rpc call result */
+    uint32_t           mount_vers = 0;
+
+    /*
+     * If the mount point is of the form host:path just use the explicit
+     * name instead of grovelling through the mount table.
+     */
+    (void) strcpy(mnt_pnt, mount_point);
+    cp = strchr(mnt_pnt, ':');
+    if (cp == NULL) {
+       (void) fprintf(stderr, "%s: malformed fsname %s\n",
+                       sfs_Myname, mount_point);
+       return(NULL);
+    }
+
+    *cp++ = '\0';
+    (void) strcpy(host, mnt_pnt);
+
+    /* Verify NFS Version */
+    rpc_result = callrpc(host,
+                       (uint32_t) NFS_PROGRAM,
+                       (uint32_t) nfs_version,
+                       (uint32_t) NFSPROC_NULL, (xdrproc_t) xdr_void,
+                       (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL);
+    if (rpc_result != 0) {
+        clnt_perrno((enum clnt_stat)rpc_result);
+        (void) fprintf(stderr,
+"\nUnable to contact NFS server %s.\n", host);
+        (void) fprintf(stderr,
+"Verify NFS server daemon supporting version %u is running and\n",
+               (uint32_t)nfs_version);
+        (void) fprintf(stderr, "registered with the portmapper.\n");
+       return(NULL);
+    }
+
+    /* Get host's address */
+    if ((thp = gethostbyname(host)) == NULL) {
+       /* Failure may be due to yellow pages, try again */
+       if ((thp = gethostbyname(host)) == NULL) {
+           (void) fprintf(stderr, "%s: %s not in hosts database\n",
+                           sfs_Myname, host);
+           return(NULL);
+       }
+    }
+
+    hp = *thp;
+    Server_hostent = &hp;
+
+    if (nfs_version == NFS_VERSION)
+       mount_vers = MOUNTVERS;
+    if (nfs_version == NFS_V3)
+       mount_vers = MOUNTVER3;
+
+    mount_client_ptr = lad_clnt_create(0, Server_hostent,
+                                        (uint32_t) MOUNTPROG,
+                                        mount_vers,
+                                        RPC_ANYSOCK, &Mount_timer);
+                
+
+    if (mount_client_ptr == ((CLIENT*) NULL)) {
+       (void) fprintf(stderr,
+                       "%s: portmap/mountd %s server not responding",
+                       sfs_Myname, mount_point);
+       return(NULL);
+    }
+
+    mount_client_ptr->cl_auth = authunix_create_default();
+    return (mount_client_ptr);
+
+} /* lad_getmnt_hand */
+
+
+/*
+ * Get the filehandle for 'mount_fsname', and return it in 'fh_ptr'.
+ * Returns 0 for OK, -1 for error ... not mounted || no NFS client.
+ *
+ * Children should only call this routine 1 time.
+ */
+static int
+pseudo_mount(
+    char *             mount_fsname,
+    int                        version,
+    char *             fh_ptr,
+    CLIENT *           mount_client_ptr)
+{
+    char *             host_ptr;               /* host with exported fs */
+    char *             path_ptr;               /* ptr to path for RPC */
+
+    struct fhstatus    fhs;                    /* status of mountd call */
+    nfs_fh3 *          fh_ptr3;
+    mountres3          mntres3;                /* status of mountd call */
+    char *             cp;
+    enum clnt_stat     rpc_stat;
+    int                        tries = 0;              /* Number of retries */
+                               /* Space by 200ms intervals. */
+    int                        pacesleep = Child_num * 200;
+
+    /* Parse the fsname for host and path strings */
+    cp = strchr(mount_fsname, ':');
+
+    if (cp == NULL) {
+       (void) fprintf(stderr, "%s: malformed fsname %s\n",
+                       sfs_Myname, mount_fsname);
+       return(-1);
+    }
+
+    *cp++ = '\0';
+    host_ptr = mount_fsname;
+    path_ptr = cp;
+
+    /* Check host's address */
+    if (gethostbyname(host_ptr) == NULL) {
+       /* Failure may be due to yellow pages, try again */
+       if (gethostbyname(host_ptr) == NULL) {
+           (void) fprintf(stderr, "%s: %s not in hosts database\n",
+                           sfs_Myname, host_ptr);
+           return(-1);
+       }
+    }
+
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: mount clnt_call\n", sfs_Myname);
+    }
+
+    /* get fhandle of remote path from host's mountd */
+
+retry_mount:
+    /*
+     * Many children on many clients hammer a server with
+     * mounts. Crude fix is to pace them. Some run rule interpretations
+     * are to have *many* children on each client. This can
+     * cause problems.
+     */
+    (void) msec_sleep(pacesleep);
+
+    if (version == NFS_VERSION) {
+       (void) memset((char *) &fhs, '\0', sizeof (fhs));
+       rpc_stat = clnt_call(mount_client_ptr, MOUNTPROC_MNT, xdr_path,
+                       (char *) &path_ptr,xdr_fhstatus,(char *) &fhs,
+                       Mount_timer);
+    } else if (version == NFS_V3) {
+       (void) memset((char *) &mntres3, '\0', sizeof (mntres3));
+       rpc_stat = clnt_call(mount_client_ptr, MOUNTPROC_MNT, xdr_dirpath,
+                       (char *) &path_ptr, xdr_mntres3, (char *) &mntres3,
+                       Mount_timer);
+    } else
+       rpc_stat = RPC_PROGVERSMISMATCH;
+
+    errno = 0;
+    if (rpc_stat != RPC_SUCCESS) {
+
+       switch (rpc_stat) {
+
+           case RPC_TIMEDOUT:
+               errno = ETIMEDOUT;
+               (void) fprintf(stderr,
+                   "%s: mounting %s:%s server not responding: %s (%d)\n",
+                           sfs_Myname, host_ptr, path_ptr,
+                           strerror(errno), errno);
+               if (tries++ < NUMBER_MOUNT_RETRIES) {
+                   /* Randomize the backoff on retry */
+                   pacesleep = pacesleep + (sfs_random() % 2000);
+                   goto retry_mount;
+               }
+               break;
+
+
+           case RPC_PMAPFAILURE:
+               errno = ENETDOWN;       /* reasonable error */
+               (void) fprintf(stderr,
+                           "%s: mounting %s portmap call failed: %s (%d)\n",
+                           sfs_Myname, host_ptr, strerror(errno), errno);
+               break;
+
+           case RPC_PROGNOTREGISTERED:
+               errno = ENETDOWN;       /* reasonable error */
+               (void) fprintf(stderr,
+                           "%s: mounting %s nfsd not registered: %s (%d)\n",
+                           sfs_Myname, host_ptr, strerror(errno), errno);
+               break;
+
+           case RPC_AUTHERROR:
+               errno = EACCES;
+               (void) fprintf(stderr,
+                       "%s: mounting %s authentication failed: %s (%d)\n",
+                       sfs_Myname, host_ptr, strerror(errno), errno);
+               break;
+
+           default:
+               errno = ENETDOWN;       /* reasonable error */
+               (void) fprintf(stderr,
+                           "%s: mounting %s:%s failed: %s (%d)\n",
+                           sfs_Myname, host_ptr, path_ptr,
+                           strerror(errno), errno);
+               break;
+       }
+
+       clnt_perror(mount_client_ptr, "");
+       return(-1);
+
+    } /* MOUNTPROC_MNT call failed */
+
+    if (version == NFS_VERSION) {
+       if (fhs.fhs_status != 0) {
+           if (fhs.fhs_status == EACCES) {
+               (void) fprintf(stderr, "%s: mounting %s:%s - access denied\n",
+                          sfs_Myname, host_ptr, path_ptr);
+           } else {
+               (void) fprintf(stderr,
+                           "%s: mounting %s:%s - bad fh status %d\n ",
+                           sfs_Myname, host_ptr, path_ptr, fhs.fhs_status);
+           }
+           return(-1);
+       } /* bad fhs status */
+
+       /*
+        * fill in the caller's file handle
+        */
+       (void) memmove(fh_ptr, (char *) &fhs.fhs_fh, NFS_FHSIZE);
+
+    } else if (version == NFS_V3) {
+
+       if (mntres3.fhs_status != MNT_OK) {
+           if (mntres3.fhs_status == MNT3ERR_ACCES) {
+               (void) fprintf(stderr, "%s: mounting %s:%s - access denied\n",
+                          sfs_Myname, host_ptr, path_ptr);
+           } else {
+               (void) fprintf(stderr,
+                           "%s: mounting %s:%s - bad fh status %d\n ",
+                   sfs_Myname, host_ptr, path_ptr, mntres3.fhs_status);
+           }
+           return(-1);
+       } /* bad fhs status */
+
+       /*
+        * fill in the caller's file handle
+        * space pointed by fhandle3_val is allocated through xdr_mntres3
+        */
+       fh_ptr3 = (nfs_fh3 *)fh_ptr;
+       fh_ptr3->fh3_length = mntres3.mntres3_u.mntinfo.fhandle.fhandle3_len;
+       (void) memmove((char *) fh_ptr3->fh3_u.data,
+                       (char *) mntres3.mntres3_u.mntinfo.fhandle.fhandle3_val,
+                       fh_ptr3->fh3_length);
+    }
+
+    return(0);
+
+} /* pseudo_mount */
+
+
+/* sfs_c_mnt.c */