Home | History | Annotate | Download | only in common
      1  5184  ek110237 /*
      2  5184  ek110237  * CDDL HEADER START
      3  5184  ek110237  *
      4  5184  ek110237  * The contents of this file are subject to the terms of the
      5  5184  ek110237  * Common Development and Distribution License (the "License").
      6  5184  ek110237  * You may not use this file except in compliance with the License.
      7  5184  ek110237  *
      8  5184  ek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  5184  ek110237  * or http://www.opensolaris.org/os/licensing.
     10  5184  ek110237  * See the License for the specific language governing permissions
     11  5184  ek110237  * and limitations under the License.
     12  5184  ek110237  *
     13  5184  ek110237  * When distributing Covered Code, include this CDDL HEADER in each
     14  5184  ek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  5184  ek110237  * If applicable, add the following below this CDDL HEADER, with the
     16  5184  ek110237  * fields enclosed by brackets "[]" replaced with your own identifying
     17  5184  ek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  5184  ek110237  *
     19  5184  ek110237  * CDDL HEADER END
     20  5184  ek110237  */
     21  5184  ek110237 /*
     22  8615    Andrew  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  5184  ek110237  * Use is subject to license terms.
     24  6613  ek110237  *
     25  6613  ek110237  * Portions Copyright 2008 Denis Cheng
     26  5184  ek110237  */
     27  5184  ek110237 
     28  5184  ek110237 #include "config.h"
     29  5184  ek110237 
     30  5184  ek110237 #include <sys/types.h>
     31  5184  ek110237 #ifdef HAVE_SYS_ASYNCH_H
     32  5184  ek110237 #include <sys/asynch.h>
     33  5184  ek110237 #endif
     34  8615    Andrew #include <stddef.h>
     35  5184  ek110237 #include <sys/ipc.h>
     36  5184  ek110237 #include <sys/sem.h>
     37  5184  ek110237 #include <sys/errno.h>
     38  5184  ek110237 #include <sys/time.h>
     39  5184  ek110237 #include <inttypes.h>
     40  5184  ek110237 #include <fcntl.h>
     41  6212  aw148015 #include <math.h>
     42  7946    Andrew #include <dirent.h>
     43  5184  ek110237 
     44  5184  ek110237 #ifdef HAVE_UTILITY_H
     45  5184  ek110237 #include <utility.h>
     46  5184  ek110237 #endif /* HAVE_UTILITY_H */
     47  5184  ek110237 
     48  5184  ek110237 #ifdef HAVE_SYS_ASYNC_H
     49  5184  ek110237 #include <sys/asynch.h>
     50  5184  ek110237 #endif /* HAVE_SYS_ASYNC_H */
     51  5184  ek110237 
     52  5184  ek110237 #ifndef HAVE_SYSV_SEM
     53  5184  ek110237 #include <semaphore.h>
     54  5184  ek110237 #endif /* HAVE_SYSV_SEM */
     55  5184  ek110237 
     56  5184  ek110237 #include "filebench.h"
     57  5184  ek110237 #include "flowop.h"
     58  5184  ek110237 #include "fileset.h"
     59  6212  aw148015 #include "fb_random.h"
     60  7946    Andrew #include "utils.h"
     61  8615    Andrew #include "fsplug.h"
     62  8615    Andrew 
     63  5184  ek110237 /*
     64  5184  ek110237  * These routines implement the flowops from the f language. Each
     65  5184  ek110237  * flowop has has a name such as "read", and a set of function pointers
     66  5184  ek110237  * to call for initialization, execution and destruction of the flowop.
     67  5184  ek110237  * The table flowoplib_funcs[] contains a flowoplib struct for each
     68  5184  ek110237  * implemented flowop. Most flowops use a generic initialization function
     69  5184  ek110237  * and all currently use a generic destruction function. All flowop
     70  5184  ek110237  * functions referenced from the table are in this file, though, of
     71  5184  ek110237  * course, they often call functions from other files.
     72  5184  ek110237  *
     73  5184  ek110237  * The flowop_init() routine uses the flowoplib_funcs[] table to
     74  5184  ek110237  * create an initial set of "instance 0" flowops, one for each type of
     75  5184  ek110237  * flowop, from which all other flowops are derived. These "instance 0"
     76  5184  ek110237  * flowops are initialized with information from the table including
     77  5184  ek110237  * pointers for their fo_init, fo_func and fo_destroy functions. When
     78  5184  ek110237  * a flowop definition is encountered in an f language script, the
     79  5184  ek110237  * "type" of flowop, such as "read" is used to search for the
     80  5184  ek110237  * "instance 0" flowop named "read", then a new flowop is allocated
     81  5184  ek110237  * which inherits its function pointers and other initial properties
     82  5184  ek110237  * from the instance 0 flowop, and is given a new name as specified
     83  5184  ek110237  * by the "name=" attribute.
     84  5184  ek110237  */
     85  5184  ek110237 
     86  6084  aw148015 static void flowoplib_destruct_noop(flowop_t *flowop);
     87  5184  ek110237 static int flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop);
     88  7556    Andrew static int flowoplib_print(threadflow_t *threadflow, flowop_t *flowop);
     89  5184  ek110237 static int flowoplib_write(threadflow_t *threadflow, flowop_t *flowop);
     90  5184  ek110237 static int flowoplib_read(threadflow_t *threadflow, flowop_t *flowop);
     91  5184  ek110237 static int flowoplib_block_init(flowop_t *flowop);
     92  5184  ek110237 static int flowoplib_block(threadflow_t *threadflow, flowop_t *flowop);
     93  5184  ek110237 static int flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop);
     94  5184  ek110237 static int flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop);
     95  5184  ek110237 static int flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop);
     96  5184  ek110237 static int flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop);
     97  5184  ek110237 static int flowoplib_sempost_init(flowop_t *flowop);
     98  5184  ek110237 static int flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop);
     99  5184  ek110237 static int flowoplib_semblock_init(flowop_t *flowop);
    100  5184  ek110237 static void flowoplib_semblock_destruct(flowop_t *flowop);
    101  5184  ek110237 static int flowoplib_eventlimit(threadflow_t *, flowop_t *flowop);
    102  5184  ek110237 static int flowoplib_bwlimit(threadflow_t *, flowop_t *flowop);
    103  5184  ek110237 static int flowoplib_iopslimit(threadflow_t *, flowop_t *flowop);
    104  5184  ek110237 static int flowoplib_opslimit(threadflow_t *, flowop_t *flowop);
    105  5184  ek110237 static int flowoplib_openfile(threadflow_t *, flowop_t *flowop);
    106  5184  ek110237 static int flowoplib_openfile_common(threadflow_t *, flowop_t *flowop, int fd);
    107  5184  ek110237 static int flowoplib_createfile(threadflow_t *, flowop_t *flowop);
    108  5184  ek110237 static int flowoplib_closefile(threadflow_t *, flowop_t *flowop);
    109  7946    Andrew static int flowoplib_makedir(threadflow_t *, flowop_t *flowop);
    110  7946    Andrew static int flowoplib_removedir(threadflow_t *, flowop_t *flowop);
    111  7946    Andrew static int flowoplib_listdir(threadflow_t *, flowop_t *flowop);
    112  5184  ek110237 static int flowoplib_fsync(threadflow_t *, flowop_t *flowop);
    113  5184  ek110237 static int flowoplib_readwholefile(threadflow_t *, flowop_t *flowop);
    114  5184  ek110237 static int flowoplib_writewholefile(threadflow_t *, flowop_t *flowop);
    115  5184  ek110237 static int flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop);
    116  5184  ek110237 static int flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop);
    117  5184  ek110237 static int flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop);
    118  5184  ek110237 static int flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop);
    119  5184  ek110237 static int flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop);
    120  5184  ek110237 static int flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop);
    121  5184  ek110237 static int flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop);
    122  6212  aw148015 static int flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop);
    123  6212  aw148015 static int flowoplib_testrandvar_init(flowop_t *flowop);
    124  6212  aw148015 static void flowoplib_testrandvar_destruct(flowop_t *flowop);
    125  5184  ek110237 
    126  8615    Andrew static flowop_proto_t flowoplib_funcs[] = {
    127  8615    Andrew 	FLOW_TYPE_IO, FLOW_ATTR_WRITE, "write", flowop_init_generic,
    128  8615    Andrew 	flowoplib_write, flowop_destruct_generic,
    129  8615    Andrew 	FLOW_TYPE_IO, FLOW_ATTR_READ, "read", flowop_init_generic,
    130  8615    Andrew 	flowoplib_read, flowop_destruct_generic,
    131  5184  ek110237 	FLOW_TYPE_SYNC, 0, "block", flowoplib_block_init,
    132  8615    Andrew 	flowoplib_block, flowop_destruct_generic,
    133  8615    Andrew 	FLOW_TYPE_SYNC, 0, "wakeup", flowop_init_generic,
    134  8615    Andrew 	flowoplib_wakeup, flowop_destruct_generic,
    135  5184  ek110237 	FLOW_TYPE_SYNC, 0, "semblock", flowoplib_semblock_init,
    136  5184  ek110237 	flowoplib_semblock, flowoplib_semblock_destruct,
    137  5184  ek110237 	FLOW_TYPE_SYNC, 0, "sempost", flowoplib_sempost_init,
    138  6084  aw148015 	flowoplib_sempost, flowoplib_destruct_noop,
    139  8615    Andrew 	FLOW_TYPE_OTHER, 0, "hog", flowop_init_generic,
    140  8615    Andrew 	flowoplib_hog, flowop_destruct_generic,
    141  8615    Andrew 	FLOW_TYPE_OTHER, 0, "delay", flowop_init_generic,
    142  8615    Andrew 	flowoplib_delay, flowop_destruct_generic,
    143  8615    Andrew 	FLOW_TYPE_OTHER, 0, "eventlimit", flowop_init_generic,
    144  8615    Andrew 	flowoplib_eventlimit, flowop_destruct_generic,
    145  8615    Andrew 	FLOW_TYPE_OTHER, 0, "bwlimit", flowop_init_generic,
    146  8615    Andrew 	flowoplib_bwlimit, flowop_destruct_generic,
    147  8615    Andrew 	FLOW_TYPE_OTHER, 0, "iopslimit", flowop_init_generic,
    148  8615    Andrew 	flowoplib_iopslimit, flowop_destruct_generic,
    149  8615    Andrew 	FLOW_TYPE_OTHER, 0, "opslimit", flowop_init_generic,
    150  8615    Andrew 	flowoplib_opslimit, flowop_destruct_generic,
    151  8615    Andrew 	FLOW_TYPE_OTHER, 0, "finishoncount", flowop_init_generic,
    152  8615    Andrew 	flowoplib_finishoncount, flowop_destruct_generic,
    153  8615    Andrew 	FLOW_TYPE_OTHER, 0, "finishonbytes", flowop_init_generic,
    154  8615    Andrew 	flowoplib_finishonbytes, flowop_destruct_generic,
    155  8615    Andrew 	FLOW_TYPE_IO, 0, "openfile", flowop_init_generic,
    156  8615    Andrew 	flowoplib_openfile, flowop_destruct_generic,
    157  8615    Andrew 	FLOW_TYPE_IO, 0, "createfile", flowop_init_generic,
    158  8615    Andrew 	flowoplib_createfile, flowop_destruct_generic,
    159  8615    Andrew 	FLOW_TYPE_IO, 0, "closefile", flowop_init_generic,
    160  8615    Andrew 	flowoplib_closefile, flowop_destruct_generic,
    161  8615    Andrew 	FLOW_TYPE_IO, 0, "makedir", flowop_init_generic,
    162  8615    Andrew 	flowoplib_makedir, flowop_destruct_generic,
    163  8615    Andrew 	FLOW_TYPE_IO, 0, "removedir", flowop_init_generic,
    164  8615    Andrew 	flowoplib_removedir, flowop_destruct_generic,
    165  8615    Andrew 	FLOW_TYPE_IO, 0, "listdir", flowop_init_generic,
    166  8615    Andrew 	flowoplib_listdir, flowop_destruct_generic,
    167  8615    Andrew 	FLOW_TYPE_IO, 0, "fsync", flowop_init_generic,
    168  8615    Andrew 	flowoplib_fsync, flowop_destruct_generic,
    169  8615    Andrew 	FLOW_TYPE_IO, 0, "fsyncset", flowop_init_generic,
    170  8615    Andrew 	flowoplib_fsyncset, flowop_destruct_generic,
    171  8615    Andrew 	FLOW_TYPE_IO, 0, "statfile", flowop_init_generic,
    172  8615    Andrew 	flowoplib_statfile, flowop_destruct_generic,
    173  8615    Andrew 	FLOW_TYPE_IO, FLOW_ATTR_READ, "readwholefile", flowop_init_generic,
    174  8615    Andrew 	flowoplib_readwholefile, flowop_destruct_generic,
    175  8615    Andrew 	FLOW_TYPE_IO, FLOW_ATTR_WRITE, "appendfile", flowop_init_generic,
    176  8615    Andrew 	flowoplib_appendfile, flowop_destruct_generic,
    177  8615    Andrew 	FLOW_TYPE_IO, FLOW_ATTR_WRITE, "appendfilerand", flowop_init_generic,
    178  8615    Andrew 	flowoplib_appendfilerand, flowop_destruct_generic,
    179  8615    Andrew 	FLOW_TYPE_IO, 0, "deletefile", flowop_init_generic,
    180  8615    Andrew 	flowoplib_deletefile, flowop_destruct_generic,
    181  8615    Andrew 	FLOW_TYPE_IO, FLOW_ATTR_WRITE, "writewholefile", flowop_init_generic,
    182  8615    Andrew 	flowoplib_writewholefile, flowop_destruct_generic,
    183  8615    Andrew 	FLOW_TYPE_OTHER, 0, "print", flowop_init_generic,
    184  8615    Andrew 	flowoplib_print, flowop_destruct_generic,
    185  6212  aw148015 	/* routine to calculate mean and stddev for output from a randvar */
    186  6212  aw148015 	FLOW_TYPE_OTHER, 0, "testrandvar", flowoplib_testrandvar_init,
    187  6212  aw148015 	flowoplib_testrandvar, flowoplib_testrandvar_destruct
    188  5184  ek110237 };
    189  5184  ek110237 
    190  5184  ek110237 /*
    191  8615    Andrew  * Loops through the list of flowops defined in this
    192  5184  ek110237  * module, and creates and initializes a flowop for each one
    193  8615    Andrew  * by calling flowop_flow_init. As a side effect of calling
    194  8615    Andrew  * flowop_flow_init, the created flowops are placed on the
    195  5184  ek110237  * master flowop list. All created flowops are set to
    196  5184  ek110237  * instance "0".
    197  5184  ek110237  */
    198  5184  ek110237 void
    199  8615    Andrew flowoplib_flowinit()
    200  5184  ek110237 {
    201  8615    Andrew 	int nops = sizeof (flowoplib_funcs) / sizeof (flowop_proto_t);
    202  5184  ek110237 
    203  8615    Andrew 	flowop_flow_init(flowoplib_funcs, nops);
    204  6084  aw148015 }
    205  6084  aw148015 
    206  6084  aw148015 /*
    207  6084  aw148015  * Special total noop destruct
    208  6084  aw148015  */
    209  6084  aw148015 /* ARGSUSED */
    210  6084  aw148015 static void
    211  6084  aw148015 flowoplib_destruct_noop(flowop_t *flowop)
    212  6084  aw148015 {
    213  5184  ek110237 }
    214  5184  ek110237 
    215  5184  ek110237 /*
    216  5184  ek110237  * Generates a file attribute from flags in the supplied flowop.
    217  5184  ek110237  * Sets FLOW_ATTR_DIRECTIO and/or FLOW_ATTR_DSYNC as needed.
    218  5184  ek110237  */
    219  5184  ek110237 static int
    220  5184  ek110237 flowoplib_fileattrs(flowop_t *flowop)
    221  5184  ek110237 {
    222  5184  ek110237 	int attrs = 0;
    223  5184  ek110237 
    224  6212  aw148015 	if (avd_get_bool(flowop->fo_directio))
    225  5184  ek110237 		attrs |= FLOW_ATTR_DIRECTIO;
    226  5184  ek110237 
    227  6212  aw148015 	if (avd_get_bool(flowop->fo_dsync))
    228  5184  ek110237 		attrs |= FLOW_ATTR_DSYNC;
    229  5184  ek110237 
    230  5184  ek110237 	return (attrs);
    231  5184  ek110237 }
    232  5184  ek110237 
    233  5184  ek110237 /*
    234  8404    Andrew  * Obtain a filesetentry for a file. Result placed where filep points.
    235  8404    Andrew  * Supply with a flowop and a flag to indicate whether an existent or
    236  8404    Andrew  * non-existent file is required. Returns FILEBENCH_NORSC if all out
    237  8404    Andrew  * of the appropriate type of directories, FILEBENCH_ERROR if the
    238  8404    Andrew  * flowop does not point to a fileset, and FILEBENCH_OK otherwise.
    239  8404    Andrew  */
    240  8404    Andrew static int
    241  8404    Andrew flowoplib_pickfile(filesetentry_t **filep, flowop_t *flowop, int flags, int tid)
    242  8404    Andrew {
    243  8404    Andrew 	fileset_t	*fileset;
    244  8404    Andrew 	int		fileindex;
    245  8404    Andrew 
    246  8404    Andrew 	if ((fileset = flowop->fo_fileset) == NULL) {
    247  8404    Andrew 		filebench_log(LOG_ERROR, "flowop NO fileset");
    248  8404    Andrew 		return (FILEBENCH_ERROR);
    249  8404    Andrew 	}
    250  8404    Andrew 
    251  8404    Andrew 	if (flowop->fo_fileindex) {
    252  8404    Andrew 		fileindex = (int)(avd_get_dbl(flowop->fo_fileindex) *
    253  8404    Andrew 		    ((double)(fileset->fs_constentries / 2)));
    254  8404    Andrew 		fileindex = fileindex % fileset->fs_constentries;
    255  8404    Andrew 		flags |= FILESET_PICKBYINDEX;
    256  8404    Andrew 	} else {
    257  8404    Andrew 		fileindex = 0;
    258  8404    Andrew 	}
    259  8404    Andrew 
    260  8404    Andrew 	if ((*filep = fileset_pick(fileset, FILESET_PICKFILE | flags,
    261  8404    Andrew 	    tid, fileindex)) == NULL) {
    262  8404    Andrew 		filebench_log(LOG_DEBUG_SCRIPT,
    263  8404    Andrew 		    "flowop %s failed to pick file from fileset %s",
    264  8404    Andrew 		    flowop->fo_name,
    265  8404    Andrew 		    avd_get_str(fileset->fs_name));
    266  8404    Andrew 		return (FILEBENCH_NORSC);
    267  8404    Andrew 	}
    268  8404    Andrew 
    269  8404    Andrew 	return (FILEBENCH_OK);
    270  8404    Andrew }
    271  8404    Andrew 
    272  8404    Andrew /*
    273  8404    Andrew  * Obtain a filesetentry for a leaf directory. Result placed where dirp
    274  8404    Andrew  * points. Supply with flowop and a flag to indicate whether an existent
    275  8404    Andrew  * or non-existent leaf directory is required. Returns FILEBENCH_NORSC
    276  8404    Andrew  * if all out of the appropriate type of directories, FILEBENCH_ERROR
    277  8404    Andrew  * if the flowop does not point to a fileset, and FILEBENCH_OK otherwise.
    278  8404    Andrew  */
    279  8404    Andrew static int
    280  8404    Andrew flowoplib_pickleafdir(filesetentry_t **dirp, flowop_t *flowop, int flags)
    281  8404    Andrew {
    282  8404    Andrew 	fileset_t	*fileset;
    283  8404    Andrew 	int		dirindex;
    284  8404    Andrew 
    285  8404    Andrew 	if ((fileset = flowop->fo_fileset) == NULL) {
    286  8404    Andrew 		filebench_log(LOG_ERROR, "flowop NO fileset");
    287  8404    Andrew 		return (FILEBENCH_ERROR);
    288  8404    Andrew 	}
    289  8404    Andrew 
    290  8404    Andrew 	if (flowop->fo_fileindex) {
    291  8404    Andrew 		dirindex = (int)(avd_get_dbl(flowop->fo_fileindex) *
    292  8404    Andrew 		    ((double)(fileset->fs_constleafdirs / 2)));
    293  8404    Andrew 		dirindex = dirindex % fileset->fs_constleafdirs;
    294  8404    Andrew 		flags |= FILESET_PICKBYINDEX;
    295  8404    Andrew 	} else {
    296  8404    Andrew 		dirindex = 0;
    297  8404    Andrew 	}
    298  8404    Andrew 
    299  8404    Andrew 	if ((*dirp = fileset_pick(fileset,
    300  8404    Andrew 	    FILESET_PICKLEAFDIR | flags, 0, dirindex)) == NULL) {
    301  8404    Andrew 		filebench_log(LOG_DEBUG_SCRIPT,
    302  8404    Andrew 		    "flowop %s failed to pick directory from fileset %s",
    303  8404    Andrew 		    flowop->fo_name,
    304  8404    Andrew 		    avd_get_str(fileset->fs_name));
    305  8404    Andrew 		return (FILEBENCH_NORSC);
    306  8404    Andrew 	}
    307  8404    Andrew 
    308  8404    Andrew 	return (FILEBENCH_OK);
    309  8404    Andrew }
    310  8404    Andrew 
    311  8404    Andrew /*
    312  5184  ek110237  * Searches for a file descriptor. Tries the flowop's
    313  5184  ek110237  * fo_fdnumber first and returns with it if it has been
    314  5184  ek110237  * explicitly set (greater than 0). It next checks to
    315  5184  ek110237  * see if a rotating file descriptor policy is in effect,
    316  5184  ek110237  * and if not returns the fdnumber regardless of what
    317  5184  ek110237  * it is. (note that if it is 0, it just selects to the
    318  5184  ek110237  * default file descriptor in the threadflow's tf_fd
    319  5184  ek110237  * array). If the rotating fd policy is in effect, it
    320  5184  ek110237  * cycles from the end of the tf_fd array to one location
    321  5184  ek110237  * beyond the maximum needed by the number of entries in
    322  5184  ek110237  * the associated fileset on each invocation, then starts
    323  5184  ek110237  * over from the end.
    324  5184  ek110237  *
    325  5184  ek110237  * The routine returns an index into the threadflow's
    326  5184  ek110237  * tf_fd table where the actual file descriptor will be
    327  5184  ek110237  * found. Note: the calling routine must not call this
    328  5184  ek110237  * routine if the flowop does not have a fileset, and the
    329  5184  ek110237  * flowop's fo_fdnumber is zero and fo_rotatefd is
    330  5184  ek110237  * asserted, or an addressing fault may occur.
    331  5184  ek110237  */
    332  5673  aw148015 static int
    333  5184  ek110237 flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop)
    334  5184  ek110237 {
    335  6212  aw148015 	fbint_t	entries;
    336  6391  aw148015 	int fdnumber = flowop->fo_fdnumber;
    337  6212  aw148015 
    338  5184  ek110237 	/* If the script sets the fd explicitly */
    339  6391  aw148015 	if (fdnumber > 0)
    340  6391  aw148015 		return (fdnumber);
    341  5184  ek110237 
    342  5184  ek110237 	/* If the flowop defaults to persistent fd */
    343  6212  aw148015 	if (!avd_get_bool(flowop->fo_rotatefd))
    344  6391  aw148015 		return (fdnumber);
    345  6391  aw148015 
    346  6391  aw148015 	if (flowop->fo_fileset == NULL) {
    347  6391  aw148015 		filebench_log(LOG_ERROR, "flowop NULL file");
    348  6391  aw148015 		return (FILEBENCH_ERROR);
    349  6391  aw148015 	}
    350  5184  ek110237 
    351  6212  aw148015 	entries = flowop->fo_fileset->fs_constentries;
    352  6212  aw148015 
    353  5184  ek110237 	/* Rotate the fd on each flowop invocation */
    354  6212  aw148015 	if (entries > (THREADFLOW_MAXFD / 2)) {
    355  5184  ek110237 		filebench_log(LOG_ERROR, "Out of file descriptors in flowop %s"
    356  6286  aw148015 		    " (too many files : %llu",
    357  6286  aw148015 		    flowop->fo_name, (u_longlong_t)entries);
    358  6084  aw148015 		return (FILEBENCH_ERROR);
    359  5184  ek110237 	}
    360  5184  ek110237 
    361  5184  ek110237 	/* First time around */
    362  5184  ek110237 	if (threadflow->tf_fdrotor == 0)
    363  5184  ek110237 		threadflow->tf_fdrotor = THREADFLOW_MAXFD;
    364  5184  ek110237 
    365  5184  ek110237 	/* One fd for every file in the set */
    366  6212  aw148015 	if (entries == (THREADFLOW_MAXFD - threadflow->tf_fdrotor))
    367  5184  ek110237 		threadflow->tf_fdrotor = THREADFLOW_MAXFD;
    368  5184  ek110237 
    369  5184  ek110237 
    370  5184  ek110237 	threadflow->tf_fdrotor--;
    371  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "selected fd = %d",
    372  5184  ek110237 	    threadflow->tf_fdrotor);
    373  5184  ek110237 	return (threadflow->tf_fdrotor);
    374  5184  ek110237 }
    375  5184  ek110237 
    376  5184  ek110237 /*
    377  5673  aw148015  * Determines the file descriptor to use, and attempts to open
    378  5673  aw148015  * the file if it is not already open. Also determines the wss
    379  6084  aw148015  * value. Returns FILEBENCH_ERROR on errors, FILESET_NORSC if
    380  6084  aw148015  * if flowop_openfile_common couldn't obtain an appropriate file
    381  6084  aw148015  * from a the fileset, and FILEBENCH_OK otherwise.
    382  5673  aw148015  */
    383  5673  aw148015 static int
    384  5673  aw148015 flowoplib_filesetup(threadflow_t *threadflow, flowop_t *flowop,
    385  8615    Andrew     fbint_t *wssp, fb_fdesc_t **fdescp)
    386  5673  aw148015 {
    387  5673  aw148015 	int fd = flowoplib_fdnum(threadflow, flowop);
    388  5673  aw148015 
    389  5673  aw148015 	if (fd == -1)
    390  6084  aw148015 		return (FILEBENCH_ERROR);
    391  5673  aw148015 
    392  9326    Andrew 	/* check for conflicting fdnumber and file name */
    393  9326    Andrew 	if ((fd > 0) && (threadflow->tf_fse[fd] != NULL)) {
    394  9326    Andrew 		char *fd_based_name;
    395  9326    Andrew 
    396  9326    Andrew 		fd_based_name =
    397  9326    Andrew 		    avd_get_str(threadflow->tf_fse[fd]->fse_fileset->fs_name);
    398  9326    Andrew 
    399  9326    Andrew 		if (flowop->fo_filename != NULL) {
    400  9326    Andrew 			char *fo_based_name;
    401  9326    Andrew 
    402  9326    Andrew 			fo_based_name = avd_get_str(flowop->fo_filename);
    403  9326    Andrew 			if (strcmp(fd_based_name, fo_based_name) != 0) {
    404  9326    Andrew 				filebench_log(LOG_ERROR, "Name of fd refer"
    405  9326    Andrew 				    "enced fileset name (%s) CONFLICTS with"
    406  9326    Andrew 				    " flowop supplied fileset name (%s)",
    407  9326    Andrew 				    fd_based_name, fo_based_name);
    408  9326    Andrew 				filebench_shutdown(1);
    409  9326    Andrew 				return (FILEBENCH_ERROR);
    410  9326    Andrew 			}
    411  9326    Andrew 		}
    412  9326    Andrew 	}
    413  9326    Andrew 
    414  8615    Andrew 	if (threadflow->tf_fd[fd].fd_ptr == NULL) {
    415  6084  aw148015 		int ret;
    416  6084  aw148015 
    417  6084  aw148015 		if ((ret = flowoplib_openfile_common(
    418  6084  aw148015 		    threadflow, flowop, fd)) != FILEBENCH_OK)
    419  6084  aw148015 			return (ret);
    420  5673  aw148015 
    421  5673  aw148015 		if (threadflow->tf_fse[fd]) {
    422  5673  aw148015 			filebench_log(LOG_DEBUG_IMPL, "opened file %s",
    423  5673  aw148015 			    threadflow->tf_fse[fd]->fse_path);
    424  5673  aw148015 		} else {
    425  5673  aw148015 			filebench_log(LOG_DEBUG_IMPL,
    426  5673  aw148015 			    "opened device %s/%s",
    427  6212  aw148015 			    avd_get_str(flowop->fo_fileset->fs_path),
    428  6212  aw148015 			    avd_get_str(flowop->fo_fileset->fs_name));
    429  5673  aw148015 		}
    430  5673  aw148015 	}
    431  5673  aw148015 
    432  8615    Andrew 	*fdescp = &(threadflow->tf_fd[fd]);
    433  5673  aw148015 
    434  6212  aw148015 	if ((*wssp = flowop->fo_constwss) == 0) {
    435  5673  aw148015 		if (threadflow->tf_fse[fd])
    436  5673  aw148015 			*wssp = threadflow->tf_fse[fd]->fse_size;
    437  5673  aw148015 		else
    438  6212  aw148015 			*wssp = avd_get_int(flowop->fo_fileset->fs_size);
    439  5673  aw148015 	}
    440  5673  aw148015 
    441  6084  aw148015 	return (FILEBENCH_OK);
    442  5673  aw148015 }
    443  5673  aw148015 
    444  5673  aw148015 /*
    445  5673  aw148015  * Determines the io buffer or random offset into tf_mem for
    446  6084  aw148015  * the IO operation. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
    447  5673  aw148015  */
    448  5673  aw148015 static int
    449  5673  aw148015 flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop,
    450  6212  aw148015     caddr_t *iobufp, fbint_t iosize)
    451  5673  aw148015 {
    452  5673  aw148015 	long memsize;
    453  5673  aw148015 	size_t memoffset;
    454  5673  aw148015 
    455  5673  aw148015 	if (iosize == 0) {
    456  5673  aw148015 		filebench_log(LOG_ERROR, "zero iosize for thread %s",
    457  5673  aw148015 		    flowop->fo_name);
    458  6084  aw148015 		return (FILEBENCH_ERROR);
    459  5673  aw148015 	}
    460  5673  aw148015 
    461  6212  aw148015 	if ((memsize = threadflow->tf_constmemsize) != 0) {
    462  5673  aw148015 
    463  5673  aw148015 		/* use tf_mem for I/O with random offset */
    464  6212  aw148015 		if (filebench_randomno(&memoffset,
    465  6212  aw148015 		    memsize, iosize, NULL) == -1) {
    466  5673  aw148015 			filebench_log(LOG_ERROR,
    467  5673  aw148015 			    "tf_memsize smaller than IO size for thread %s",
    468  5673  aw148015 			    flowop->fo_name);
    469  6084  aw148015 			return (FILEBENCH_ERROR);
    470  5673  aw148015 		}
    471  5673  aw148015 		*iobufp = threadflow->tf_mem + memoffset;
    472  5673  aw148015 
    473  5673  aw148015 	} else {
    474  5673  aw148015 		/* use private I/O buffer */
    475  5673  aw148015 		if ((flowop->fo_buf != NULL) &&
    476  5673  aw148015 		    (flowop->fo_buf_size < iosize)) {
    477  6212  aw148015 			/* too small, so free up and re-allocate */
    478  5673  aw148015 			free(flowop->fo_buf);
    479  5673  aw148015 			flowop->fo_buf = NULL;
    480  5673  aw148015 		}
    481  6212  aw148015 
    482  6212  aw148015 		/*
    483  6212  aw148015 		 * Allocate memory for the  buffer. The memory is freed
    484  6212  aw148015 		 * by flowop_destruct_generic() or by this routine if more
    485  6212  aw148015 		 * memory is needed for the buffer.
    486  6212  aw148015 		 */
    487  5673  aw148015 		if ((flowop->fo_buf == NULL) && ((flowop->fo_buf
    488  5673  aw148015 		    = (char *)malloc(iosize)) == NULL))
    489  6084  aw148015 			return (FILEBENCH_ERROR);
    490  5673  aw148015 
    491  5673  aw148015 		flowop->fo_buf_size = iosize;
    492  5673  aw148015 		*iobufp = flowop->fo_buf;
    493  5673  aw148015 	}
    494  6084  aw148015 	return (FILEBENCH_OK);
    495  5673  aw148015 }
    496  5673  aw148015 
    497  5673  aw148015 /*
    498  5673  aw148015  * Determines the file descriptor to use, opens it if necessary, the
    499  5673  aw148015  * io buffer or random offset into tf_mem for IO operation and the wss
    500  6084  aw148015  * value. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
    501  5673  aw148015  */
    502  8615    Andrew int
    503  5673  aw148015 flowoplib_iosetup(threadflow_t *threadflow, flowop_t *flowop,
    504  8615    Andrew     fbint_t *wssp, caddr_t *iobufp, fb_fdesc_t **filedescp, fbint_t iosize)
    505  5673  aw148015 {
    506  6084  aw148015 	int ret;
    507  5673  aw148015 
    508  6084  aw148015 	if ((ret = flowoplib_filesetup(threadflow, flowop, wssp, filedescp)) !=
    509  6084  aw148015 	    FILEBENCH_OK)
    510  6084  aw148015 		return (ret);
    511  5673  aw148015 
    512  6084  aw148015 	if ((ret = flowoplib_iobufsetup(threadflow, flowop, iobufp, iosize)) !=
    513  6084  aw148015 	    FILEBENCH_OK)
    514  6084  aw148015 		return (ret);
    515  6084  aw148015 
    516  6084  aw148015 	return (FILEBENCH_OK);
    517  5673  aw148015 }
    518  5673  aw148015 
    519  5673  aw148015 /*
    520  5184  ek110237  * Emulate posix read / pread. If the flowop has a fileset,
    521  5184  ek110237  * a file descriptor number index is fetched, otherwise a
    522  5184  ek110237  * supplied fileobj file is used. In either case the specified
    523  5184  ek110237  * file will be opened if not already open. If the flowop has
    524  6084  aw148015  * neither a fileset or fileobj, an error is logged and FILEBENCH_ERROR
    525  5184  ek110237  * returned.
    526  5184  ek110237  *
    527  5184  ek110237  * The actual read is done to a random offset in the
    528  5184  ek110237  * threadflow's thread memory (tf_mem), with a size set by
    529  5184  ek110237  * fo_iosize and at either a random disk offset within the
    530  5184  ek110237  * working set size, or at the next sequential location. If
    531  6084  aw148015  * any errors are encountered, FILEBENCH_ERROR is returned,
    532  6084  aw148015  * if no appropriate file can be obtained from the fileset then
    533  6084  aw148015  * FILEBENCH_NORSC is returned, otherise FILEBENCH_OK is returned.
    534  5184  ek110237  */
    535  5184  ek110237 static int
    536  5184  ek110237 flowoplib_read(threadflow_t *threadflow, flowop_t *flowop)
    537  5184  ek110237 {
    538  5673  aw148015 	caddr_t iobuf;
    539  6212  aw148015 	fbint_t wss;
    540  6212  aw148015 	fbint_t iosize;
    541  8615    Andrew 	fb_fdesc_t *fdesc;
    542  5184  ek110237 	int ret;
    543  5184  ek110237 
    544  6212  aw148015 
    545  6212  aw148015 	iosize = avd_get_int(flowop->fo_iosize);
    546  6084  aw148015 	if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
    547  8615    Andrew 	    &fdesc, iosize)) != FILEBENCH_OK)
    548  6084  aw148015 		return (ret);
    549  5184  ek110237 
    550  6212  aw148015 	if (avd_get_bool(flowop->fo_random)) {
    551  5184  ek110237 		uint64_t fileoffset;
    552  5184  ek110237 
    553  6212  aw148015 		if (filebench_randomno64(&fileoffset,
    554  6212  aw148015 		    wss, iosize, NULL) == -1) {
    555  5184  ek110237 			filebench_log(LOG_ERROR,
    556  5184  ek110237 			    "file size smaller than IO size for thread %s",
    557  5184  ek110237 			    flowop->fo_name);
    558  6084  aw148015 			return (FILEBENCH_ERROR);
    559  5184  ek110237 		}
    560  5184  ek110237 
    561  5184  ek110237 		(void) flowop_beginop(threadflow, flowop);
    562  8615    Andrew 		if ((ret = FB_PREAD(fdesc, iobuf,
    563  6212  aw148015 		    iosize, (off64_t)fileoffset)) == -1) {
    564  5673  aw148015 			(void) flowop_endop(threadflow, flowop, 0);
    565  5184  ek110237 			filebench_log(LOG_ERROR,
    566  6286  aw148015 			    "read file %s failed, offset %llu "
    567  5673  aw148015 			    "io buffer %zd: %s",
    568  6212  aw148015 			    avd_get_str(flowop->fo_fileset->fs_name),
    569  6286  aw148015 			    (u_longlong_t)fileoffset, iobuf, strerror(errno));
    570  5673  aw148015 			flowop_endop(threadflow, flowop, 0);
    571  6084  aw148015 			return (FILEBENCH_ERROR);
    572  5184  ek110237 		}
    573  5673  aw148015 		(void) flowop_endop(threadflow, flowop, ret);
    574  5184  ek110237 
    575  5184  ek110237 		if ((ret == 0))
    576  8615    Andrew 			(void) FB_LSEEK(fdesc, 0, SEEK_SET);
    577  5184  ek110237 
    578  5184  ek110237 	} else {
    579  5184  ek110237 		(void) flowop_beginop(threadflow, flowop);
    580  8615    Andrew 		if ((ret = FB_READ(fdesc, iobuf, iosize)) == -1) {
    581  6212  aw148015 			(void) flowop_endop(threadflow, flowop, 0);
    582  5184  ek110237 			filebench_log(LOG_ERROR,
    583  5673  aw148015 			    "read file %s failed, io buffer %zd: %s",
    584  6212  aw148015 			    avd_get_str(flowop->fo_fileset->fs_name),
    585  5673  aw148015 			    iobuf, strerror(errno));
    586  5673  aw148015 			(void) flowop_endop(threadflow, flowop, 0);
    587  6084  aw148015 			return (FILEBENCH_ERROR);
    588  5184  ek110237 		}
    589  5673  aw148015 		(void) flowop_endop(threadflow, flowop, ret);
    590  5184  ek110237 
    591  5184  ek110237 		if ((ret == 0))
    592  8615    Andrew 			(void) FB_LSEEK(fdesc, 0, SEEK_SET);
    593  5184  ek110237 	}
    594  5184  ek110237 
    595  6084  aw148015 	return (FILEBENCH_OK);
    596  5184  ek110237 }
    597  5184  ek110237 
    598  5184  ek110237 /*
    599  5184  ek110237  * Initializes a "flowop_block" flowop. Specifically, it
    600  5184  ek110237  * initializes the flowop's fo_cv and unlocks the fo_lock.
    601  5184  ek110237  */
    602  5184  ek110237 static int
    603  5184  ek110237 flowoplib_block_init(flowop_t *flowop)
    604  5184  ek110237 {
    605  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "flow %s-%d block init address %zx",
    606  5184  ek110237 	    flowop->fo_name, flowop->fo_instance, &flowop->fo_cv);
    607  5184  ek110237 	(void) pthread_cond_init(&flowop->fo_cv, ipc_condattr());
    608  5184  ek110237 	(void) ipc_mutex_unlock(&flowop->fo_lock);
    609  5184  ek110237 
    610  6084  aw148015 	return (FILEBENCH_OK);
    611  5184  ek110237 }
    612  5184  ek110237 
    613  5184  ek110237 /*
    614  5184  ek110237  * Blocks the threadflow until woken up by flowoplib_wakeup.
    615  5184  ek110237  * The routine blocks on the flowop's fo_cv condition variable.
    616  5184  ek110237  */
    617  5184  ek110237 static int
    618  5184  ek110237 flowoplib_block(threadflow_t *threadflow, flowop_t *flowop)
    619  5184  ek110237 {
    620  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "flow %s-%d blocking at address %zx",
    621  5184  ek110237 	    flowop->fo_name, flowop->fo_instance, &flowop->fo_cv);
    622  5184  ek110237 	(void) ipc_mutex_lock(&flowop->fo_lock);
    623  5184  ek110237 
    624  5184  ek110237 	flowop_beginop(threadflow, flowop);
    625  5184  ek110237 	(void) pthread_cond_wait(&flowop->fo_cv, &flowop->fo_lock);
    626  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
    627  5184  ek110237 
    628  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "flow %s-%d unblocking",
    629  5184  ek110237 	    flowop->fo_name, flowop->fo_instance);
    630  5184  ek110237 
    631  5184  ek110237 	(void) ipc_mutex_unlock(&flowop->fo_lock);
    632  5184  ek110237 
    633  6084  aw148015 	return (FILEBENCH_OK);
    634  5184  ek110237 }
    635  5184  ek110237 
    636  5184  ek110237 /*
    637  5184  ek110237  * Wakes up one or more target blocking flowops.
    638  5184  ek110237  * Sends broadcasts on the fo_cv condition variables of all
    639  5184  ek110237  * flowops on the target list, except those that are
    640  5184  ek110237  * FLOW_MASTER flowops. The target list consists of all
    641  5184  ek110237  * flowops whose name matches this flowop's "fo_targetname"
    642  5184  ek110237  * attribute. The target list is generated on the first
    643  5184  ek110237  * invocation, and the run will be shutdown if no targets
    644  6084  aw148015  * are found. Otherwise the routine always returns FILEBENCH_OK.
    645  5184  ek110237  */
    646  5184  ek110237 static int
    647  5184  ek110237 flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop)
    648  5184  ek110237 {
    649  5184  ek110237 	flowop_t *target;
    650  5184  ek110237 
    651  5184  ek110237 	/* if this is the first wakeup, create the wakeup list */
    652  5184  ek110237 	if (flowop->fo_targets == NULL) {
    653  5184  ek110237 		flowop_t *result = flowop_find(flowop->fo_targetname);
    654  5184  ek110237 
    655  5184  ek110237 		flowop->fo_targets = result;
    656  5184  ek110237 		if (result == NULL) {
    657  5184  ek110237 			filebench_log(LOG_ERROR,
    658  5184  ek110237 			    "wakeup: could not find op %s for thread %s",
    659  5184  ek110237 			    flowop->fo_targetname,
    660  5184  ek110237 			    threadflow->tf_name);
    661  5184  ek110237 			filebench_shutdown(1);
    662  5184  ek110237 		}
    663  5184  ek110237 		while (result) {
    664  5184  ek110237 			result->fo_targetnext =
    665  5184  ek110237 			    result->fo_resultnext;
    666  5184  ek110237 			result = result->fo_resultnext;
    667  5184  ek110237 		}
    668  5184  ek110237 	}
    669  5184  ek110237 
    670  5184  ek110237 	target = flowop->fo_targets;
    671  5184  ek110237 
    672  5184  ek110237 	/* wakeup the targets */
    673  5184  ek110237 	while (target) {
    674  5184  ek110237 		if (target->fo_instance == FLOW_MASTER) {
    675  5184  ek110237 			target = target->fo_targetnext;
    676  5184  ek110237 			continue;
    677  5184  ek110237 		}
    678  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL,
    679  5184  ek110237 		    "wakeup flow %s-%d at address %zx",
    680  5184  ek110237 		    target->fo_name,
    681  5184  ek110237 		    target->fo_instance,
    682  5184  ek110237 		    &target->fo_cv);
    683  5184  ek110237 
    684  5184  ek110237 		flowop_beginop(threadflow, flowop);
    685  5184  ek110237 		(void) ipc_mutex_lock(&target->fo_lock);
    686  5184  ek110237 		(void) pthread_cond_broadcast(&target->fo_cv);
    687  5184  ek110237 		(void) ipc_mutex_unlock(&target->fo_lock);
    688  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
    689  5184  ek110237 
    690  5184  ek110237 		target = target->fo_targetnext;
    691  5184  ek110237 	}
    692  5184  ek110237 
    693  6084  aw148015 	return (FILEBENCH_OK);
    694  5184  ek110237 }
    695  5184  ek110237 
    696  5184  ek110237 /*
    697  5184  ek110237  * "think time" routines. the "hog" routine consumes cpu cycles as
    698  5184  ek110237  * it "thinks", while the "delay" flowop simply calls sleep() to delay
    699  5184  ek110237  * for a given number of seconds without consuming cpu cycles.
    700  5184  ek110237  */
    701  5184  ek110237 
    702  5184  ek110237 
    703  5184  ek110237 /*
    704  5184  ek110237  * Consumes CPU cycles and memory bandwidth by looping for
    705  5184  ek110237  * flowop->fo_value times. With each loop sets memory location
    706  5184  ek110237  * threadflow->tf_mem to 1.
    707  5184  ek110237  */
    708  5184  ek110237 static int
    709  5184  ek110237 flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop)
    710  5184  ek110237 {
    711  6212  aw148015 	uint64_t value = avd_get_int(flowop->fo_value);
    712  5184  ek110237 	int i;
    713  5184  ek110237 
    714  5673  aw148015 	filebench_log(LOG_DEBUG_IMPL, "hog enter");
    715  5184  ek110237 	flowop_beginop(threadflow, flowop);
    716  5673  aw148015 	if (threadflow->tf_mem != NULL) {
    717  5673  aw148015 		for (i = 0; i < value; i++)
    718  5673  aw148015 			*(threadflow->tf_mem) = 1;
    719  5673  aw148015 	}
    720  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
    721  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "hog exit");
    722  6084  aw148015 	return (FILEBENCH_OK);
    723  5184  ek110237 }
    724  5184  ek110237 
    725  5184  ek110237 
    726  5184  ek110237 /*
    727  5184  ek110237  * Delays for fo_value seconds.
    728  5184  ek110237  */
    729  5184  ek110237 static int
    730  5184  ek110237 flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop)
    731  5184  ek110237 {
    732  6212  aw148015 	int value = avd_get_int(flowop->fo_value);
    733  5184  ek110237 
    734  5184  ek110237 	flowop_beginop(threadflow, flowop);
    735  5184  ek110237 	(void) sleep(value);
    736  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
    737  6084  aw148015 	return (FILEBENCH_OK);
    738  5184  ek110237 }
    739  5184  ek110237 
    740  5184  ek110237 /*
    741  5184  ek110237  * Rate limiting routines. This is the event consuming half of the
    742  5184  ek110237  * event system. Each of the four following routines will limit the rate
    743  5184  ek110237  * to one unit of either calls, issued I/O operations, issued filebench
    744  5184  ek110237  * operations, or I/O bandwidth. Since there is only one event generator,
    745  5184  ek110237  * the events will be divided amoung multiple instances of an event
    746  5184  ek110237  * consumer, and further divided among different consumers if more than
    747  5184  ek110237  * one has been defined. There is no mechanism to enforce equal sharing
    748  5184  ek110237  * of events.
    749  5184  ek110237  */
    750  5184  ek110237 
    751  5184  ek110237 /*
    752  5184  ek110237  * Completes one invocation per posted event. If eventgen_q
    753  5184  ek110237  * has an event count greater than zero, one will be removed
    754  5184  ek110237  * (count decremented), otherwise the calling thread will
    755  5184  ek110237  * block until another event has been posted. Always returns 0
    756  5184  ek110237  */
    757  5184  ek110237 static int
    758  5184  ek110237 flowoplib_eventlimit(threadflow_t *threadflow, flowop_t *flowop)
    759  5184  ek110237 {
    760  5184  ek110237 	/* Immediately bail if not set/enabled */
    761  9801    Andrew 	if (!filebench_shm->shm_eventgen_enabled)
    762  6084  aw148015 		return (FILEBENCH_OK);
    763  5184  ek110237 
    764  5184  ek110237 	if (flowop->fo_initted == 0) {
    765  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
    766  5184  ek110237 		    flowop, threadflow->tf_name, threadflow->tf_instance);
    767  5184  ek110237 		flowop->fo_initted = 1;
    768  5184  ek110237 	}
    769  5184  ek110237 
    770  5184  ek110237 	flowop_beginop(threadflow, flowop);
    771  9801    Andrew 	while (filebench_shm->shm_eventgen_enabled) {
    772  6391  aw148015 		(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
    773  6391  aw148015 		if (filebench_shm->shm_eventgen_q > 0) {
    774  6391  aw148015 			filebench_shm->shm_eventgen_q--;
    775  6391  aw148015 			(void) ipc_mutex_unlock(
    776  6391  aw148015 			    &filebench_shm->shm_eventgen_lock);
    777  5184  ek110237 			break;
    778  5184  ek110237 		}
    779  6391  aw148015 		(void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
    780  6391  aw148015 		    &filebench_shm->shm_eventgen_lock);
    781  6391  aw148015 		(void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
    782  5184  ek110237 	}
    783  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
    784  6084  aw148015 	return (FILEBENCH_OK);
    785  5184  ek110237 }
    786  5184  ek110237 
    787  6701  aw148015 static int
    788  6701  aw148015 flowoplib_event_find_target(threadflow_t *threadflow, flowop_t *flowop)
    789  6701  aw148015 {
    790  6701  aw148015 	if (flowop->fo_targetname[0] != '\0') {
    791  6701  aw148015 
    792  6701  aw148015 		/* Try to use statistics from specific flowop */
    793  6701  aw148015 		flowop->fo_targets =
    794  6701  aw148015 		    flowop_find_from_list(flowop->fo_targetname,
    795  6701  aw148015 		    threadflow->tf_thrd_fops);
    796  6701  aw148015 		if (flowop->fo_targets == NULL) {
    797  6701  aw148015 			filebench_log(LOG_ERROR,
    798  6701  aw148015 			    "limit target: could not find flowop %s",
    799  6701  aw148015 			    flowop->fo_targetname);
    800  6701  aw148015 			filebench_shutdown(1);
    801  6701  aw148015 			return (FILEBENCH_ERROR);
    802  6701  aw148015 		}
    803  6701  aw148015 	} else {
    804  6701  aw148015 		/* use total workload statistics */
    805  6701  aw148015 		flowop->fo_targets = NULL;
    806  6701  aw148015 	}
    807  6701  aw148015 	return (FILEBENCH_OK);
    808  6701  aw148015 }
    809  6701  aw148015 
    810  5184  ek110237 /*
    811  5184  ek110237  * Blocks the calling thread if the number of issued I/O
    812  5184  ek110237  * operations exceeds the number of posted events, thus
    813  5184  ek110237  * limiting the average I/O operation rate to the rate
    814  6084  aw148015  * specified by eventgen_hz. Always returns FILEBENCH_OK.
    815  5184  ek110237  */
    816  5184  ek110237 static int
    817  5184  ek110237 flowoplib_iopslimit(threadflow_t *threadflow, flowop_t *flowop)
    818  5184  ek110237 {
    819  5184  ek110237 	uint64_t iops;
    820  5184  ek110237 	uint64_t delta;
    821  5673  aw148015 	uint64_t events;
    822  5184  ek110237 
    823  5184  ek110237 	/* Immediately bail if not set/enabled */
    824  9801    Andrew 	if (!filebench_shm->shm_eventgen_enabled)
    825  6084  aw148015 		return (FILEBENCH_OK);
    826  5184  ek110237 
    827  5184  ek110237 	if (flowop->fo_initted == 0) {
    828  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
    829  5184  ek110237 		    flowop, threadflow->tf_name, threadflow->tf_instance);
    830  5184  ek110237 		flowop->fo_initted = 1;
    831  6701  aw148015 
    832  6701  aw148015 		if (flowoplib_event_find_target(threadflow, flowop)
    833  6701  aw148015 		    == FILEBENCH_ERROR)
    834  6701  aw148015 			return (FILEBENCH_ERROR);
    835  6701  aw148015 
    836  6701  aw148015 		if (flowop->fo_targets && ((flowop->fo_targets->fo_attrs &
    837  6701  aw148015 		    (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) {
    838  6701  aw148015 			filebench_log(LOG_ERROR,
    839  6701  aw148015 			    "WARNING: Flowop %s does no IO",
    840  6701  aw148015 			    flowop->fo_targets->fo_name);
    841  6701  aw148015 			filebench_shutdown(1);
    842  6701  aw148015 			return (FILEBENCH_ERROR);
    843  6701  aw148015 		}
    844  5184  ek110237 	}
    845  5184  ek110237 
    846  6701  aw148015 	if (flowop->fo_targets) {
    847  6701  aw148015 		/*
    848  6701  aw148015 		 * Note that fs_count is already the sum of fs_rcount
    849  6701  aw148015 		 * and fs_wcount if looking at a single flowop.
    850  6701  aw148015 		 */
    851  6701  aw148015 		iops = flowop->fo_targets->fo_stats.fs_count;
    852  6701  aw148015 	} else {
    853  6701  aw148015 		(void) ipc_mutex_lock(&controlstats_lock);
    854  6701  aw148015 		iops = (controlstats.fs_rcount +
    855  6701  aw148015 		    controlstats.fs_wcount);
    856  6701  aw148015 		(void) ipc_mutex_unlock(&controlstats_lock);
    857  6701  aw148015 	}
    858  5184  ek110237 
    859  5184  ek110237 	/* Is this the first time around */
    860  5184  ek110237 	if (flowop->fo_tputlast == 0) {
    861  5184  ek110237 		flowop->fo_tputlast = iops;
    862  6084  aw148015 		return (FILEBENCH_OK);
    863  5184  ek110237 	}
    864  5184  ek110237 
    865  5184  ek110237 	delta = iops - flowop->fo_tputlast;
    866  5184  ek110237 	flowop->fo_tputbucket -= delta;
    867  5184  ek110237 	flowop->fo_tputlast = iops;
    868  5184  ek110237 
    869  5184  ek110237 	/* No need to block if the q isn't empty */
    870  5184  ek110237 	if (flowop->fo_tputbucket >= 0LL) {
    871  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
    872  6084  aw148015 		return (FILEBENCH_OK);
    873  5184  ek110237 	}
    874  5184  ek110237 
    875  5184  ek110237 	iops = flowop->fo_tputbucket * -1;
    876  5184  ek110237 	events = iops;
    877  5184  ek110237 
    878  5184  ek110237 	flowop_beginop(threadflow, flowop);
    879  9801    Andrew 	while (filebench_shm->shm_eventgen_enabled) {
    880  5184  ek110237 
    881  6391  aw148015 		(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
    882  6391  aw148015 		if (filebench_shm->shm_eventgen_q >= events) {
    883  6391  aw148015 			filebench_shm->shm_eventgen_q -= events;
    884  6391  aw148015 			(void) ipc_mutex_unlock(
    885  6391  aw148015 			    &filebench_shm->shm_eventgen_lock);
    886  5184  ek110237 			flowop->fo_tputbucket += events;
    887  5184  ek110237 			break;
    888  5184  ek110237 		}
    889  6391  aw148015 		(void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
    890  6391  aw148015 		    &filebench_shm->shm_eventgen_lock);
    891  6391  aw148015 		(void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
    892  5184  ek110237 	}
    893  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
    894  5184  ek110237 
    895  6084  aw148015 	return (FILEBENCH_OK);
    896  5184  ek110237 }
    897  5184  ek110237 
    898  5184  ek110237 /*
    899  5184  ek110237  * Blocks the calling thread if the number of issued filebench
    900  5184  ek110237  * operations exceeds the number of posted events, thus limiting
    901  5184  ek110237  * the average filebench operation rate to the rate specified by
    902  6084  aw148015  * eventgen_hz. Always returns FILEBENCH_OK.
    903  5184  ek110237  */
    904  5184  ek110237 static int
    905  5184  ek110237 flowoplib_opslimit(threadflow_t *threadflow, flowop_t *flowop)
    906  5184  ek110237 {
    907  5184  ek110237 	uint64_t ops;
    908  5184  ek110237 	uint64_t delta;
    909  5673  aw148015 	uint64_t events;
    910  5184  ek110237 
    911  5184  ek110237 	/* Immediately bail if not set/enabled */
    912  9801    Andrew 	if (!filebench_shm->shm_eventgen_enabled)
    913  6084  aw148015 		return (FILEBENCH_OK);
    914  5184  ek110237 
    915  5184  ek110237 	if (flowop->fo_initted == 0) {
    916  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
    917  5184  ek110237 		    flowop, threadflow->tf_name, threadflow->tf_instance);
    918  5184  ek110237 		flowop->fo_initted = 1;
    919  6701  aw148015 
    920  6701  aw148015 		if (flowoplib_event_find_target(threadflow, flowop)
    921  6701  aw148015 		    == FILEBENCH_ERROR)
    922  6701  aw148015 			return (FILEBENCH_ERROR);
    923  5184  ek110237 	}
    924  5184  ek110237 
    925  6701  aw148015 	if (flowop->fo_targets) {
    926  6701  aw148015 		ops = flowop->fo_targets->fo_stats.fs_count;
    927  6701  aw148015 	} else {
    928  6701  aw148015 		(void) ipc_mutex_lock(&controlstats_lock);
    929  6701  aw148015 		ops = controlstats.fs_count;
    930  6701  aw148015 		(void) ipc_mutex_unlock(&controlstats_lock);
    931  6701  aw148015 	}
    932  5184  ek110237 
    933  5184  ek110237 	/* Is this the first time around */
    934  5184  ek110237 	if (flowop->fo_tputlast == 0) {
    935  5184  ek110237 		flowop->fo_tputlast = ops;
    936  6084  aw148015 		return (FILEBENCH_OK);
    937  5184  ek110237 	}
    938  5184  ek110237 
    939  5184  ek110237 	delta = ops - flowop->fo_tputlast;
    940  5184  ek110237 	flowop->fo_tputbucket -= delta;
    941  5184  ek110237 	flowop->fo_tputlast = ops;
    942  5184  ek110237 
    943  5184  ek110237 	/* No need to block if the q isn't empty */
    944  5184  ek110237 	if (flowop->fo_tputbucket >= 0LL) {
    945  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
    946  6084  aw148015 		return (FILEBENCH_OK);
    947  5184  ek110237 	}
    948  5184  ek110237 
    949  5184  ek110237 	ops = flowop->fo_tputbucket * -1;
    950  5184  ek110237 	events = ops;
    951  5184  ek110237 
    952  5184  ek110237 	flowop_beginop(threadflow, flowop);
    953  9801    Andrew 	while (filebench_shm->shm_eventgen_enabled) {
    954  6391  aw148015 		(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
    955  6391  aw148015 		if (filebench_shm->shm_eventgen_q >= events) {
    956  6391  aw148015 			filebench_shm->shm_eventgen_q -= events;
    957  6391  aw148015 			(void) ipc_mutex_unlock(
    958  6391  aw148015 			    &filebench_shm->shm_eventgen_lock);
    959  5184  ek110237 			flowop->fo_tputbucket += events;
    960  5184  ek110237 			break;
    961  5184  ek110237 		}
    962  6391  aw148015 		(void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
    963  6391  aw148015 		    &filebench_shm->shm_eventgen_lock);
    964  6391  aw148015 		(void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
    965  5184  ek110237 	}
    966  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
    967  5184  ek110237 
    968  6084  aw148015 	return (FILEBENCH_OK);
    969  5184  ek110237 }
    970  5184  ek110237 
    971  5184  ek110237 
    972  5184  ek110237 /*
    973  5184  ek110237  * Blocks the calling thread if the number of bytes of I/O
    974  5184  ek110237  * issued exceeds one megabyte times the number of posted
    975  5184  ek110237  * events, thus limiting the average I/O byte rate to one
    976  5184  ek110237  * megabyte times the event rate as set by eventgen_hz.
    977  6084  aw148015  * Always retuns FILEBENCH_OK.
    978  5184  ek110237  */
    979  5184  ek110237 static int
    980  5184  ek110237 flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop)
    981  5184  ek110237 {
    982  5184  ek110237 	uint64_t bytes;
    983  5184  ek110237 	uint64_t delta;
    984  5673  aw148015 	uint64_t events;
    985  5184  ek110237 
    986  5184  ek110237 	/* Immediately bail if not set/enabled */
    987  9801    Andrew 	if (!filebench_shm->shm_eventgen_enabled)
    988  6084  aw148015 		return (FILEBENCH_OK);
    989  5184  ek110237 
    990  5184  ek110237 	if (flowop->fo_initted == 0) {
    991  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
    992  5184  ek110237 		    flowop, threadflow->tf_name, threadflow->tf_instance);
    993  5184  ek110237 		flowop->fo_initted = 1;
    994  6701  aw148015 
    995  6701  aw148015 		if (flowoplib_event_find_target(threadflow, flowop)
    996  6701  aw148015 		    == FILEBENCH_ERROR)
    997  6701  aw148015 			return (FILEBENCH_ERROR);
    998  6701  aw148015 
    999  6701  aw148015 		if ((flowop->fo_targets) &&
   1000  6701  aw148015 		    ((flowop->fo_targets->fo_attrs &
   1001  6701  aw148015 		    (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) {
   1002  6701  aw148015 			filebench_log(LOG_ERROR,
   1003  6701  aw148015 			    "WARNING: Flowop %s does no Reads or Writes",
   1004  6701  aw148015 			    flowop->fo_targets->fo_name);
   1005  6701  aw148015 			filebench_shutdown(1);
   1006  6701  aw148015 			return (FILEBENCH_ERROR);
   1007  6701  aw148015 		}
   1008  5184  ek110237 	}
   1009  5184  ek110237 
   1010  6701  aw148015 	if (flowop->fo_targets) {
   1011  6701  aw148015 		/*
   1012  6701  aw148015 		 * Note that fs_bytes is already the sum of fs_rbytes
   1013  6701  aw148015 		 * and fs_wbytes if looking at a single flowop.
   1014  6701  aw148015 		 */
   1015  6701  aw148015 		bytes = flowop->fo_targets->fo_stats.fs_bytes;
   1016  6701  aw148015 	} else {
   1017  6701  aw148015 		(void) ipc_mutex_lock(&controlstats_lock);
   1018  6701  aw148015 		bytes = (controlstats.fs_rbytes +
   1019  6701  aw148015 		    controlstats.fs_wbytes);
   1020  6701  aw148015 		(void) ipc_mutex_unlock(&controlstats_lock);
   1021  6701  aw148015 	}
   1022  5184  ek110237 
   1023  6701  aw148015 	/* Is this the first time around? */
   1024  5184  ek110237 	if (flowop->fo_tputlast == 0) {
   1025  5184  ek110237 		flowop->fo_tputlast = bytes;
   1026  6084  aw148015 		return (FILEBENCH_OK);
   1027  5184  ek110237 	}
   1028  5184  ek110237 
   1029  5184  ek110237 	delta = bytes - flowop->fo_tputlast;
   1030  5184  ek110237 	flowop->fo_tputbucket -= delta;
   1031  5184  ek110237 	flowop->fo_tputlast = bytes;
   1032  5184  ek110237 
   1033  5184  ek110237 	/* No need to block if the q isn't empty */
   1034  5184  ek110237 	if (flowop->fo_tputbucket >= 0LL) {
   1035  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
   1036  6084  aw148015 		return (FILEBENCH_OK);
   1037  5184  ek110237 	}
   1038  5184  ek110237 
   1039  5184  ek110237 	bytes = flowop->fo_tputbucket * -1;
   1040  5184  ek110237 	events = (bytes / MB) + 1;
   1041  5184  ek110237 
   1042  6286  aw148015 	filebench_log(LOG_DEBUG_IMPL, "%llu bytes, %llu events",
   1043  6286  aw148015 	    (u_longlong_t)bytes, (u_longlong_t)events);
   1044  5184  ek110237 
   1045  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1046  9801    Andrew 	while (filebench_shm->shm_eventgen_enabled) {
   1047  6391  aw148015 		(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
   1048  6391  aw148015 		if (filebench_shm->shm_eventgen_q >= events) {
   1049  6391  aw148015 			filebench_shm->shm_eventgen_q -= events;
   1050  6391  aw148015 			(void) ipc_mutex_unlock(
   1051  6391  aw148015 			    &filebench_shm->shm_eventgen_lock);
   1052  5184  ek110237 			flowop->fo_tputbucket += (events * MB);
   1053  5184  ek110237 			break;
   1054  5184  ek110237 		}
   1055  6391  aw148015 		(void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
   1056  6391  aw148015 		    &filebench_shm->shm_eventgen_lock);
   1057  6391  aw148015 		(void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
   1058  5184  ek110237 	}
   1059  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1060  5184  ek110237 
   1061  6084  aw148015 	return (FILEBENCH_OK);
   1062  5184  ek110237 }
   1063  5184  ek110237 
   1064  5184  ek110237 /*
   1065  5184  ek110237  * These flowops terminate a benchmark run when either the specified
   1066  5184  ek110237  * number of bytes of I/O (flowoplib_finishonbytes) or the specified
   1067  5184  ek110237  * number of I/O operations (flowoplib_finishoncount) have been generated.
   1068  5184  ek110237  */
   1069  5184  ek110237 
   1070  5184  ek110237 
   1071  5184  ek110237 /*
   1072  5184  ek110237  * Stop filebench run when specified number of I/O bytes have been
   1073  6212  aw148015  * transferred. Compares controlstats.fs_bytes with flowop->value,
   1074  5184  ek110237  * and if greater returns 1, stopping the run, if not, returns 0
   1075  5184  ek110237  * to continue running.
   1076  5184  ek110237  */
   1077  5184  ek110237 static int
   1078  5184  ek110237 flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop)
   1079  5184  ek110237 {
   1080  6701  aw148015 	uint64_t bytes_io;		/* Bytes of I/O delivered so far */
   1081  6701  aw148015 	uint64_t byte_lim = flowop->fo_constvalue;  /* Total Bytes desired */
   1082  6701  aw148015 						    /* Uses constant value */
   1083  5184  ek110237 
   1084  6701  aw148015 	if (flowop->fo_initted == 0) {
   1085  6701  aw148015 		filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
   1086  6701  aw148015 		    flowop, threadflow->tf_name, threadflow->tf_instance);
   1087  6701  aw148015 		flowop->fo_initted = 1;
   1088  6701  aw148015 
   1089  6701  aw148015 		if (flowoplib_event_find_target(threadflow, flowop)
   1090  6701  aw148015 		    == FILEBENCH_ERROR)
   1091  6701  aw148015 			return (FILEBENCH_ERROR);
   1092  6701  aw148015 
   1093  6701  aw148015 		if ((flowop->fo_targets) &&
   1094  6701  aw148015 		    ((flowop->fo_targets->fo_attrs &
   1095  6701  aw148015 		    (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) {
   1096  6701  aw148015 			filebench_log(LOG_ERROR,
   1097  6701  aw148015 			    "WARNING: Flowop %s does no Reads or Writes",
   1098  6701  aw148015 			    flowop->fo_targets->fo_name);
   1099  6701  aw148015 			filebench_shutdown(1);
   1100  6701  aw148015 			return (FILEBENCH_ERROR);
   1101  6701  aw148015 		}
   1102  6701  aw148015 	}
   1103  6701  aw148015 
   1104  6701  aw148015 	if (flowop->fo_targets) {
   1105  6701  aw148015 		bytes_io = flowop->fo_targets->fo_stats.fs_bytes;
   1106  6701  aw148015 	} else {
   1107  6701  aw148015 		(void) ipc_mutex_lock(&controlstats_lock);
   1108  6701  aw148015 		bytes_io = controlstats.fs_bytes;
   1109  6701  aw148015 		(void) ipc_mutex_unlock(&controlstats_lock);
   1110  6701  aw148015 	}
   1111  5184  ek110237 
   1112  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1113  6701  aw148015 	if (bytes_io > byte_lim) {
   1114  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
   1115  6084  aw148015 		return (FILEBENCH_DONE);
   1116  5184  ek110237 	}
   1117  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1118  5184  ek110237 
   1119  6084  aw148015 	return (FILEBENCH_OK);
   1120  5184  ek110237 }
   1121  5184  ek110237 
   1122  5184  ek110237 /*
   1123  5184  ek110237  * Stop filebench run when specified number of I/O operations have
   1124  5184  ek110237  * been performed. Compares controlstats.fs_count with *flowop->value,
   1125  6084  aw148015  * and if greater returns 1, stopping the run, if not, returns FILEBENCH_OK
   1126  6084  aw148015  * to continue running.
   1127  5184  ek110237  */
   1128  5184  ek110237 static int
   1129  5184  ek110237 flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop)
   1130  5184  ek110237 {
   1131  5184  ek110237 	uint64_t ops;
   1132  6212  aw148015 	uint64_t count = flowop->fo_constvalue; /* use constant value */
   1133  5184  ek110237 
   1134  6701  aw148015 	if (flowop->fo_initted == 0) {
   1135  6701  aw148015 		filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
   1136  6701  aw148015 		    flowop, threadflow->tf_name, threadflow->tf_instance);
   1137  6701  aw148015 		flowop->fo_initted = 1;
   1138  6701  aw148015 
   1139  6701  aw148015 		if (flowoplib_event_find_target(threadflow, flowop)
   1140  6701  aw148015 		    == FILEBENCH_ERROR)
   1141  6701  aw148015 			return (FILEBENCH_ERROR);
   1142  6701  aw148015 	}
   1143  6701  aw148015 
   1144  6701  aw148015 	if (flowop->fo_targets) {
   1145  6701  aw148015 		ops = flowop->fo_targets->fo_stats.fs_count;
   1146  6701  aw148015 	} else {
   1147  6701  aw148015 		(void) ipc_mutex_lock(&controlstats_lock);
   1148  6701  aw148015 		ops = controlstats.fs_count;
   1149  6701  aw148015 		(void) ipc_mutex_unlock(&controlstats_lock);
   1150  6701  aw148015 	}
   1151  5184  ek110237 
   1152  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1153  6084  aw148015 	if (ops >= count) {
   1154  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
   1155  6084  aw148015 		return (FILEBENCH_DONE);
   1156  5184  ek110237 	}
   1157  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1158  5184  ek110237 
   1159  6084  aw148015 	return (FILEBENCH_OK);
   1160  5184  ek110237 }
   1161  5184  ek110237 
   1162  5184  ek110237 /*
   1163  5184  ek110237  * Semaphore synchronization using either System V semaphores or
   1164  5184  ek110237  * posix semaphores. If System V semaphores are available, they will be
   1165  5184  ek110237  * used, otherwise posix semaphores will be used.
   1166  5184  ek110237  */
   1167  5184  ek110237 
   1168  5184  ek110237 
   1169  5184  ek110237 /*
   1170  5184  ek110237  * Initializes the filebench "block on semaphore" flowop.
   1171  5184  ek110237  * If System V semaphores are implemented, the routine
   1172  5184  ek110237  * initializes the System V semaphore subsystem if it hasn't
   1173  5184  ek110237  * already been initialized, also allocates a pair of semids
   1174  5184  ek110237  * and initializes the highwater System V semaphore.
   1175  5184  ek110237  * If no System V semaphores, then does nothing special.
   1176  6084  aw148015  * Returns FILEBENCH_ERROR if it cannot acquire a set of System V semphores
   1177  6084  aw148015  * or if the initial post to the semaphore set fails. Returns FILEBENCH_OK
   1178  5184  ek110237  * on success.
   1179  5184  ek110237  */
   1180  5184  ek110237 static int
   1181  5184  ek110237 flowoplib_semblock_init(flowop_t *flowop)
   1182  5184  ek110237 {
   1183  5184  ek110237 
   1184  5184  ek110237 #ifdef HAVE_SYSV_SEM
   1185  6391  aw148015 	int sys_semid;
   1186  5184  ek110237 	struct sembuf sbuf[2];
   1187  5184  ek110237 	int highwater;
   1188  5184  ek110237 
   1189  5184  ek110237 	ipc_seminit();
   1190  5184  ek110237 
   1191  5184  ek110237 	flowop->fo_semid_lw = ipc_semidalloc();
   1192  5184  ek110237 	flowop->fo_semid_hw = ipc_semidalloc();
   1193  5184  ek110237 
   1194  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "flow %s-%d semblock init semid=%x",
   1195  5184  ek110237 	    flowop->fo_name, flowop->fo_instance, flowop->fo_semid_lw);
   1196  5184  ek110237 
   1197  6391  aw148015 	sys_semid = filebench_shm->shm_sys_semid;
   1198  5184  ek110237 
   1199  5184  ek110237 	if ((highwater = flowop->fo_semid_hw) == 0)
   1200  6212  aw148015 		highwater = flowop->fo_constvalue; /* use constant value */
   1201  5184  ek110237 
   1202  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "setting highwater to : %d", highwater);
   1203  5184  ek110237 
   1204  5673  aw148015 	sbuf[0].sem_num = (short)highwater;
   1205  6212  aw148015 	sbuf[0].sem_op = avd_get_int(flowop->fo_highwater);
   1206  5184  ek110237 	sbuf[0].sem_flg = 0;
   1207  6391  aw148015 	if ((semop(sys_semid, &sbuf[0], 1) == -1) && errno) {
   1208  5184  ek110237 		filebench_log(LOG_ERROR, "semblock init post failed: %s (%d,"
   1209  5184  ek110237 		    "%d)", strerror(errno), sbuf[0].sem_num, sbuf[0].sem_op);
   1210  6084  aw148015 		return (FILEBENCH_ERROR);
   1211  5184  ek110237 	}
   1212  5184  ek110237 #else
   1213  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL,
   1214  5184  ek110237 	    "flow %s-%d semblock init with posix semaphore",
   1215  5184  ek110237 	    flowop->fo_name, flowop->fo_instance);
   1216  5184  ek110237 
   1217  5184  ek110237 	sem_init(&flowop->fo_sem, 1, 0);
   1218  5184  ek110237 #endif	/* HAVE_SYSV_SEM */
   1219  5184  ek110237 
   1220  6212  aw148015 	if (!(avd_get_bool(flowop->fo_blocking)))
   1221  5184  ek110237 		(void) ipc_mutex_unlock(&flowop->fo_lock);
   1222  5184  ek110237 
   1223  6084  aw148015 	return (FILEBENCH_OK);
   1224  5184  ek110237 }
   1225  5184  ek110237 
   1226  5184  ek110237 /*
   1227  5184  ek110237  * Releases the semids for the System V semaphore allocated
   1228  5184  ek110237  * to this flowop. If not using System V semaphores, then
   1229  6084  aw148015  * it is effectively just a no-op.
   1230  5184  ek110237  */
   1231  5184  ek110237 static void
   1232  5184  ek110237 flowoplib_semblock_destruct(flowop_t *flowop)
   1233  5184  ek110237 {
   1234  5184  ek110237 #ifdef HAVE_SYSV_SEM
   1235  5184  ek110237 	ipc_semidfree(flowop->fo_semid_lw);
   1236  5184  ek110237 	ipc_semidfree(flowop->fo_semid_hw);
   1237  5184  ek110237 #else
   1238  5184  ek110237 	sem_destroy(&flowop->fo_sem);
   1239  5184  ek110237 #endif /* HAVE_SYSV_SEM */
   1240  5184  ek110237 }
   1241  5184  ek110237 
   1242  5184  ek110237 /*
   1243  5184  ek110237  * Attempts to pass a System V or posix semaphore as appropriate,
   1244  6084  aw148015  * and blocks if necessary. Returns FILEBENCH_ERROR if a set of System V
   1245  5184  ek110237  * semphores is not available or cannot be acquired, or if the initial
   1246  6084  aw148015  * post to the semaphore set fails. Returns FILEBENCH_OK on success.
   1247  5184  ek110237  */
   1248  5184  ek110237 static int
   1249  5184  ek110237 flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop)
   1250  5184  ek110237 {
   1251  5184  ek110237 
   1252  5184  ek110237 #ifdef HAVE_SYSV_SEM
   1253  5184  ek110237 	struct sembuf sbuf[2];
   1254  6212  aw148015 	int value = avd_get_int(flowop->fo_value);
   1255  6391  aw148015 	int sys_semid;
   1256  5184  ek110237 	struct timespec timeout;
   1257  5184  ek110237 
   1258  6391  aw148015 	sys_semid = filebench_shm->shm_sys_semid;
   1259  5184  ek110237 
   1260  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL,
   1261  5184  ek110237 	    "flow %s-%d sem blocking on id %x num %x value %d",
   1262  6391  aw148015 	    flowop->fo_name, flowop->fo_instance, sys_semid,
   1263  5184  ek110237 	    flowop->fo_semid_hw, value);
   1264  5184  ek110237 
   1265  5184  ek110237 	/* Post, decrement the increment the hw queue */
   1266  5184  ek110237 	sbuf[0].sem_num = flowop->fo_semid_hw;
   1267  5673  aw148015 	sbuf[0].sem_op = (short)value;
   1268  5184  ek110237 	sbuf[0].sem_flg = 0;
   1269  5184  ek110237 	sbuf[1].sem_num = flowop->fo_semid_lw;
   1270  5184  ek110237 	sbuf[1].sem_op = value * -1;
   1271  5184  ek110237 	sbuf[1].sem_flg = 0;
   1272  5184  ek110237 	timeout.tv_sec = 600;
   1273  5184  ek110237 	timeout.tv_nsec = 0;
   1274  5184  ek110237 
   1275  6212  aw148015 	if (avd_get_bool(flowop->fo_blocking))
   1276  5184  ek110237 		(void) ipc_mutex_unlock(&flowop->fo_lock);
   1277  5184  ek110237 
   1278  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1279  5184  ek110237 
   1280  5184  ek110237 #ifdef HAVE_SEMTIMEDOP
   1281  6391  aw148015 	(void) semtimedop(sys_semid, &sbuf[0], 1, &timeout);
   1282  6391  aw148015 	(void) semtimedop(sys_semid, &sbuf[1], 1, &timeout);
   1283  5184  ek110237 #else
   1284  6391  aw148015 	(void) semop(sys_semid, &sbuf[0], 1);
   1285  6391  aw148015 	(void) semop(sys_semid, &sbuf[1], 1);
   1286  5184  ek110237 #endif /* HAVE_SEMTIMEDOP */
   1287  5184  ek110237 
   1288  6212  aw148015 	if (avd_get_bool(flowop->fo_blocking))
   1289  5184  ek110237 		(void) ipc_mutex_lock(&flowop->fo_lock);
   1290  5184  ek110237 
   1291  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1292  5184  ek110237 
   1293  5184  ek110237 #else
   1294  6212  aw148015 	int value = avd_get_int(flowop->fo_value);
   1295  5184  ek110237 	int i;
   1296  5184  ek110237 
   1297  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL,
   1298  5184  ek110237 	    "flow %s-%d sem blocking on posix semaphore",
   1299  5184  ek110237 	    flowop->fo_name, flowop->fo_instance);
   1300  5184  ek110237 
   1301  5184  ek110237 	/* Decrement sem by value */
   1302  5184  ek110237 	for (i = 0; i < value; i++) {
   1303  5184  ek110237 		if (sem_wait(&flowop->fo_sem) == -1) {
   1304  5184  ek110237 			filebench_log(LOG_ERROR, "semop wait failed");
   1305  6084  aw148015 			return (FILEBENCH_ERROR);
   1306  5184  ek110237 		}
   1307  5184  ek110237 	}
   1308  5184  ek110237 
   1309  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL, "flow %s-%d sem unblocking",
   1310  5184  ek110237 	    flowop->fo_name, flowop->fo_instance);
   1311  5184  ek110237 #endif /* HAVE_SYSV_SEM */
   1312  5184  ek110237 
   1313  6084  aw148015 	return (FILEBENCH_OK);
   1314  5184  ek110237 }
   1315  5184  ek110237 
   1316  5184  ek110237 /*
   1317  6084  aw148015  * Calls ipc_seminit(). Always returns FILEBENCH_OK.
   1318  5184  ek110237  */
   1319  5184  ek110237 /* ARGSUSED */
   1320  5184  ek110237 static int
   1321  5184  ek110237 flowoplib_sempost_init(flowop_t *flowop)
   1322  5184  ek110237 {
   1323  5184  ek110237 #ifdef HAVE_SYSV_SEM
   1324  5184  ek110237 	ipc_seminit();
   1325  5184  ek110237 #endif /* HAVE_SYSV_SEM */
   1326  6084  aw148015 	return (FILEBENCH_OK);
   1327  5184  ek110237 }
   1328  5184  ek110237 
   1329  5184  ek110237 /*
   1330  5184  ek110237  * Post to a System V or posix semaphore as appropriate.
   1331  5184  ek110237  * On the first call for a given flowop instance, this routine
   1332  5184  ek110237  * will use the fo_targetname attribute to locate all semblock
   1333  5184  ek110237  * flowops that are expecting posts from this flowop. All
   1334  5184  ek110237  * target flowops on this list will have a post operation done
   1335  5184  ek110237  * to their semaphores on each call.
   1336  5184  ek110237  */
   1337  5184  ek110237 static int
   1338  5184  ek110237 flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop)
   1339  5184  ek110237 {
   1340  5184  ek110237 	flowop_t *target;
   1341  5184  ek110237 
   1342  5184  ek110237 	filebench_log(LOG_DEBUG_IMPL,
   1343  5184  ek110237 	    "sempost flow %s-%d",
   1344  5184  ek110237 	    flowop->fo_name,
   1345  5184  ek110237 	    flowop->fo_instance);
   1346  5184  ek110237 
   1347  5184  ek110237 	/* if this is the first post, create the post list */
   1348  5184  ek110237 	if (flowop->fo_targets == NULL) {
   1349  5184  ek110237 		flowop_t *result = flowop_find(flowop->fo_targetname);
   1350  5184  ek110237 
   1351  5184  ek110237 		flowop->fo_targets = result;
   1352  5184  ek110237 
   1353  5184  ek110237 		if (result == NULL) {
   1354  5184  ek110237 			filebench_log(LOG_ERROR,
   1355  5184  ek110237 			    "sempost: could not find op %s for thread %s",
   1356  5184  ek110237 			    flowop->fo_targetname,
   1357  5184  ek110237 			    threadflow->tf_name);
   1358  5184  ek110237 			filebench_shutdown(1);
   1359  5184  ek110237 		}
   1360  5184  ek110237 
   1361  5184  ek110237 		while (result) {
   1362  5184  ek110237 			result->fo_targetnext =
   1363  5184  ek110237 			    result->fo_resultnext;
   1364  5184  ek110237 			result = result->fo_resultnext;
   1365  5184  ek110237 		}
   1366  5184  ek110237 	}
   1367  5184  ek110237 
   1368  5184  ek110237 	target = flowop->fo_targets;
   1369  5184  ek110237 
   1370  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1371  5184  ek110237 	/* post to the targets */
   1372  5184  ek110237 	while (target) {
   1373  5184  ek110237 #ifdef HAVE_SYSV_SEM
   1374  5184  ek110237 		struct sembuf sbuf[2];
   1375  6391  aw148015 		int sys_semid;
   1376  5184  ek110237 		int blocking;
   1377  5184  ek110237 #else
   1378  5184  ek110237 		int i;
   1379  5184  ek110237 #endif /* HAVE_SYSV_SEM */
   1380  5184  ek110237 		struct timespec timeout;
   1381  6550  aw148015 		int value = (int)avd_get_int(flowop->fo_value);
   1382  5184  ek110237 
   1383  5184  ek110237 		if (target->fo_instance == FLOW_MASTER) {
   1384  5184  ek110237 			target = target->fo_targetnext;
   1385  5184  ek110237 			continue;
   1386  5184  ek110237 		}
   1387  5184  ek110237 
   1388  5184  ek110237 #ifdef HAVE_SYSV_SEM
   1389  5184  ek110237 
   1390  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL,
   1391  5184  ek110237 		    "sempost flow %s-%d num %x",
   1392  5184  ek110237 		    target->fo_name,
   1393  5184  ek110237 		    target->fo_instance,
   1394  5184  ek110237 		    target->fo_semid_lw);
   1395  5184  ek110237 
   1396  6391  aw148015 		sys_semid = filebench_shm->shm_sys_semid;
   1397  5184  ek110237 		sbuf[0].sem_num = target->fo_semid_lw;
   1398  5673  aw148015 		sbuf[0].sem_op = (short)value;
   1399  5184  ek110237 		sbuf[0].sem_flg = 0;
   1400  5184  ek110237 		sbuf[1].sem_num = target->fo_semid_hw;
   1401  5184  ek110237 		sbuf[1].sem_op = value * -1;
   1402  5184  ek110237 		sbuf[1].sem_flg = 0;
   1403  5184  ek110237 		timeout.tv_sec = 600;
   1404  5184  ek110237 		timeout.tv_nsec = 0;
   1405  5184  ek110237 
   1406  6212  aw148015 		if (avd_get_bool(flowop->fo_blocking))
   1407  5184  ek110237 			blocking = 1;
   1408  5184  ek110237 		else
   1409  5184  ek110237 			blocking = 0;
   1410  5184  ek110237 
   1411  5184  ek110237 #ifdef HAVE_SEMTIMEDOP
   1412  6391  aw148015 		if ((semtimedop(sys_semid, &sbuf[0], blocking + 1,
   1413  5184  ek110237 		    &timeout) == -1) && (errno && (errno != EAGAIN))) {
   1414  5184  ek110237 #else
   1415  6391  aw148015 		if ((semop(sys_semid, &sbuf[0], blocking + 1) == -1) &&
   1416  5184  ek110237 		    (errno && (errno != EAGAIN))) {
   1417  5184  ek110237 #endif /* HAVE_SEMTIMEDOP */
   1418  5184  ek110237 			filebench_log(LOG_ERROR, "semop post failed: %s",
   1419  5184  ek110237 			    strerror(errno));
   1420  6084  aw148015 			return (FILEBENCH_ERROR);
   1421  5184  ek110237 		}
   1422  5184  ek110237 
   1423  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL,
   1424  5184  ek110237 		    "flow %s-%d finished posting",
   1425  5184  ek110237 		    target->fo_name, target->fo_instance);
   1426  5184  ek110237 #else
   1427  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL,
   1428  5184  ek110237 		    "sempost flow %s-%d to posix semaphore",
   1429  5184  ek110237 		    target->fo_name,
   1430  5184  ek110237 		    target->fo_instance);
   1431  5184  ek110237 
   1432  5184  ek110237 		/* Increment sem by value */
   1433  5184  ek110237 		for (i = 0; i < value; i++) {
   1434  5184  ek110237 			if (sem_post(&target->fo_sem) == -1) {
   1435  5184  ek110237 				filebench_log(LOG_ERROR, "semop post failed");
   1436  6084  aw148015 				return (FILEBENCH_ERROR);
   1437  5184  ek110237 			}
   1438  5184  ek110237 		}
   1439  5184  ek110237 
   1440  5184  ek110237 		filebench_log(LOG_DEBUG_IMPL, "flow %s-%d unblocking",
   1441  5184  ek110237 		    target->fo_name, target->fo_instance);
   1442  5184  ek110237 #endif /* HAVE_SYSV_SEM */
   1443  5184  ek110237 
   1444  5184  ek110237 		target = target->fo_targetnext;
   1445  5184  ek110237 	}
   1446  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1447  5184  ek110237 
   1448  6084  aw148015 	return (FILEBENCH_OK);
   1449  5184  ek110237 }
   1450  5184  ek110237 
   1451  5184  ek110237 
   1452  5184  ek110237 /*
   1453  5184  ek110237  * Section for exercising create / open / close / delete operations
   1454  5184  ek110237  * on files within a fileset. For proper operation, the flowop attribute
   1455  5184  ek110237  * "fd", which sets the fo_fdnumber field in the flowop, must be used
   1456  5184  ek110237  * so that the same file is opened and later closed. "fd" is an index
   1457  5184  ek110237  * into a pair of arrays maintained by threadflows, one of which
   1458  5184  ek110237  * contains the operating system assigned file descriptors and the other
   1459  5184  ek110237  * a pointer to the filesetentry whose file the file descriptor
   1460  5184  ek110237  * references. An openfile flowop defined without fd being set will use
   1461  5184  ek110237  * the default (0) fd or, if specified, rotate through fd indices, but
   1462  5184  ek110237  * createfile and closefile must use the default or a specified fd.
   1463  5184  ek110237  * Meanwhile deletefile picks and arbitrary file to delete, regardless
   1464  5184  ek110237  * of fd attribute.
   1465  5184  ek110237  */
   1466  5184  ek110237 
   1467  5184  ek110237 /*
   1468  5184  ek110237  * Emulates (and actually does) file open. Obtains a file descriptor
   1469  6084  aw148015  * index, then calls flowoplib_openfile_common() to open. Returns
   1470  6084  aw148015  * FILEBENCH_ERROR if no file descriptor is found, and returns the
   1471  6084  aw148015  * status from flowoplib_openfile_common otherwise (FILEBENCH_ERROR,
   1472  6084  aw148015  * FILEBENCH_NORSC, FILEBENCH_OK).
   1473  5184  ek110237  */
   1474  5184  ek110237 static int
   1475  5184  ek110237 flowoplib_openfile(threadflow_t *threadflow, flowop_t *flowop)
   1476  5184  ek110237 {
   1477  5184  ek110237 	int fd = flowoplib_fdnum(threadflow, flowop);
   1478  5184  ek110237 
   1479  5184  ek110237 	if (fd == -1)
   1480  6084  aw148015 		return (FILEBENCH_ERROR);
   1481  5184  ek110237 
   1482  5184  ek110237 	return (flowoplib_openfile_common(threadflow, flowop, fd));
   1483  5184  ek110237 }
   1484  5184  ek110237 
   1485  5184  ek110237 /*
   1486  5184  ek110237  * Common file opening code for filesets. Uses the supplied
   1487  5184  ek110237  * file descriptor index to determine the tf_fd entry to use.
   1488  5184  ek110237  * If the entry is empty (0) and the fileset exists, fileset
   1489  5184  ek110237  * pick is called to select a fileset entry to use. The file
   1490  5184  ek110237  * specified in the filesetentry is opened, and the returned
   1491  5184  ek110237  * operating system file descriptor and a pointer to the
   1492  5184  ek110237  * filesetentry are stored in tf_fd[fd] and tf_fse[fd],
   1493  6084  aw148015  * respectively. Returns FILEBENCH_ERROR on error,
   1494  6084  aw148015  * FILEBENCH_NORSC if no suitable filesetentry can be found,
   1495  6084  aw148015  * and FILEBENCH_OK on success.
   1496  5184  ek110237  */
   1497  5184  ek110237 static int
   1498  5184  ek110237 flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd)
   1499  5184  ek110237 {
   1500  5184  ek110237 	filesetentry_t *file;
   1501  6212  aw148015 	char *fileset_name;
   1502  5184  ek110237 	int tid = 0;
   1503  9326    Andrew 	int openflag = 0;
   1504  8404    Andrew 	int err;
   1505  6212  aw148015 
   1506  6391  aw148015 	if (flowop->fo_fileset == NULL) {
   1507  6391  aw148015 		filebench_log(LOG_ERROR, "flowop NULL file");
   1508  6391  aw148015 		return (FILEBENCH_ERROR);
   1509  6391  aw148015 	}
   1510  6391  aw148015 
   1511  6212  aw148015 	if ((fileset_name =
   1512  6212  aw148015 	    avd_get_str(flowop->fo_fileset->fs_name)) == NULL) {
   1513  6212  aw148015 		filebench_log(LOG_ERROR,
   1514  6212  aw148015 		    "flowop %s: fileset has no name", flowop->fo_name);
   1515  6212  aw148015 		return (FILEBENCH_ERROR);
   1516  6212  aw148015 	}
   1517  9326    Andrew 
   1518  9326    Andrew 	/*
   1519  9326    Andrew 	 * set the open flag for read only or read/write, as appropriate.
   1520  9326    Andrew 	 */
   1521  9326    Andrew 	if (avd_get_bool(flowop->fo_fileset->fs_readonly) == TRUE)
   1522  9326    Andrew 		openflag = O_RDONLY;
   1523  9326    Andrew 	else
   1524  9326    Andrew 		openflag = O_RDWR;
   1525  5184  ek110237 
   1526  5184  ek110237 	/*
   1527  5184  ek110237 	 * If the flowop doesn't default to persistent fd
   1528  5184  ek110237 	 * then get unique thread ID for use by fileset_pick
   1529  5184  ek110237 	 */
   1530  6212  aw148015 	if (avd_get_bool(flowop->fo_rotatefd))
   1531  5184  ek110237 		tid = threadflow->tf_utid;
   1532  5184  ek110237 
   1533  8615    Andrew 	if (threadflow->tf_fd[fd].fd_ptr != NULL) {
   1534  5184  ek110237 		filebench_log(LOG_ERROR,
   1535  5184  ek110237 		    "flowop %s attempted to open without closing on fd %d",
   1536  5184  ek110237 		    flowop->fo_name, fd);
   1537  6084  aw148015 		return (FILEBENCH_ERROR);
   1538  5184  ek110237 	}
   1539  5184  ek110237 
   1540  5673  aw148015 #ifdef HAVE_RAW_SUPPORT
   1541  5673  aw148015 	if (flowop->fo_fileset->fs_attrs & FILESET_IS_RAW_DEV) {
   1542  5673  aw148015 		int open_attrs = 0;
   1543  5673  aw148015 		char name[MAXPATHLEN];
   1544  5673  aw148015 
   1545  7946    Andrew 		(void) fb_strlcpy(name,
   1546  7946    Andrew 		    avd_get_str(flowop->fo_fileset->fs_path), MAXPATHLEN);
   1547  7946    Andrew 		(void) fb_strlcat(name, "/", MAXPATHLEN);
   1548  7946    Andrew 		(void) fb_strlcat(name, fileset_name, MAXPATHLEN);
   1549  5673  aw148015 
   1550  6212  aw148015 		if (avd_get_bool(flowop->fo_dsync)) {
   1551  5673  aw148015 #ifdef sun
   1552  5673  aw148015 			open_attrs |= O_DSYNC;
   1553  5673  aw148015 #else
   1554  5673  aw148015 			open_attrs |= O_FSYNC;
   1555  5673  aw148015 #endif
   1556  5673  aw148015 		}
   1557  5673  aw148015 
   1558  5673  aw148015 		filebench_log(LOG_DEBUG_SCRIPT,
   1559  5673  aw148015 		    "open raw device %s flags %d = %d", name, open_attrs, fd);
   1560  5673  aw148015 
   1561  8615    Andrew 		if (FB_OPEN(&(threadflow->tf_fd[fd]), name,
   1562  9326    Andrew 		    openflag | open_attrs, 0666) == FILEBENCH_ERROR) {
   1563  5673  aw148015 			filebench_log(LOG_ERROR,
   1564  5673  aw148015 			    "Failed to open raw device %s: %s",
   1565  5673  aw148015 			    name, strerror(errno));
   1566  6084  aw148015 			return (FILEBENCH_ERROR);
   1567  5673  aw148015 		}
   1568  5673  aw148015 
   1569  5673  aw148015 		/* if running on Solaris, use un-buffered io */
   1570  5673  aw148015 #ifdef sun
   1571  8615    Andrew 		(void) directio(threadflow->tf_fd[fd].fd_num, DIRECTIO_ON);
   1572  5673  aw148015 #endif
   1573  5673  aw148015 
   1574  5673  aw148015 		threadflow->tf_fse[fd] = NULL;
   1575  5673  aw148015 
   1576  6084  aw148015 		return (FILEBENCH_OK);
   1577  5673  aw148015 	}
   1578  5673  aw148015 #endif /* HAVE_RAW_SUPPORT */
   1579  5673  aw148015 
   1580  8404    Andrew 	if ((err = flowoplib_pickfile(&file, flowop,
   1581  8404    Andrew 	    FILESET_PICKEXISTS, tid)) != FILEBENCH_OK) {
   1582  6084  aw148015 		filebench_log(LOG_DEBUG_SCRIPT,
   1583  5184  ek110237 		    "flowop %s failed to pick file from %s on fd %d",
   1584  6212  aw148015 		    flowop->fo_name, fileset_name, fd);
   1585  8404    Andrew 		return (err);
   1586  5184  ek110237 	}
   1587  5184  ek110237 
   1588  5184  ek110237 	threadflow->tf_fse[fd] = file;
   1589  5184  ek110237 
   1590  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1591  8615    Andrew 	err = fileset_openfile(&threadflow->tf_fd[fd], flowop->fo_fileset,
   1592  9326    Andrew 	    file, openflag, 0666, flowoplib_fileattrs(flowop));
   1593  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1594  5184  ek110237 
   1595  8615    Andrew 	if (err == FILEBENCH_ERROR) {
   1596  6212  aw148015 		filebench_log(LOG_ERROR, "flowop %s failed to open file %s",
   1597  6212  aw148015 		    flowop->fo_name, file->fse_path);
   1598  6084  aw148015 		return (FILEBENCH_ERROR);
   1599  5184  ek110237 	}
   1600  5184  ek110237 
   1601  5184  ek110237 	filebench_log(LOG_DEBUG_SCRIPT,
   1602  5184  ek110237 	    "flowop %s: opened %s fd[%d] = %d",
   1603  5184  ek110237 	    flowop->fo_name, file->fse_path, fd, threadflow->tf_fd[fd]);
   1604  5184  ek110237 
   1605  6084  aw148015 	return (FILEBENCH_OK);
   1606  5184  ek110237 }
   1607  5184  ek110237 
   1608  5184  ek110237 /*
   1609  5184  ek110237  * Emulate create of a file. Uses the flowop's fdnumber to select
   1610  5184  ek110237  * tf_fd and tf_fse array locations to put the created file's file
   1611  8404    Andrew  * descriptor and filesetentry respectively. Uses flowoplib_pickfile()
   1612  5184  ek110237  * to select a specific filesetentry whose file does not currently
   1613  5184  ek110237  * exist for the file create operation. Then calls
   1614  5184  ek110237  * fileset_openfile() with the O_CREATE flag set to create the
   1615  6084  aw148015  * file. Returns FILEBENCH_ERROR if the array index specified by fdnumber is
   1616  5184  ek110237  * already in use, the flowop has no associated fileset, or
   1617  5184  ek110237  * the create call fails. Returns 1 if a filesetentry with a
   1618  6084  aw148015  * nonexistent file cannot be found. Returns FILEBENCH_OK on success.
   1619  5184  ek110237  */
   1620  5184  ek110237 static int
   1621  5184  ek110237 flowoplib_createfile(threadflow_t *threadflow, flowop_t *flowop)
   1622  5184  ek110237 {
   1623  5184  ek110237 	filesetentry_t *file;
   1624  5184  ek110237 	int fd = flowop->fo_fdnumber;
   1625  8404    Andrew 	int err;
   1626  5184  ek110237 
   1627  8615    Andrew 	if (threadflow->tf_fd[fd].fd_ptr != NULL) {
   1628  5184  ek110237 		filebench_log(LOG_ERROR,
   1629  5184  ek110237 		    "flowop %s attempted to create without closing on fd %d",
   1630  5184  ek110237 		    flowop->fo_name, fd);
   1631  6084  aw148015 		return (FILEBENCH_ERROR);
   1632  5184  ek110237 	}
   1633  5184  ek110237 
   1634  5184  ek110237 	if (flowop->fo_fileset == NULL) {
   1635  5184  ek110237 		filebench_log(LOG_ERROR, "flowop NULL file");
   1636  6084  aw148015 		return (FILEBENCH_ERROR);
   1637  5184  ek110237 	}
   1638  9326    Andrew 
   1639  9326    Andrew 	if (avd_get_bool(flowop->fo_fileset->fs_readonly) == TRUE) {
   1640  9326    Andrew 		filebench_log(LOG_ERROR, "Can not CREATE the READONLY file %s",
   1641  9326    Andrew 		    avd_get_str(flowop->fo_fileset->fs_name));
   1642  9326    Andrew 		return (FILEBENCH_ERROR);
   1643  9326    Andrew 	}
   1644  9326    Andrew 
   1645  5184  ek110237 
   1646  5673  aw148015 #ifdef HAVE_RAW_SUPPORT
   1647  5673  aw148015 	/* can't be used with raw devices */
   1648  5673  aw148015 	if (flowop->fo_fileset->fs_attrs & FILESET_IS_RAW_DEV) {
   1649  5673  aw148015 		filebench_log(LOG_ERROR,
   1650  5673  aw148015 		    "flowop %s attempted to a createfile on RAW device",
   1651  5673  aw148015 		    flowop->fo_name);
   1652  6084  aw148015 		return (FILEBENCH_ERROR);
   1653  5673  aw148015 	}
   1654  5673  aw148015 #endif /* HAVE_RAW_SUPPORT */
   1655  5673  aw148015 
   1656  8404    Andrew 	if ((err = flowoplib_pickfile(&file, flowop,
   1657  8404    Andrew 	    FILESET_PICKNOEXIST, 0)) != FILEBENCH_OK) {
   1658  6084  aw148015 		filebench_log(LOG_DEBUG_SCRIPT,
   1659  6084  aw148015 		    "flowop %s failed to pick file from fileset %s",
   1660  6212  aw148015 		    flowop->fo_name,
   1661  6212  aw148015 		    avd_get_str(flowop->fo_fileset->fs_name));
   1662  8404    Andrew 		return (err);
   1663  5184  ek110237 	}
   1664  5184  ek110237 
   1665  5184  ek110237 	threadflow->tf_fse[fd] = file;
   1666  5184  ek110237 
   1667  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1668  8615    Andrew 	err = fileset_openfile(&threadflow->tf_fd[fd], flowop->fo_fileset,
   1669  5184  ek110237 	    file, O_RDWR | O_CREAT, 0666, flowoplib_fileattrs(flowop));
   1670  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1671  5184  ek110237 
   1672  8615    Andrew 	if (err == FILEBENCH_ERROR) {
   1673  5184  ek110237 		filebench_log(LOG_ERROR, "failed to create file %s",
   1674  5184  ek110237 		    flowop->fo_name);
   1675  6084  aw148015 		return (FILEBENCH_ERROR);
   1676  5184  ek110237 	}
   1677  5184  ek110237 
   1678  5184  ek110237 	filebench_log(LOG_DEBUG_SCRIPT,
   1679  5184  ek110237 	    "flowop %s: created %s fd[%d] = %d",
   1680  5184  ek110237 	    flowop->fo_name, file->fse_path, fd, threadflow->tf_fd[fd]);
   1681  5184  ek110237 
   1682  6084  aw148015 	return (FILEBENCH_OK);
   1683  5184  ek110237 }
   1684  5184  ek110237 
   1685  5184  ek110237 /*
   1686  6391  aw148015  * Emulates delete of a file. If a valid fd is provided, it uses the
   1687  6391  aw148015  * filesetentry stored at that fd location to select the file to be
   1688  6391  aw148015  * deleted, otherwise it picks an arbitrary filesetentry
   1689  6391  aw148015  * whose file exists. It then uses unlink() to delete it and Clears
   1690  6084  aw148015  * the FSE_EXISTS flag for the filesetentry. Returns FILEBENCH_ERROR if the
   1691  6084  aw148015  * flowop has no associated fileset. Returns FILEBENCH_NORSC if an appropriate
   1692  6084  aw148015  * filesetentry cannot be found, and FILEBENCH_OK on success.
   1693  5184  ek110237  */
   1694  5184  ek110237 static int
   1695  5184  ek110237 flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop)
   1696  5184  ek110237 {
   1697  5184  ek110237 	filesetentry_t *file;
   1698  5184  ek110237 	fileset_t *fileset;
   1699  5184  ek110237 	char path[MAXPATHLEN];
   1700  5184  ek110237 	char *pathtmp;
   1701  6391  aw148015 	int fd = flowop->fo_fdnumber;
   1702  5184  ek110237 
   1703  6391  aw148015 	/* if fd specified, use it to access file */
   1704  6391  aw148015 	if ((fd > 0) && ((file = threadflow->tf_fse[fd]) != NULL)) {
   1705  6391  aw148015 
   1706  6391  aw148015 		/* indicate that the file will be deleted */
   1707  6391  aw148015 		threadflow->tf_fse[fd] = NULL;
   1708  6391  aw148015 
   1709  6391  aw148015 		/* if here, we still have a valid file pointer */
   1710  6391  aw148015 		fileset = file->fse_fileset;
   1711  6391  aw148015 	} else {
   1712  8404    Andrew 
   1713  6391  aw148015 		/* Otherwise, pick arbitrary file */
   1714  6391  aw148015 		file = NULL;
   1715  6391  aw148015 		fileset = flowop->fo_fileset;
   1716  6391  aw148015 	}
   1717  6391  aw148015 
   1718  6391  aw148015 
   1719  6391  aw148015 	if (fileset == NULL) {
   1720  5184  ek110237 		filebench_log(LOG_ERROR, "flowop NULL file");
   1721  6084  aw148015 		return (FILEBENCH_ERROR);
   1722  5184  ek110237 	}
   1723  5184  ek110237 
   1724  5673  aw148015 #ifdef HAVE_RAW_SUPPORT
   1725  5673  aw148015 	/* can't be used with raw devices */
   1726  6391  aw148015 	if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
   1727  5673  aw148015 		filebench_log(LOG_ERROR,
   1728  5673  aw148015 		    "flowop %s attempted a deletefile on RAW device",
   1729  5673  aw148015 		    flowop->fo_name);
   1730  6084  aw148015 		return (FILEBENCH_ERROR);
   1731  5673  aw148015 	}
   1732  5673  aw148015 #endif /* HAVE_RAW_SUPPORT */
   1733  5673  aw148015 
   1734  6391  aw148015 	if (file == NULL) {
   1735  8404    Andrew 		int err;
   1736  8404    Andrew 
   1737  7556    Andrew 		/* pick arbitrary, existing (allocated) file */
   1738  8404    Andrew 		if ((err = flowoplib_pickfile(&file, flowop,
   1739  8404    Andrew 		    FILESET_PICKEXISTS, 0)) != FILEBENCH_OK) {
   1740  6391  aw148015 			filebench_log(LOG_DEBUG_SCRIPT,
   1741  6391  aw148015 			    "flowop %s failed to pick file", flowop->fo_name);
   1742  8404    Andrew 			return (err);
   1743  6391  aw148015 		}
   1744  6391  aw148015 	} else {
   1745  7556    Andrew 		/* delete specific file. wait for it to be non-busy */
   1746  7556    Andrew 		(void) ipc_mutex_lock(&fileset->fs_pick_lock);
   1747  7556    Andrew 		while (file->fse_flags & FSE_BUSY) {
   1748  7556    Andrew 			file->fse_flags |= FSE_THRD_WAITNG;
   1749  7556    Andrew 			(void) pthread_cond_wait(&fileset->fs_thrd_wait_cv,
   1750  7556    Andrew 			    &fileset->fs_pick_lock);
   1751  7556    Andrew 		}
   1752  7556    Andrew 
   1753  7556    Andrew 		/* File now available, grab it for deletion */
   1754  7556    Andrew 		file->fse_flags |= FSE_BUSY;
   1755  7556    Andrew 		fileset->fs_idle_files--;
   1756  7556    Andrew 		(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
   1757  5184  ek110237 	}
   1758  5184  ek110237 
   1759  8404    Andrew 	/* don't delete if anyone (other than me) has file open */
   1760  8615    Andrew 	if ((fd > 0) && (threadflow->tf_fd[fd].fd_num > 0)) {
   1761  8404    Andrew 		if (file->fse_open_cnt > 1) {
   1762  8404    Andrew 			filebench_log(LOG_DEBUG_SCRIPT,
   1763  8404    Andrew 			    "flowop %s can't delete file opened by other"
   1764  8404    Andrew 			    " threads at fd = %d", flowop->fo_name, fd);
   1765  8404    Andrew 			fileset_unbusy(file, FALSE, FALSE, 0);
   1766  8404    Andrew 			return (FILEBENCH_OK);
   1767  8404    Andrew 		} else {
   1768  8404    Andrew 			filebench_log(LOG_DEBUG_SCRIPT,
   1769  8404    Andrew 			    "flowop %s deleting still open file at fd = %d",
   1770  8404    Andrew 			    flowop->fo_name, fd);
   1771  8404    Andrew 		}
   1772  8404    Andrew 	} else if (file->fse_open_cnt > 0) {
   1773  8404    Andrew 		filebench_log(LOG_DEBUG_SCRIPT,
   1774  8404    Andrew 		    "flowop %s can't delete file opened by other"
   1775  8404    Andrew 		    " threads at fd = %d, open count = %d",
   1776  8404    Andrew 		    flowop->fo_name, fd, file->fse_open_cnt);
   1777  8404    Andrew 		fileset_unbusy(file, FALSE, FALSE, 0);
   1778  8404    Andrew 		return (FILEBENCH_OK);
   1779  8404    Andrew 	}
   1780  8404    Andrew 
   1781  7946    Andrew 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
   1782  7946    Andrew 	(void) fb_strlcat(path, "/", MAXPATHLEN);
   1783  7946    Andrew 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
   1784  5184  ek110237 	pathtmp = fileset_resolvepath(file);
   1785  7946    Andrew 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
   1786  5184  ek110237 	free(pathtmp);
   1787  5184  ek110237 
   1788  7556    Andrew 	/* delete the selected file */
   1789  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1790  8615    Andrew 	(void) FB_UNLINK(path);
   1791  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1792  7556    Andrew 
   1793  7556    Andrew 	/* indicate that it is no longer busy and no longer exists */
   1794  8404    Andrew 	fileset_unbusy(file, TRUE, FALSE, -file->fse_open_cnt);
   1795  5184  ek110237 
   1796  5184  ek110237 	filebench_log(LOG_DEBUG_SCRIPT, "deleted file %s", file->fse_path);
   1797  5184  ek110237 
   1798  6084  aw148015 	return (FILEBENCH_OK);
   1799  5184  ek110237 }
   1800  5184  ek110237 
   1801  5184  ek110237 /*
   1802  5184  ek110237  * Emulates fsync of a file. Obtains the file descriptor index
   1803  5184  ek110237  * from the flowop, obtains the actual file descriptor from
   1804  5184  ek110237  * the threadflow's table, checks to be sure it is still an
   1805  6084  aw148015  * open file, then does an fsync operation on it. Returns FILEBENCH_ERROR
   1806  6084  aw148015  * if the file no longer is open, FILEBENCH_OK otherwise.
   1807  5184  ek110237  */
   1808  5184  ek110237 static int
   1809  5184  ek110237 flowoplib_fsync(threadflow_t *threadflow, flowop_t *flowop)
   1810  5184  ek110237 {
   1811  5184  ek110237 	filesetentry_t *file;
   1812  5184  ek110237 	int fd = flowop->fo_fdnumber;
   1813  5184  ek110237 
   1814  8615    Andrew 	if (threadflow->tf_fd[fd].fd_ptr == NULL) {
   1815  5184  ek110237 		filebench_log(LOG_ERROR,
   1816  5184  ek110237 		    "flowop %s attempted to fsync a closed fd %d",
   1817  5184  ek110237 		    flowop->fo_name, fd);
   1818  6084  aw148015 		return (FILEBENCH_ERROR);
   1819  5184  ek110237 	}
   1820  5184  ek110237 
   1821  5673  aw148015 	file = threadflow->tf_fse[fd];
   1822  5673  aw148015 
   1823  5673  aw148015 	if ((file == NULL) ||
   1824  5673  aw148015 	    (file->fse_fileset->fs_attrs & FILESET_IS_RAW_DEV)) {
   1825  5673  aw148015 		filebench_log(LOG_ERROR,
   1826  5673  aw148015 		    "flowop %s attempted to a fsync a RAW device",
   1827  5673  aw148015 		    flowop->fo_name);
   1828  6084  aw148015 		return (FILEBENCH_ERROR);
   1829  5673  aw148015 	}
   1830  5673  aw148015 
   1831  5184  ek110237 	/* Measure time to fsync */
   1832  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1833  8615    Andrew 	(void) FB_FSYNC(&threadflow->tf_fd[fd]);
   1834  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1835  5184  ek110237 
   1836  5184  ek110237 	filebench_log(LOG_DEBUG_SCRIPT, "fsync file %s", file->fse_path);
   1837  5184  ek110237 
   1838  6084  aw148015 	return (FILEBENCH_OK);
   1839  5184  ek110237 }
   1840  5184  ek110237 
   1841  5184  ek110237 /*
   1842  5184  ek110237  * Emulate fsync of an entire fileset. Search through the
   1843  5184  ek110237  * threadflow's file descriptor array, doing fsync() on each
   1844  5184  ek110237  * open file that belongs to the flowop's fileset. Always
   1845  6084  aw148015  * returns FILEBENCH_OK.
   1846  5184  ek110237  */
   1847  5184  ek110237 static int
   1848  5184  ek110237 flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop)
   1849  5184  ek110237 {
   1850  5184  ek110237 	int fd;
   1851  5184  ek110237 
   1852  5184  ek110237 	for (fd = 0; fd < THREADFLOW_MAXFD; fd++) {
   1853  5184  ek110237 		filesetentry_t *file;
   1854  5184  ek110237 
   1855  5184  ek110237 		/* Match the file set to fsync */
   1856  5184  ek110237 		if ((threadflow->tf_fse[fd] == NULL) ||
   1857  5184  ek110237 		    (flowop->fo_fileset != threadflow->tf_fse[fd]->fse_fileset))
   1858  5184  ek110237 			continue;
   1859  5184  ek110237 
   1860  5184  ek110237 		/* Measure time to fsync */
   1861  5184  ek110237 		flowop_beginop(threadflow, flowop);
   1862  8615    Andrew 		(void) FB_FSYNC(&threadflow->tf_fd[fd]);
   1863  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
   1864  5184  ek110237 
   1865  5184  ek110237 		file = threadflow->tf_fse[fd];
   1866  5184  ek110237 
   1867  5184  ek110237 		filebench_log(LOG_DEBUG_SCRIPT, "fsync file %s",
   1868  5184  ek110237 		    file->fse_path);
   1869  5184  ek110237 	}
   1870  5184  ek110237 
   1871  6084  aw148015 	return (FILEBENCH_OK);
   1872  5184  ek110237 }
   1873  5184  ek110237 
   1874  5184  ek110237 /*
   1875  5184  ek110237  * Emulate close of a file.  Obtains the file descriptor index
   1876  5184  ek110237  * from the flowop, obtains the actual file descriptor from the
   1877  5184  ek110237  * threadflow's table, checks to be sure it is still an open
   1878  5184  ek110237  * file, then does a close operation on it. Then sets the
   1879  5184  ek110237  * threadflow file descriptor table entry to 0, and the file set
   1880  6084  aw148015  * entry pointer to NULL. Returns FILEBENCH_ERROR if the file was not open,
   1881  6084  aw148015  * FILEBENCH_OK otherwise.
   1882  5184  ek110237  */
   1883  5184  ek110237 static int
   1884  5184  ek110237 flowoplib_closefile(threadflow_t *threadflow, flowop_t *flowop)
   1885  5184  ek110237 {
   1886  5184  ek110237 	filesetentry_t *file;
   1887  8404    Andrew 	fileset_t *fileset;
   1888  5184  ek110237 	int fd = flowop->fo_fdnumber;
   1889  5184  ek110237 
   1890  8615    Andrew 	if (threadflow->tf_fd[fd].fd_ptr == NULL) {
   1891  5184  ek110237 		filebench_log(LOG_ERROR,
   1892  5184  ek110237 		    "flowop %s attempted to close an already closed fd %d",
   1893  5184  ek110237 		    flowop->fo_name, fd);
   1894  6084  aw148015 		return (FILEBENCH_ERROR);
   1895  5184  ek110237 	}
   1896  5184  ek110237 
   1897  8404    Andrew 	file = threadflow->tf_fse[fd];
   1898  8404    Andrew 	fileset = file->fse_fileset;
   1899  8404    Andrew 
   1900  8404    Andrew 	/* Wait for it to be non-busy */
   1901  8404    Andrew 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
   1902  8404    Andrew 	while (file->fse_flags & FSE_BUSY) {
   1903  8404    Andrew 		file->fse_flags |= FSE_THRD_WAITNG;
   1904  8404    Andrew 		(void) pthread_cond_wait(&fileset->fs_thrd_wait_cv,
   1905  8404    Andrew 		    &fileset->fs_pick_lock);
   1906  8404    Andrew 	}
   1907  8404    Andrew 
   1908  8404    Andrew 	/* File now available, grab it for closing */
   1909  8404    Andrew 	file->fse_flags |= FSE_BUSY;
   1910  8404    Andrew 
   1911  8404    Andrew 	/* if last open, set declare idle */
   1912  8404    Andrew 	if (file->fse_open_cnt == 1)
   1913  8404    Andrew 		fileset->fs_idle_files--;
   1914  8404    Andrew 
   1915  8404    Andrew 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
   1916  8404    Andrew 
   1917  5184  ek110237 	/* Measure time to close */
   1918  5184  ek110237 	flowop_beginop(threadflow, flowop);
   1919  8615    Andrew 	(void) FB_CLOSE(&threadflow->tf_fd[fd]);
   1920  5673  aw148015 	flowop_endop(threadflow, flowop, 0);
   1921  5184  ek110237 
   1922  8404    Andrew 	fileset_unbusy(file, FALSE, FALSE, -1);
   1923  5184  ek110237 
   1924  8615    Andrew 	threadflow->tf_fd[fd].fd_ptr = NULL;
   1925  5184  ek110237 
   1926  5184  ek110237 	filebench_log(LOG_DEBUG_SCRIPT, "closed file %s", file->fse_path);
   1927  7946    Andrew 
   1928  7946    Andrew 	return (FILEBENCH_OK);
   1929  7946    Andrew }
   1930  7946    Andrew 
   1931  7946    Andrew /*
   1932  7946    Andrew  * Obtain the full pathname of the directory described by the filesetentry
   1933  7946    Andrew  * indicated by "dir", and copy it into the character array pointed to by
   1934  7946    Andrew  * path. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
   1935  7946    Andrew  */
   1936  7946    Andrew static int
   1937  7946    Andrew flowoplib_getdirpath(filesetentry_t *dir, char *path)
   1938  7946    Andrew {
   1939  7946    Andrew 	char		*fileset_path;
   1940  7946    Andrew 	char		*fileset_name;
   1941  7946    Andrew 	char		*part_path;
   1942  7946    Andrew 
   1943  7946    Andrew 	if ((fileset_path = avd_get_str(dir->fse_fileset->fs_path)) == NULL) {
   1944  7946    Andrew 		filebench_log(LOG_ERROR, "Fileset path not set");
   1945  7946    Andrew 		return (FILEBENCH_ERROR);
   1946  7946    Andrew 	}
   1947  7946    Andrew 
   1948  7946    Andrew 	if ((fileset_name = avd_get_str(dir->fse_fileset->fs_name)) == NULL) {
   1949  7946    Andrew 		filebench_log(LOG_ERROR, "Fileset name not set");
   1950  7946    Andrew 		return (FILEBENCH_ERROR);
   1951  7946    Andrew 	}
   1952  7946    Andrew 
   1953  7946    Andrew 	(void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
   1954  7946    Andrew 	(void) fb_strlcat(path, "/", MAXPATHLEN);
   1955  7946    Andrew 	(void) fb_strlcat(path, fileset_name, MAXPATHLEN);
   1956  7946    Andrew 
   1957  7946    Andrew 	if ((part_path = fileset_resolvepath(dir)) == NULL)
   1958  7946    Andrew 		return (FILEBENCH_ERROR);
   1959  7946    Andrew 
   1960  7946    Andrew 	(void) fb_strlcat(path, part_path, MAXPATHLEN);
   1961  7946    Andrew 	free(part_path);
   1962  7946    Andrew 
   1963  7946    Andrew 	return (FILEBENCH_OK);
   1964  7946    Andrew }
   1965  7946    Andrew 
   1966  7946    Andrew /*
   1967  7946    Andrew  * Use mkdir to create a directory.  Obtains the fileset name from the
   1968  7946    Andrew  * flowop, selects a non-existent leaf directory and obtains its full
   1969  7946    Andrew  * path, then uses mkdir to create it on the storage subsystem (make it
   1970  7946    Andrew  * existent). Returns FILEBENCH_NORSC is there are no more non-existent
   1971  7946    Andrew  * directories in the fileset, FILEBENCH_ERROR on other errors, and
   1972  7946    Andrew  * FILEBENCH_OK on success.
   1973  7946    Andrew  */
   1974  7946    Andrew static int
   1975  7946    Andrew flowoplib_makedir(threadflow_t *threadflow, flowop_t *flowop)
   1976  7946    Andrew {
   1977  7946    Andrew 	filesetentry_t	*dir;
   1978  7946    Andrew 	int		ret;
   1979  7946    Andrew 	char		full_path[MAXPATHLEN];
   1980  7946    Andrew 
   1981  7946    Andrew 	if ((ret = flowoplib_pickleafdir(&dir, flowop,
   1982  7946    Andrew 	    FILESET_PICKNOEXIST)) != FILEBENCH_OK)
   1983  7946    Andrew 		return (ret);
   1984  7946    Andrew 
   1985  7946    Andrew 	if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
   1986  7946    Andrew 		return (ret);
   1987  7946    Andrew 
   1988  7946    Andrew 	flowop_beginop(threadflow, flowop);
   1989  8615    Andrew 	(void) FB_MKDIR(full_path, 0755);
   1990  7946    Andrew 	flowop_endop(threadflow, flowop, 0);
   1991  7946    Andrew 
   1992  7946    Andrew 	/* indicate that it is no longer busy and now exists */
   1993  8404    Andrew 	fileset_unbusy(dir, TRUE, TRUE, 0);
   1994  7946    Andrew 
   1995  7946    Andrew 	return (FILEBENCH_OK);
   1996  7946    Andrew }
   1997  7946    Andrew 
   1998  7946    Andrew /*
   1999  7946    Andrew  * Use rmdir to delete a directory.  Obtains the fileset name from the
   2000  7946    Andrew  * flowop, selects an existent leaf directory and obtains its full path,
   2001  7946    Andrew  * then uses rmdir to remove it from the storage subsystem (make it
   2002  7946    Andrew  * non-existent). Returns FILEBENCH_NORSC is there are no more existent
   2003  7946    Andrew  * directories in the fileset, FILEBENCH_ERROR on other errors, and
   2004  7946    Andrew  * FILEBENCH_OK on success.
   2005  7946    Andrew  */
   2006  7946    Andrew static int
   2007  7946    Andrew flowoplib_removedir(threadflow_t *threadflow, flowop_t *flowop)
   2008  7946    Andrew {
   2009  7946    Andrew 	filesetentry_t *dir;
   2010  7946    Andrew 	int		ret;
   2011  7946    Andrew 	char		full_path[MAXPATHLEN];
   2012  7946    Andrew 
   2013  7946    Andrew 	if ((ret = flowoplib_pickleafdir(&dir, flowop,
   2014  7946    Andrew 	    FILESET_PICKEXISTS)) != FILEBENCH_OK)
   2015  7946    Andrew 		return (ret);
   2016  7946    Andrew 
   2017  7946    Andrew 	if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
   2018  7946    Andrew 		return (ret);
   2019  7946    Andrew 
   2020  7946    Andrew 	flowop_beginop(threadflow, flowop);
   2021  8615    Andrew 	(void) FB_RMDIR(full_path);
   2022  7946    Andrew 	flowop_endop(threadflow, flowop, 0);
   2023  7946    Andrew 
   2024  7946    Andrew 	/* indicate that it is no longer busy and no longer exists */
   2025  8404    Andrew 	fileset_unbusy(dir, TRUE, FALSE, 0);
   2026  7946    Andrew 
   2027  7946    Andrew 	return (FILEBENCH_OK);
   2028  7946    Andrew }
   2029  7946    Andrew 
   2030  7946    Andrew /*
   2031  7946    Andrew  * Use opendir(), multiple readdir() calls, and closedir() to list the
   2032  7946    Andrew  * contents of a directory.  Obtains the fileset name from the
   2033  7946    Andrew  * flowop, selects a normal subdirectory (which always exist) and obtains
   2034  7946    Andrew  * its full path, then uses opendir() to get a DIR handle to it from the
   2035  7946    Andrew  * file system, a readdir() loop to access each directory entry, and
   2036  7946    Andrew  * finally cleans up with a closedir(). The latency reported is the total
   2037  7946    Andrew  * for all this activity, and it also reports the total number of bytes
   2038  7946    Andrew  * in the entries as the amount "read". Returns FILEBENCH_ERROR on errors,
   2039  7946    Andrew  * and FILEBENCH_OK on success.
   2040  7946    Andrew  */
   2041  7946    Andrew static int
   2042  7946    Andrew flowoplib_listdir(threadflow_t *threadflow, flowop_t *flowop)
   2043  7946    Andrew {
   2044  7946    Andrew 	fileset_t	*fileset;
   2045  7946    Andrew 	filesetentry_t	*dir;
   2046  8615    Andrew 	DIR		*dir_handle;
   2047  7946    Andrew 	struct dirent	*direntp;
   2048  7946    Andrew 	int		dir_bytes = 0;
   2049  7946    Andrew 	int		ret;
   2050  7946    Andrew 	char		full_path[MAXPATHLEN];
   2051  7946    Andrew 
   2052  7946    Andrew 	if ((fileset = flowop->fo_fileset) == NULL) {
   2053  7946    Andrew 		filebench_log(LOG_ERROR, "flowop NO fileset");
   2054  7946    Andrew 		return (FILEBENCH_ERROR);
   2055  7946    Andrew 	}
   2056  7946    Andrew 
   2057  8404    Andrew 	if ((dir = fileset_pick(fileset, FILESET_PICKDIR, 0, 0)) == NULL) {
   2058  7946    Andrew 		filebench_log(LOG_DEBUG_SCRIPT,
   2059  7946    Andrew 		    "flowop %s failed to pick directory from fileset %s",
   2060  7946    Andrew 		    flowop->fo_name,
   2061  7946    Andrew 		    avd_get_str(fileset->fs_name));
   2062  8404    Andrew 		return (FILEBENCH_ERROR);
   2063  7946    Andrew 	}
   2064  7946    Andrew 
   2065  7946    Andrew 	if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
   2066  7946    Andrew 		return (ret);
   2067  7946    Andrew 
   2068  7946    Andrew 	flowop_beginop(threadflow, flowop);
   2069  7946    Andrew 
   2070  7946    Andrew 	/* open the directory */
   2071  8615    Andrew 	if ((dir_handle = FB_OPENDIR(full_path)) == NULL) {
   2072  7946    Andrew 		filebench_log(LOG_ERROR,
   2073  7946    Andrew 		    "flowop %s failed to open directory in fileset %s\n",
   2074  7946    Andrew 		    flowop->fo_name, avd_get_str(fileset->fs_name));
   2075  7946    Andrew 		return (FILEBENCH_ERROR);
   2076  7946    Andrew 	}
   2077  7946    Andrew 
   2078  7946    Andrew 	/* read through the directory entries */
   2079  8615    Andrew 	while ((direntp = FB_READDIR(dir_handle)) != NULL) {
   2080  7946    Andrew 		dir_bytes += (strlen(direntp->d_name) +
   2081  7946    Andrew 		    sizeof (struct dirent) - 1);
   2082  7946    Andrew 	}
   2083  7946    Andrew 
   2084  7946    Andrew 	/* close the directory */
   2085  8615    Andrew 	(void) FB_CLOSEDIR(dir_handle);
   2086  7946    Andrew 
   2087  7946    Andrew 	flowop_endop(threadflow, flowop, dir_bytes);
   2088  7946    Andrew 
   2089  7946    Andrew 	/* indicate that it is no longer busy */
   2090  8404    Andrew 	fileset_unbusy(dir, FALSE, FALSE, 0);
   2091  7946    Andrew 
   2092  7946    Andrew 	return (FILEBENCH_OK);
   2093  7946    Andrew }
   2094  7946    Andrew 
   2095  7946    Andrew /*
   2096  5184  ek110237  * Emulate stat of a file. Picks an arbitrary filesetentry with
   2097  5184  ek110237  * an existing file from the flowop's fileset, then performs a
   2098  6084  aw148015  * stat() operation on it. Returns FILEBENCH_ERROR if the flowop has no
   2099  6084  aw148015  * associated fileset. Returns FILEBENCH_NORSC if an appropriate filesetentry
   2100  6084  aw148015  * cannot be found, and FILEBENCH_OK on success.
   2101  5184  ek110237  */
   2102  5184  ek110237 static int
   2103  5184  ek110237 flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop)
   2104  5184  ek110237 {
   2105  5184  ek110237 	filesetentry_t *file;
   2106  5184  ek110237 	fileset_t *fileset;
   2107  8615    Andrew 	struct stat64 statbuf;
   2108  7556    Andrew 	int fd = flowop->fo_fdnumber;
   2109  5184  ek110237 
   2110  7556    Andrew 	/* if fd specified and the file is open, use it to access file */
   2111  8615    Andrew 	if ((fd > 0) && (threadflow->tf_fd[fd].fd_num > 0)) {
   2112  7556    Andrew 
   2113  7556    Andrew 		/* check whether file handle still valid */
   2114  7556    Andrew 		if ((file = threadflow->tf_fse[fd]) == NULL) {
   2115  7556    Andrew 			filebench_log(LOG_DEBUG_SCRIPT,
   2116  7556    Andrew 			    "flowop %s trying to stat NULL file at fd = %d",
   2117  7556    Andrew 			    flowop->fo_name, fd);
   2118  7556    Andrew 			return (FILEBENCH_ERROR);
   2119  7556    Andrew 		}
   2120  7556    Andrew 
   2121  7556    Andrew 		/* if here, we still have a valid file pointer */
   2122  7556    Andrew 		fileset = file->fse_fileset;
   2123  7556    Andrew 	} else {
   2124  7556    Andrew 		/* Otherwise, pick arbitrary file */
   2125  7556    Andrew 		file = NULL;
   2126  7556    Andrew 		fileset = flowop->fo_fileset;
   2127  7556    Andrew 	}
   2128  7556    Andrew 
   2129  7556    Andrew 	if (fileset == NULL) {
   2130  7556    Andrew 		filebench_log(LOG_ERROR,
   2131  7556    Andrew 		    "statfile with no fileset specified");
   2132  6084  aw148015 		return (FILEBENCH_ERROR);
   2133  5184  ek110237 	}
   2134  5184  ek110237 
   2135  7556    Andrew #ifdef HAVE_RAW_SUPPORT
   2136  7556    Andrew 	/* can't be used with raw devices */
   2137  7556    Andrew 	if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
   2138  7556    Andrew 		filebench_log(LOG_ERROR,
   2139  7556    Andrew 		    "flowop %s attempted do a statfile on a RAW device",
   2140  5184  ek110237 		    flowop->fo_name);
   2141  7556    Andrew 		return (FILEBENCH_ERROR);
   2142  5184  ek110237 	}
   2143  7556    Andrew #endif /* HAVE_RAW_SUPPORT */
   2144  5184  ek110237 
   2145  7556    Andrew 	if (file == NULL) {
   2146  7556    Andrew 		char path[MAXPATHLEN];
   2147  7556    Andrew 		char *pathtmp;
   2148  8404    Andrew 		int err;
   2149  5184  ek110237 
   2150  7556    Andrew 		/* pick arbitrary, existing (allocated) file */
   2151  8404    Andrew 		if ((err = flowoplib_pickfile(&file, flowop,
   2152  8404    Andrew 		    FILESET_PICKEXISTS, 0)) != FILEBENCH_OK) {
   2153  7556    Andrew 			filebench_log(LOG_DEBUG_SCRIPT,
   2154  7556    Andrew 			    "Statfile flowop %s failed to pick file",
   2155  7556    Andrew 			    flowop->fo_name);
   2156  8404    Andrew 			return (err);
   2157  7556    Andrew 		}
   2158  5184  ek110237 
   2159  7556    Andrew 		/* resolve path and do a stat on file */
   2160  7946    Andrew 		(void) fb_strlcpy(path, avd_get_str(fileset->fs_path),
   2161  7946    Andrew 		    MAXPATHLEN);
   2162  7946    Andrew 		(void) fb_strlcat(path, "/", MAXPATHLEN);
   2163  7946    Andrew 		(void) fb_strlcat(path, avd_get_str(fileset->fs_name),
   2164  7946    Andrew 		    MAXPATHLEN);
   2165  7556    Andrew 		pathtmp = fileset_resolvepath(file);
   2166  7946    Andrew 		(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
   2167  7556    Andrew 		free(pathtmp);
   2168  7556    Andrew 
   2169  7556    Andrew 		/* stat the file */
   2170  7556    Andrew 		flowop_beginop(threadflow, flowop);
   2171  8615    Andrew 		if (FB_STAT(path, &statbuf) == -1)
   2172  7556    Andrew 			filebench_log(LOG_ERROR,
   2173  7556    Andrew 			    "statfile flowop %s failed", flowop->fo_name);
   2174  7556    Andrew 		flowop_endop(threadflow, flowop, 0);
   2175  7556    Andrew 
   2176  8404    Andrew 		fileset_unbusy(file, FALSE, FALSE, 0);
   2177  7556    Andrew 	} else {
   2178  7556    Andrew 		/* stat specific file */
   2179  7556    Andrew 		flowop_beginop(threadflow, flowop);
   2180  8615    Andrew 		if (FB_FSTAT(&threadflow->tf_fd[fd], &statbuf) == -1)
   2181  7556    Andrew 			filebench_log(LOG_ERROR,
   2182  7556    Andrew 			    "statfile flowop %s failed", flowop->fo_name);
   2183  7556    Andrew 		flowop_endop(threadflow, flowop, 0);
   2184  7556    Andrew 
   2185  7556    Andrew 	}
   2186  5184  ek110237 
   2187  6084  aw148015 	return (FILEBENCH_OK);
   2188  5184  ek110237 }
   2189  5184  ek110237 
   2190  5184  ek110237 
   2191  5184  ek110237 /*
   2192  5184  ek110237  * Additional reads and writes. Read and write whole files, write
   2193  5184  ek110237  * and append to files. Some of these work with both fileobjs and
   2194  5184  ek110237  * filesets, others only with filesets. The flowoplib_write routine
   2195  5184  ek110237  * writes from thread memory, while the others read or write using
   2196  5184  ek110237  * fo_buf memory. Note that both flowoplib_read() and
   2197  5184  ek110237  * flowoplib_aiowrite() use thread memory as well.
   2198  5184  ek110237  */
   2199  5184  ek110237 
   2200  5184  ek110237 
   2201  5184  ek110237 /*
   2202  5673  aw148015  * Emulate a read of a whole file. The file must be open with
   2203  5673  aw148015  * file descriptor and filesetentry stored at the locations indexed
   2204  5673  aw148015  * by the flowop's fdnumber. It then seeks to the beginning of the
   2205  5673  aw148015  * associated file, and reads fs_iosize bytes at a time until the end
   2206  6084  aw148015  * of the file. Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if
   2207  6084  aw148015  * out of files, and FILEBENCH_OK on success.
   2208  5184  ek110237  */
   2209  5184  ek110237 static int
   2210  5184  ek110237 flowoplib_readwholefile(threadflow_t *threadflow, flowop_t *flowop)
   2211  5184  ek110237 {
   2212  5673  aw148015 	caddr_t iobuf;
   2213  5184  ek110237 	off64_t bytes = 0;
   2214  8615    Andrew 	fb_fdesc_t *fdesc;
   2215  6212  aw148015 	uint64_t wss;
   2216  6212  aw148015 	fbint_t iosize;
   2217  5184  ek110237 	int ret;
   2218  6212  aw148015 	char zerordbuf;
   2219  5184  ek110237 
   2220  5673  aw148015 	/* get the file to use */
   2221  6084  aw148015 	if ((ret = flowoplib_filesetup(threadflow, flowop, &wss,
   2222  8615    Andrew 	    &fdesc)) != FILEBENCH_OK)
   2223  6084  aw148015 		return (ret);
   2224  5184  ek110237 
   2225  5673  aw148015 	/* an I/O size of zero means read entire working set with one I/O */
   2226  6212  aw148015 	if ((iosize = avd_get_int(flowop->fo_iosize)) == 0)
   2227  5673  aw148015 		iosize = wss;
   2228  5673  aw148015 
   2229  6212  aw148015 	/*
   2230  6212  aw148015 	 * The file may actually be 0 bytes long, in which case skip
   2231  6212  aw148015 	 * the buffer set up call (which would fail) and substitute
   2232  6212  aw148015 	 * a small buffer, which won't really be used.
   2233  6212  aw148015 	 */
   2234  6212  aw148015 	if (iosize == 0) {
   2235  6212  aw148015 		iobuf = (caddr_t)&zerordbuf;
   2236  6212  aw148015 		filebench_log(LOG_DEBUG_SCRIPT,
   2237  6212  aw148015 		    "flowop %s read zero length file", flowop->fo_name);
   2238  6212  aw148015 	} else {
   2239  6212  aw148015 		if (flowoplib_iobufsetup(threadflow, flowop, &iobuf,
   2240  6212  aw148015 		    iosize) != 0)
   2241  6212  aw148015 			return (FILEBENCH_ERROR);
   2242  6212  aw148015 	}
   2243  5184  ek110237 
   2244  5184  ek110237 	/* Measure time to read bytes */
   2245  5184  ek110237 	flowop_beginop(threadflow, flowop);
   2246  8615    Andrew 	(void) FB_LSEEK(fdesc, 0, SEEK_SET);
   2247  8615    Andrew 	while ((ret = FB_READ(fdesc, iobuf, iosize)) > 0)
   2248  5184  ek110237 		bytes += ret;
   2249  5184  ek110237 
   2250  5673  aw148015 	flowop_endop(threadflow, flowop, bytes);
   2251  5184  ek110237 
   2252  5184  ek110237 	if (ret < 0) {
   2253  5184  ek110237 		filebench_log(LOG_ERROR,
   2254  6391  aw148015 		    "readwhole fail Failed to read whole file: %s",
   2255  6391  aw148015 		    strerror(errno));
   2256  6084  aw148015 		return (FILEBENCH_ERROR);
   2257  5184  ek110237 	}
   2258  5184  ek110237 
   2259  6084  aw148015 	return (FILEBENCH_OK);
   2260  5184  ek110237 }
   2261  5184  ek110237 
   2262  5184  ek110237 /*
   2263  5184  ek110237  * Emulate a write to a file of size fo_iosize.  Will write
   2264  5184  ek110237  * to a file from a fileset if the flowop's fo_fileset field
   2265  5184  ek110237  * specifies one or its fdnumber is non zero. Otherwise it
   2266  5184  ek110237  * will write to a fileobj file, if one exists. If the file
   2267  5184  ek110237  * is not currently open, the routine will attempt to open
   2268  5184  ek110237  * it. The flowop's fo_wss parameter will be used to set the
   2269  5184  ek110237  * maximum file size if it is non-zero, otherwise the
   2270  5184  ek110237  * filesetentry's  fse_size will be used. A random memory
   2271  5184  ek110237  * buffer offset is calculated, and, if fo_random is TRUE,
   2272  5184  ek110237  * a random file offset is used for the write. Otherwise the
   2273  6084  aw148015  * write is to the next sequential location. Returns
   2274  6084  aw148015  * FILEBENCH_ERROR on errors, FILEBENCH_NORSC if iosetup can't
   2275  6084  aw148015  * obtain a file, or FILEBENCH_OK on success.
   2276  5184  ek110237  */
   2277  5184  ek110237 static int
   2278  5184  ek110237 flowoplib_write(threadflow_t *threadflow, flowop_t *flowop)
   2279  5184  ek110237 {
   2280  5673  aw148015 	caddr_t iobuf;
   2281  6212  aw148015 	fbint_t wss;
   2282  6212  aw148015 	fbint_t iosize;
   2283  8615    Andrew 	fb_fdesc_t *fdesc;
   2284  6084  aw148015 	int ret;
   2285  5184  ek110237 
   2286  6212  aw148015 	iosize = avd_get_int(flowop->fo_iosize);
   2287  6084  aw148015 	if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
   2288  8615    Andrew 	    &fdesc, iosize)) != FILEBENCH_OK)
   2289  6084  aw148015 		return (ret);
   2290  5184  ek110237 
   2291  6212  aw148015 	if (avd_get_bool(flowop->fo_random)) {
   2292  5184  ek110237 		uint64_t fileoffset;
   2293  5184  ek110237 
   2294  5184  ek110237 		if (filebench_randomno64(&fileoffset,
   2295  6212  aw148015 		    wss, iosize, NULL) == -1) {
   2296  5184  ek110237 			filebench_log(LOG_ERROR,
   2297  5184  ek110237 			    "file size smaller than IO size for thread %s",
   2298  5184  ek110237 			    flowop->fo_name);
   2299  6084  aw148015 			return (FILEBENCH_ERROR);
   2300  5184  ek110237 		}
   2301  5184  ek110237 		flowop_beginop(threadflow, flowop);
   2302  8615    Andrew 		if (FB_PWRITE(fdesc, iobuf,
   2303  6212  aw148015 		    iosize, (off64_t)fileoffset) == -1) {
   2304  5184  ek110237 			filebench_log(LOG_ERROR, "write failed, "
   2305  6286  aw148015 			    "offset %llu io buffer %zd: %s",
   2306  6286  aw148015 			    (u_longlong_t)fileoffset, iobuf, strerror(errno));
   2307  5673  aw148015 			flowop_endop(threadflow, flowop, 0);
   2308  6084  aw148015 			return (FILEBENCH_ERROR);
   2309  5184  ek110237 		}
   2310  6212  aw148015 		flowop_endop(threadflow, flowop, iosize);
   2311  5184  ek110237 	} else {
   2312  5184  ek110237 		flowop_beginop(threadflow, flowop);
   2313  8615    Andrew 		if (FB_WRITE(fdesc, iobuf, iosize) == -1) {
   2314  5184  ek110237 			filebench_log(LOG_ERROR,
   2315  5673  aw148015 			    "write failed, io buffer %zd: %s",
   2316  5673  aw148015 			    iobuf, strerror(errno));
   2317  5673  aw148015 			flowop_endop(threadflow, flowop, 0);
   2318  6084  aw148015 			return (FILEBENCH_ERROR);
   2319  5184  ek110237 		}
   2320  6212  aw148015 		flowop_endop(threadflow, flowop, iosize);
   2321  5184  ek110237 	}
   2322  5184  ek110237 
   2323  6084  aw148015 	return (FILEBENCH_OK);
   2324  5184  ek110237 }
   2325  5184  ek110237 
   2326  5184  ek110237 /*
   2327  5184  ek110237  * Emulate a write of a whole file.  The size of the file
   2328  5673  aw148015  * is taken from a filesetentry identified by fo_srcfdnumber or
   2329  5673  aw148015  * from the working set size, while the file descriptor used is
   2330  5673  aw148015  * identified by fo_fdnumber. Does multiple writes of fo_iosize
   2331  6084  aw148015  * length length until full file has been written. Returns FILEBENCH_ERROR on
   2332  6084  aw148015  * error, FILEBENCH_NORSC if out of files, FILEBENCH_OK on success.
   2333  5184  ek110237  */
   2334  5184  ek110237 static int
   2335  5184  ek110237 flowoplib_writewholefile(threadflow_t *threadflow, flowop_t *flowop)
   2336  5184  ek110237 {
   2337  5673  aw148015 	caddr_t iobuf;
   2338  5184  ek110237 	filesetentry_t *file;
   2339  5184  ek110237 	int wsize;
   2340  5184  ek110237 	off64_t seek;
   2341  5184  ek110237 	off64_t bytes = 0;
   2342  5673  aw148015 	uint64_t wss;
   2343  6212  aw148015 	fbint_t iosize;
   2344  8615    Andrew 	fb_fdesc_t *fdesc;
   2345  5184  ek110237 	int srcfd = flowop->fo_srcfdnumber;
   2346  5184  ek110237 	int ret;
   2347  6212  aw148015 	char zerowrtbuf;
   2348  5184  ek110237 
   2349  5673  aw148015 	/* get the file to use */
   2350  6084  aw148015 	if ((ret = flowoplib_filesetup(threadflow, flowop, &wss,
   2351  8615    Andrew 	    &fdesc)) != FILEBENCH_OK)
   2352  6084  aw148015 		return (ret);
   2353  5184  ek110237 
   2354  6212  aw148015 	/* an I/O size of zero means write entire working set with one I/O */
   2355  6212  aw148015 	if ((iosize = avd_get_int(flowop->fo_iosize)) == 0)
   2356  5673  aw148015 		iosize = wss;
   2357  5673  aw148015 
   2358  6212  aw148015 	/*
   2359  6212  aw148015 	 * The file may actually be 0 bytes long, in which case skip
   2360  6212  aw148015 	 * the buffer set up call (which would fail) and substitute
   2361  6212  aw148015 	 * a small buffer, which won't really be used.
   2362  6212  aw148015 	 */
   2363  6212  aw148015 	if (iosize == 0) {
   2364  6212  aw148015 		iobuf = (caddr_t)&zerowrtbuf;
   2365  6212  aw148015 		filebench_log(LOG_DEBUG_SCRIPT,
   2366  6212  aw148015 		    "flowop %s wrote zero length file", flowop->fo_name);
   2367  6212  aw148015 	} else {
   2368  6212  aw148015 		if (flowoplib_iobufsetup(threadflow, flowop, &iobuf,
   2369  6212  aw148015 		    iosize) != 0)
   2370  6212  aw148015 			return (FILEBENCH_ERROR);
   2371  6212  aw148015 	}
   2372  5184  ek110237 
   2373  5184  ek110237 	file = threadflow->tf_fse[srcfd];
   2374  5673  aw148015 	if ((srcfd != 0) && (file == NULL)) {
   2375  5673  aw148015 		filebench_log(LOG_ERROR, "flowop %s: NULL src file",
   2376  5184  ek110237 		    flowop->fo_name);
   2377  6084  aw148015 		return (FILEBENCH_ERROR);
   2378  5184  ek110237 	}
   2379  5184  ek110237 
   2380  5673  aw148015 	if (file)
   2381  5673  aw148015 		wss = file->fse_size;
   2382  5673  aw148015 
   2383  5673  aw148015 	wsize = (int)MIN(wss, iosize);
   2384  5184  ek110237 
   2385  5184  ek110237 	/* Measure time to write bytes */
   2386  5184  ek110237 	flowop_beginop(threadflow, flowop);
   2387  5673  aw148015 	for (seek = 0; seek < wss; seek += wsize) {
   2388  8615    Andrew 		ret = FB_WRITE(fdesc, iobuf, wsize);
   2389  5184  ek110237 		if (ret != wsize) {
   2390  5184  ek110237 			filebench_log(LOG_ERROR,
   2391  5184  ek110237 			    "Failed to write %d bytes on fd %d: %s",
   2392  8615    Andrew 			    wsize, fdesc->fd_num, strerror(errno));
   2393  5673  aw148015 			flowop_endop(threadflow, flowop, 0);
   2394  6084  aw148015 			return (FILEBENCH_ERROR);
   2395  5184  ek110237 		}
   2396  5673  aw148015 		wsize = (int)MIN(wss - seek, iosize);
   2397  5184  ek110237 		bytes += ret;
   2398  5184  ek110237 	}
   2399  5673  aw148015 	flowop_endop(threadflow, flowop, bytes);
   2400  5184  ek110237 
   2401  6084  aw148015 	return (FILEBENCH_OK);
   2402  5184  ek110237 }
   2403  5184  ek110237 
   2404  5184  ek110237 
   2405  5184  ek110237 /*
   2406  5184  ek110237  * Emulate a fixed size append to a file. Will append data to
   2407  5184  ek110237  * a file chosen from a fileset if the flowop's fo_fileset
   2408  5184  ek110237  * field specifies one or if its fdnumber is non zero.
   2409  5184  ek110237  * Otherwise it will write to a fileobj file, if one exists.
   2410  5184  ek110237  * The flowop's fo_wss parameter will be used to set the
   2411  5184  ek110237  * maximum file size if it is non-zero, otherwise the
   2412  5184  ek110237  * filesetentry's fse_size will be used. A random memory
   2413  5184  ek110237  * buffer offset is calculated, then a logical seek to the
   2414  5184  ek110237  * end of file is done followed by a write of fo_iosize
   2415  5184  ek110237  * bytes. Writes are actually done from fo_buf, rather than
   2416  5184  ek110237  * tf_mem as is done with flowoplib_write(), and no check
   2417  5184  ek110237  * is made to see if fo_iosize exceeds the size of fo_buf.
   2418  6084  aw148015  * Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if out of
   2419  6084  aw148015  * files in the fileset, FILEBENCH_OK on success.
   2420  5184  ek110237  */
   2421  5184  ek110237 static int
   2422  5184  ek110237 flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop)
   2423  5184  ek110237 {
   2424  5673  aw148015 	caddr_t iobuf;
   2425  8615    Andrew 	fb_fdesc_t *fdesc;
   2426  6212  aw148015 	fbint_t wss;
   2427  6212  aw148015 	fbint_t iosize;
   2428  5184  ek110237 	int ret;
   2429  5184  ek110237 
   2430  6212  aw148015 	iosize = avd_get_int(flowop->fo_iosize);
   2431  6084  aw148015 	if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
   2432  8615    Andrew 	    &fdesc, iosize)) != FILEBENCH_OK)
   2433  6084  aw148015 		return (ret);
   2434  5184  ek110237 
   2435  5184  ek110237 	/* XXX wss is not being used */
   2436  5184  ek110237 
   2437  5184  ek110237 	/* Measure time to write bytes */
   2438  5184  ek110237 	flowop_beginop(threadflow, flowop);
   2439  8615    Andrew 	(void) FB_LSEEK(fdesc, 0, SEEK_END);
   2440  8615    Andrew 	ret = FB_WRITE(fdesc, iobuf, iosize);
   2441  5673  aw148015 	if (ret != iosize) {
   2442  5184  ek110237 		filebench_log(LOG_ERROR,
   2443  6286  aw148015 		    "Failed to write %llu bytes on fd %d: %s",
   2444  8615    Andrew 		    (u_longlong_t)iosize, fdesc->fd_num, strerror(errno));
   2445  6212  aw148015 		flowop_endop(threadflow, flowop, ret);
   2446  6084  aw148015 		return (FILEBENCH_ERROR);
   2447  5184  ek110237 	}
   2448  6212  aw148015 	flowop_endop(threadflow, flowop, ret);
   2449  5184  ek110237 
   2450  6084  aw148015 	return (FILEBENCH_OK);
   2451  5184  ek110237 }
   2452  5184  ek110237 
   2453  5184  ek110237 /*
   2454  5184  ek110237  * Emulate a random size append to a file. Will append data
   2455  5184  ek110237  * to a file chosen from a fileset if the flowop's fo_fileset
   2456  5184  ek110237  * field specifies one or if its fdnumber is non zero. Otherwise
   2457  5184  ek110237  * it will write to a fileobj file, if one exists. The flowop's
   2458  5184  ek110237  * fo_wss parameter will be used to set the maximum file size
   2459  5184  ek110237  * if it is non-zero, otherwise the filesetentry's fse_size
   2460  5184  ek110237  * will be used.  A random transfer size (but at most fo_iosize
   2461  5184  ek110237  * bytes) and a random memory offset are calculated. A logical
   2462  5184  ek110237  * seek to the end of file is done, then writes of up to
   2463  5184  ek110237  * FILE_ALLOC_BLOCK in size are done until the full transfer
   2464  5184  ek110237  * size has been written. Writes are actually done from fo_buf,
   2465  5184  ek110237  * rather than tf_mem as is done with flowoplib_write().
   2466  6084  aw148015  * Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if out of
   2467  6084  aw148015  * files in the fileset, FILEBENCH_OK on success.
   2468  5184  ek110237  */
   2469  5184  ek110237 static int
   2470  5184  ek110237 flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop)
   2471  5184  ek110237 {
   2472  5673  aw148015 	caddr_t iobuf;
   2473  5184  ek110237 	uint64_t appendsize;
   2474  8615    Andrew 	fb_fdesc_t *fdesc;
   2475  6212  aw148015 	fbint_t wss;
   2476  6212  aw148015 	fbint_t iosize;
   2477  6212  aw148015 	int ret = 0;
   2478  5184  ek110237 
   2479  6212  aw148015 	if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) {
   2480  6212  aw148015 		filebench_log(LOG_ERROR, "zero iosize for flowop %s",
   2481  6212  aw148015 		    flowop->fo_name);
   2482  6212  aw148015 		return (FILEBENCH_ERROR);
   2483  6212  aw148015 	}
   2484  6212  aw148015 
   2485  6212  aw148015 	if (filebench_randomno64(&appendsize, iosize, 1LL, NULL) != 0)
   2486  6084  aw148015 		return (FILEBENCH_ERROR);
   2487  5184  ek110237 
   2488  5673  aw148015 	/* skip if attempting zero length append */
   2489  5673  aw148015 	if (appendsize == 0) {
   2490  5673  aw148015 		flowop_beginop(threadflow, flowop);
   2491  5673  aw148015 		flowop_endop(threadflow, flowop, 0LL);
   2492  6084  aw148015 		return (FILEBENCH_OK);
   2493  5673  aw148015 	}
   2494  5184  ek110237 
   2495  6084  aw148015 	if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
   2496  8615    Andrew 	    &fdesc, appendsize)) != FILEBENCH_OK)
   2497  6084  aw148015 		return (ret);
   2498  5184  ek110237 
   2499  5184  ek110237 	/* XXX wss is not being used */
   2500  5184  ek110237 
   2501  5673  aw148015 	/* Measure time to write bytes */
   2502  5673  aw148015 	flowop_beginop(threadflow, flowop);
   2503  5673  aw148015 
   2504  8615    Andrew 	(void) FB_LSEEK(fdesc, 0, SEEK_END);
   2505  8615    Andrew 	ret = FB_WRITE(fdesc, iobuf, appendsize);
   2506  5673  aw148015 	if (ret != appendsize) {
   2507  5673  aw148015 		filebench_log(LOG_ERROR,
   2508  6286  aw148015 		    "Failed to write %llu bytes on fd %d: %s",
   2509  8615    Andrew 		    (u_longlong_t)appendsize, fdesc->fd_num, strerror(errno));
   2510  5673  aw148015 		flowop_endop(threadflow, flowop, 0);
   2511  6084  aw148015 		return (FILEBENCH_ERROR);
   2512  5184  ek110237 	}
   2513  5184  ek110237 
   2514  5673  aw148015 	flowop_endop(threadflow, flowop, appendsize);
   2515  5184  ek110237 
   2516  6084  aw148015 	return (FILEBENCH_OK);
   2517  5184  ek110237 }
   2518  5184  ek110237 
   2519  6212  aw148015 typedef struct testrandvar_priv {
   2520  6212  aw148015 	uint64_t sample_count;
   2521  6212  aw148015 	double val_sum;
   2522  6212  aw148015 	double sqr_sum;
   2523  6212  aw148015 } testrandvar_priv_t;
   2524  6212  aw148015 
   2525  6212  aw148015 /*
   2526  6212  aw148015  * flowop to calculate various statistics from the number stream
   2527  6212  aw148015  * produced by a random variable. This allows verification that the
   2528  6212  aw148015  * random distribution used to define the random variable is producing
   2529  6212  aw148015  * the expected distribution of random numbers.
   2530  6212  aw148015  */
   2531  6212  aw148015 /* ARGSUSED */
   2532  6212  aw148015 static int
   2533  6212  aw148015 flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop)
   2534  6212  aw148015 {
   2535  6212  aw148015 	testrandvar_priv_t	*mystats;
   2536  6212  aw148015 	double			value;
   2537  6212  aw148015 
   2538  6212  aw148015 	if ((mystats = (testrandvar_priv_t *)flowop->fo_private) == NULL) {
   2539  6212  aw148015 		filebench_log(LOG_ERROR, "testrandvar not initialized\n");
   2540  6212  aw148015 		filebench_shutdown(1);
   2541  6212  aw148015 		return (-1);
   2542  6212  aw148015 	}
   2543  6212  aw148015 
   2544  6212  aw148015 	value = avd_get_dbl(flowop->fo_value);
   2545  6212  aw148015 
   2546  6212  aw148015 	mystats->sample_count++;
   2547  6212  aw148015 	mystats->val_sum += value;
   2548  6212  aw148015 	mystats->sqr_sum += (value * value);
   2549  6212  aw148015 
   2550  6212  aw148015 	return (0);
   2551  6212  aw148015 }
   2552  6212  aw148015 
   2553  6212  aw148015 /*
   2554  6212  aw148015  * Initialize the private data area used to accumulate the statistics
   2555  6212  aw148015  */
   2556  6212  aw148015 static int
   2557  6212  aw148015 flowoplib_testrandvar_init(flowop_t *flowop)
   2558  6212  aw148015 {
   2559  6212  aw148015 	testrandvar_priv_t	*mystats;
   2560  6212  aw148015 
   2561  6212  aw148015 	if ((mystats = (testrandvar_priv_t *)
   2562  6212  aw148015 	    malloc(sizeof (testrandvar_priv_t))) == NULL) {
   2563  6212  aw148015 		filebench_log(LOG_ERROR, "could not initialize testrandvar");
   2564  6212  aw148015 		filebench_shutdown(1);
   2565  6212  aw148015 		return (-1);
   2566  6212  aw148015 	}
   2567  6212  aw148015 
   2568  6212  aw148015 	mystats->sample_count = 0;
   2569  6212  aw148015 	mystats->val_sum = 0;
   2570  6212  aw148015 	mystats->sqr_sum = 0;
   2571  6212  aw148015 	flowop->fo_private = (void *)mystats;
   2572  6212  aw148015 
   2573  6212  aw148015 	(void) ipc_mutex_unlock(&flowop->fo_lock);
   2574  6212  aw148015 	return (0);
   2575  6212  aw148015 }
   2576  6212  aw148015 
   2577  6212  aw148015 /*
   2578  6212  aw148015  * Print out the accumulated statistics, and free the private storage
   2579  6212  aw148015  */
   2580  6212  aw148015 static void
   2581  6212  aw148015 flowoplib_testrandvar_destruct(flowop_t *flowop)
   2582  6212  aw148015 {
   2583  6212  aw148015 	testrandvar_priv_t	*mystats;
   2584  6212  aw148015 	double mean, std_dev, dbl_count;
   2585  6212  aw148015 
   2586  6212  aw148015 	(void) ipc_mutex_lock(&flowop->fo_lock);
   2587  6212  aw148015 	if ((mystats = (testrandvar_priv_t *)
   2588  6212  aw148015 	    flowop->fo_private) == NULL) {
   2589  6212  aw148015 		(void) ipc_mutex_unlock(&flowop->fo_lock);
   2590  6212  aw148015 		return;
   2591  6212  aw148015 	}
   2592  6212  aw148015 
   2593  6212  aw148015 	flowop->fo_private = NULL;
   2594  6212  aw148015 	(void) ipc_mutex_unlock(&flowop->fo_lock);
   2595  6212  aw148015 
   2596  6212  aw148015 	dbl_count = (double)mystats->sample_count;
   2597  6212  aw148015 	mean = mystats->val_sum / dbl_count;
   2598  6212  aw148015 	std_dev = sqrt((mystats->sqr_sum / dbl_count) - (mean * mean)) / mean;
   2599  6212  aw148015 
   2600  6212  aw148015 	filebench_log(LOG_VERBOSE,
   2601  6286  aw148015 	    "testrandvar: ops = %llu, mean = %8.2lf, stddev = %8.2lf",
   2602  6286  aw148015 	    (u_longlong_t)mystats->sample_count, mean, std_dev);
   2603  6212  aw148015 	free(mystats);
   2604  6212  aw148015 }
   2605  5184  ek110237 
   2606  5184  ek110237 /*
   2607  7556    Andrew  * prints message to the console from within a thread
   2608  7556    Andrew  */
   2609  7556    Andrew static int
   2610  7556    Andrew flowoplib_print(threadflow_t *threadflow, flowop_t *flowop)
   2611  7556    Andrew {
   2612  7556    Andrew 	procflow_t *procflow;
   2613  7556    Andrew 
   2614  7556    Andrew 	procflow = threadflow->tf_process;
   2615  7556    Andrew 	filebench_log(LOG_INFO,
   2616  7556    Andrew 	    "Message from process (%s,%d), thread (%s,%d): %s",
   2617  7556    Andrew 	    procflow->pf_name, procflow->pf_instance,
   2618  7556    Andrew 	    threadflow->tf_name, threadflow->tf_instance,
   2619  7556    Andrew 	    avd_get_str(flowop->fo_value));
   2620  7556    Andrew 
   2621  7556    Andrew 	return (FILEBENCH_OK);
   2622  7556    Andrew }
   2623  7556    Andrew 
   2624  7556    Andrew /*
   2625  5184  ek110237  * Prints usage information for flowop operations.
   2626  5184  ek110237  */
   2627  5184  ek110237 void
   2628  5184  ek110237 flowoplib_usage()
   2629  5184  ek110237 {
   2630  5184  ek110237 	(void) fprintf(stderr,
   2631  5184  ek110237 	    "flowop [openfile|createfile] name=<name>,fileset=<fname>\n");
   2632  5184  ek110237 	(void) fprintf(stderr,
   2633  5184  ek110237 	    "                       [,fd=<file desc num>]\n");
   2634  5184  ek110237 	(void) fprintf(stderr, "\n");
   2635  5184  ek110237 	(void) fprintf(stderr,
   2636  5184  ek110237 	    "flowop closefile name=<name>,fd=<file desc num>]\n");
   2637  5184  ek110237 	(void) fprintf(stderr, "\n");
   2638  5184  ek110237 	(void) fprintf(stderr, "flowop deletefile name=<name>\n");
   2639  5184  ek110237 	(void) fprintf(stderr, "                       [,fileset=<fname>]\n");
   2640  5184  ek110237 	(void) fprintf(stderr,
   2641  5184  ek110237 	    "                       [,fd=<file desc num>]\n");
   2642  5184  ek110237 	(void) fprintf(stderr, "\n");
   2643  5184  ek110237 	(void) fprintf(stderr, "flowop statfile name=<name>\n");
   2644  5184  ek110237 	(void) fprintf(stderr, "                       [,fileset=<fname>]\n");
   2645  5184  ek110237 	(void) fprintf(stderr,
   2646  5184  ek110237 	    "                       [,fd=<file desc num>]\n");
   2647  5184  ek110237 	(void) fprintf(stderr, "\n");
   2648  5184  ek110237 	(void) fprintf(stderr,
   2649  5184  ek110237 	    "flowop fsync name=<name>,fd=<file desc num>]\n");
   2650  5184  ek110237 	(void) fprintf(stderr, "\n");
   2651  5184  ek110237 	(void) fprintf(stderr,
   2652  5184  ek110237 	    "flowop fsyncset name=<name>,fileset=<fname>]\n");
   2653  5184  ek110237 	(void) fprintf(stderr, "\n");
   2654  5184  ek110237 	(void) fprintf(stderr, "flowop [write|read|aiowrite] name=<name>, \n");
   2655  5184  ek110237 	(void) fprintf(stderr,
   2656  5184  ek110237 	    "                       filename|fileset=<fname>,\n");
   2657  5184  ek110237 	(void) fprintf(stderr, "                       iosize=<size>\n");
   2658  5184  ek110237 	(void) fprintf(stderr, "                       [,directio]\n");
   2659  5184  ek110237 	(void) fprintf(stderr, "                       [,dsync]\n");
   2660  5184  ek110237 	(void) fprintf(stderr, "                       [,iters=<count>]\n");
   2661  5184  ek110237 	(void) fprintf(stderr, "                       [,random]\n");
   2662  5184  ek110237 	(void) fprintf(stderr, "                       [,opennext]\n");
   2663  5184  ek110237 	(void) fprintf(stderr, "                       [,workingset=<size>]\n");
   2664  5184  ek110237 	(void) fprintf(stderr,
   2665  5184  ek110237 	    "flowop [appendfile|appendfilerand] name=<name>, \n");
   2666  5184  ek110237 	(void) fprintf(stderr,
   2667  5184  ek110237 	    "                       filename|fileset=<fname>,\n");
   2668  5184  ek110237 	(void) fprintf(stderr, "                       iosize=<size>\n");
   2669  5184  ek110237 	(void) fprintf(stderr, "                       [,dsync]\n");
   2670  5184  ek110237 	(void) fprintf(stderr, "                       [,iters=<count>]\n");
   2671  5184  ek110237 	(void) fprintf(stderr, "                       [,workingset=<size>]\n");
   2672  5184  ek110237 	(void) fprintf(stderr,
   2673  5184  ek110237 	    "flowop [readwholefile|writewholefile] name=<name>, \n");
   2674  5184  ek110237 	(void) fprintf(stderr,
   2675  5184  ek110237 	    "                       filename|fileset=<fname>,\n");
   2676  5184  ek110237 	(void) fprintf(stderr, "                       iosize=<size>\n");
   2677  5184  ek110237 	(void) fprintf(stderr, "                       [,dsync]\n");
   2678  5184  ek110237 	(void) fprintf(stderr, "                       [,iters=<count>]\n");
   2679  5184  ek110237 	(void) fprintf(stderr, "\n");
   2680  5184  ek110237 	(void) fprintf(stderr, "flowop aiowait name=<name>,target="
   2681  5184  ek110237 	    "<aiowrite-flowop>\n");
   2682  5184  ek110237 	(void) fprintf(stderr, "\n");
   2683  5184  ek110237 	(void) fprintf(stderr, "flowop sempost name=<name>,"
   2684  5184  ek110237 	    "target=<semblock-flowop>,\n");
   2685  5184  ek110237 	(void) fprintf(stderr,
   2686  5184  ek110237 	    "                       value=<increment-to-post>\n");
   2687  5184  ek110237 	(void) fprintf(stderr, "\n");
   2688  5184  ek110237 	(void) fprintf(stderr, "flowop semblock name=<name>,value="
   2689  5184  ek110237 	    "<decrement-to-receive>,\n");
   2690  5184  ek110237 	(void) fprintf(stderr, "                       highwater="
   2691  5184  ek110237 	    "<inbound-queue-max>\n");
   2692  5184  ek110237 	(void) fprintf(stderr, "\n");
   2693  5184  ek110237 	(void) fprintf(stderr, "flowop block name=<name>\n");
   2694  5184  ek110237 	(void) fprintf(stderr, "\n");
   2695  5184  ek110237 	(void) fprintf(stderr,
   2696  5184  ek110237 	    "flowop wakeup name=<name>,target=<block-flowop>,\n");
   2697  5184  ek110237 	(void) fprintf(stderr, "\n");
   2698  5184  ek110237 	(void) fprintf(stderr,
   2699  5184  ek110237 	    "flowop hog name=<name>,value=<number-of-mem-ops>\n");
   2700  5184  ek110237 	(void) fprintf(stderr,
   2701  5184  ek110237 	    "flowop delay name=<name>,value=<number-of-seconds>\n");
   2702  5184  ek110237 	(void) fprintf(stderr, "\n");
   2703  5184  ek110237 	(void) fprintf(stderr, "flowop eventlimit name=<name>\n");
   2704  5184  ek110237 	(void) fprintf(stderr, "flowop bwlimit name=<name>,value=<mb/s>\n");
   2705  5184  ek110237 	(void) fprintf(stderr, "flowop iopslimit name=<name>,value=<iop/s>\n");
   2706  5184  ek110237 	(void) fprintf(stderr,
   2707  5184  ek110237 	    "flowop finishoncount name=<name>,value=<ops/s>\n");
   2708  5184  ek110237 	(void) fprintf(stderr,
   2709  5184  ek110237 	    "flowop finishonbytes name=<name>,value=<bytes>\n");
   2710  5184  ek110237 	(void) fprintf(stderr, "\n");
   2711  5184  ek110237 	(void) fprintf(stderr, "\n");
   2712  5184  ek110237 }
   2713