15184Sek110237 /*
25184Sek110237 * CDDL HEADER START
35184Sek110237 *
45184Sek110237 * The contents of this file are subject to the terms of the
55184Sek110237 * Common Development and Distribution License (the "License").
65184Sek110237 * You may not use this file except in compliance with the License.
75184Sek110237 *
85184Sek110237 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95184Sek110237 * or http://www.opensolaris.org/os/licensing.
105184Sek110237 * See the License for the specific language governing permissions
115184Sek110237 * and limitations under the License.
125184Sek110237 *
135184Sek110237 * When distributing Covered Code, include this CDDL HEADER in each
145184Sek110237 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155184Sek110237 * If applicable, add the following below this CDDL HEADER, with the
165184Sek110237 * fields enclosed by brackets "[]" replaced with your own identifying
175184Sek110237 * information: Portions Copyright [yyyy] [name of copyright owner]
185184Sek110237 *
195184Sek110237 * CDDL HEADER END
205184Sek110237 */
215184Sek110237 /*
228615SAndrew.W.Wilson@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
235184Sek110237 * Use is subject to license terms.
246613Sek110237 *
256613Sek110237 * Portions Copyright 2008 Denis Cheng
265184Sek110237 */
275184Sek110237
285184Sek110237 #include "config.h"
295184Sek110237
305184Sek110237 #include <sys/types.h>
315184Sek110237 #ifdef HAVE_SYS_ASYNCH_H
325184Sek110237 #include <sys/asynch.h>
335184Sek110237 #endif
348615SAndrew.W.Wilson@sun.com #include <stddef.h>
355184Sek110237 #include <sys/ipc.h>
365184Sek110237 #include <sys/sem.h>
375184Sek110237 #include <sys/errno.h>
385184Sek110237 #include <sys/time.h>
395184Sek110237 #include <inttypes.h>
405184Sek110237 #include <fcntl.h>
416212Saw148015 #include <math.h>
427946SAndrew.W.Wilson@sun.com #include <dirent.h>
435184Sek110237
445184Sek110237 #ifdef HAVE_UTILITY_H
455184Sek110237 #include <utility.h>
465184Sek110237 #endif /* HAVE_UTILITY_H */
475184Sek110237
485184Sek110237 #ifdef HAVE_SYS_ASYNC_H
495184Sek110237 #include <sys/asynch.h>
505184Sek110237 #endif /* HAVE_SYS_ASYNC_H */
515184Sek110237
525184Sek110237 #ifndef HAVE_SYSV_SEM
535184Sek110237 #include <semaphore.h>
545184Sek110237 #endif /* HAVE_SYSV_SEM */
555184Sek110237
565184Sek110237 #include "filebench.h"
575184Sek110237 #include "flowop.h"
585184Sek110237 #include "fileset.h"
596212Saw148015 #include "fb_random.h"
607946SAndrew.W.Wilson@sun.com #include "utils.h"
618615SAndrew.W.Wilson@sun.com #include "fsplug.h"
628615SAndrew.W.Wilson@sun.com
635184Sek110237 /*
645184Sek110237 * These routines implement the flowops from the f language. Each
655184Sek110237 * flowop has has a name such as "read", and a set of function pointers
665184Sek110237 * to call for initialization, execution and destruction of the flowop.
675184Sek110237 * The table flowoplib_funcs[] contains a flowoplib struct for each
685184Sek110237 * implemented flowop. Most flowops use a generic initialization function
695184Sek110237 * and all currently use a generic destruction function. All flowop
705184Sek110237 * functions referenced from the table are in this file, though, of
715184Sek110237 * course, they often call functions from other files.
725184Sek110237 *
735184Sek110237 * The flowop_init() routine uses the flowoplib_funcs[] table to
745184Sek110237 * create an initial set of "instance 0" flowops, one for each type of
755184Sek110237 * flowop, from which all other flowops are derived. These "instance 0"
765184Sek110237 * flowops are initialized with information from the table including
775184Sek110237 * pointers for their fo_init, fo_func and fo_destroy functions. When
785184Sek110237 * a flowop definition is encountered in an f language script, the
795184Sek110237 * "type" of flowop, such as "read" is used to search for the
805184Sek110237 * "instance 0" flowop named "read", then a new flowop is allocated
815184Sek110237 * which inherits its function pointers and other initial properties
825184Sek110237 * from the instance 0 flowop, and is given a new name as specified
835184Sek110237 * by the "name=" attribute.
845184Sek110237 */
855184Sek110237
866084Saw148015 static void flowoplib_destruct_noop(flowop_t *flowop);
875184Sek110237 static int flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop);
887556SAndrew.W.Wilson@sun.com static int flowoplib_print(threadflow_t *threadflow, flowop_t *flowop);
895184Sek110237 static int flowoplib_write(threadflow_t *threadflow, flowop_t *flowop);
905184Sek110237 static int flowoplib_read(threadflow_t *threadflow, flowop_t *flowop);
915184Sek110237 static int flowoplib_block_init(flowop_t *flowop);
925184Sek110237 static int flowoplib_block(threadflow_t *threadflow, flowop_t *flowop);
935184Sek110237 static int flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop);
945184Sek110237 static int flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop);
955184Sek110237 static int flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop);
965184Sek110237 static int flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop);
975184Sek110237 static int flowoplib_sempost_init(flowop_t *flowop);
985184Sek110237 static int flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop);
995184Sek110237 static int flowoplib_semblock_init(flowop_t *flowop);
1005184Sek110237 static void flowoplib_semblock_destruct(flowop_t *flowop);
1015184Sek110237 static int flowoplib_eventlimit(threadflow_t *, flowop_t *flowop);
1025184Sek110237 static int flowoplib_bwlimit(threadflow_t *, flowop_t *flowop);
1035184Sek110237 static int flowoplib_iopslimit(threadflow_t *, flowop_t *flowop);
1045184Sek110237 static int flowoplib_opslimit(threadflow_t *, flowop_t *flowop);
1055184Sek110237 static int flowoplib_openfile(threadflow_t *, flowop_t *flowop);
1065184Sek110237 static int flowoplib_openfile_common(threadflow_t *, flowop_t *flowop, int fd);
1075184Sek110237 static int flowoplib_createfile(threadflow_t *, flowop_t *flowop);
1085184Sek110237 static int flowoplib_closefile(threadflow_t *, flowop_t *flowop);
1097946SAndrew.W.Wilson@sun.com static int flowoplib_makedir(threadflow_t *, flowop_t *flowop);
1107946SAndrew.W.Wilson@sun.com static int flowoplib_removedir(threadflow_t *, flowop_t *flowop);
1117946SAndrew.W.Wilson@sun.com static int flowoplib_listdir(threadflow_t *, flowop_t *flowop);
1125184Sek110237 static int flowoplib_fsync(threadflow_t *, flowop_t *flowop);
1135184Sek110237 static int flowoplib_readwholefile(threadflow_t *, flowop_t *flowop);
1145184Sek110237 static int flowoplib_writewholefile(threadflow_t *, flowop_t *flowop);
1155184Sek110237 static int flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop);
1165184Sek110237 static int flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop);
1175184Sek110237 static int flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop);
1185184Sek110237 static int flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop);
1195184Sek110237 static int flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop);
1205184Sek110237 static int flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop);
1215184Sek110237 static int flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop);
1226212Saw148015 static int flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop);
1236212Saw148015 static int flowoplib_testrandvar_init(flowop_t *flowop);
1246212Saw148015 static void flowoplib_testrandvar_destruct(flowop_t *flowop);
1255184Sek110237
1268615SAndrew.W.Wilson@sun.com static flowop_proto_t flowoplib_funcs[] = {
1278615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "write", flowop_init_generic,
1288615SAndrew.W.Wilson@sun.com flowoplib_write, flowop_destruct_generic,
1298615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_READ, "read", flowop_init_generic,
1308615SAndrew.W.Wilson@sun.com flowoplib_read, flowop_destruct_generic,
1315184Sek110237 FLOW_TYPE_SYNC, 0, "block", flowoplib_block_init,
1328615SAndrew.W.Wilson@sun.com flowoplib_block, flowop_destruct_generic,
1338615SAndrew.W.Wilson@sun.com FLOW_TYPE_SYNC, 0, "wakeup", flowop_init_generic,
1348615SAndrew.W.Wilson@sun.com flowoplib_wakeup, flowop_destruct_generic,
1355184Sek110237 FLOW_TYPE_SYNC, 0, "semblock", flowoplib_semblock_init,
1365184Sek110237 flowoplib_semblock, flowoplib_semblock_destruct,
1375184Sek110237 FLOW_TYPE_SYNC, 0, "sempost", flowoplib_sempost_init,
1386084Saw148015 flowoplib_sempost, flowoplib_destruct_noop,
1398615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "hog", flowop_init_generic,
1408615SAndrew.W.Wilson@sun.com flowoplib_hog, flowop_destruct_generic,
1418615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "delay", flowop_init_generic,
1428615SAndrew.W.Wilson@sun.com flowoplib_delay, flowop_destruct_generic,
1438615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "eventlimit", flowop_init_generic,
1448615SAndrew.W.Wilson@sun.com flowoplib_eventlimit, flowop_destruct_generic,
1458615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "bwlimit", flowop_init_generic,
1468615SAndrew.W.Wilson@sun.com flowoplib_bwlimit, flowop_destruct_generic,
1478615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "iopslimit", flowop_init_generic,
1488615SAndrew.W.Wilson@sun.com flowoplib_iopslimit, flowop_destruct_generic,
1498615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "opslimit", flowop_init_generic,
1508615SAndrew.W.Wilson@sun.com flowoplib_opslimit, flowop_destruct_generic,
1518615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "finishoncount", flowop_init_generic,
1528615SAndrew.W.Wilson@sun.com flowoplib_finishoncount, flowop_destruct_generic,
1538615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "finishonbytes", flowop_init_generic,
1548615SAndrew.W.Wilson@sun.com flowoplib_finishonbytes, flowop_destruct_generic,
1558615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "openfile", flowop_init_generic,
1568615SAndrew.W.Wilson@sun.com flowoplib_openfile, flowop_destruct_generic,
1578615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "createfile", flowop_init_generic,
1588615SAndrew.W.Wilson@sun.com flowoplib_createfile, flowop_destruct_generic,
1598615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "closefile", flowop_init_generic,
1608615SAndrew.W.Wilson@sun.com flowoplib_closefile, flowop_destruct_generic,
1618615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "makedir", flowop_init_generic,
1628615SAndrew.W.Wilson@sun.com flowoplib_makedir, flowop_destruct_generic,
1638615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "removedir", flowop_init_generic,
1648615SAndrew.W.Wilson@sun.com flowoplib_removedir, flowop_destruct_generic,
1658615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "listdir", flowop_init_generic,
1668615SAndrew.W.Wilson@sun.com flowoplib_listdir, flowop_destruct_generic,
1678615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "fsync", flowop_init_generic,
1688615SAndrew.W.Wilson@sun.com flowoplib_fsync, flowop_destruct_generic,
1698615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "fsyncset", flowop_init_generic,
1708615SAndrew.W.Wilson@sun.com flowoplib_fsyncset, flowop_destruct_generic,
1718615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "statfile", flowop_init_generic,
1728615SAndrew.W.Wilson@sun.com flowoplib_statfile, flowop_destruct_generic,
1738615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_READ, "readwholefile", flowop_init_generic,
1748615SAndrew.W.Wilson@sun.com flowoplib_readwholefile, flowop_destruct_generic,
1758615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "appendfile", flowop_init_generic,
1768615SAndrew.W.Wilson@sun.com flowoplib_appendfile, flowop_destruct_generic,
1778615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "appendfilerand", flowop_init_generic,
1788615SAndrew.W.Wilson@sun.com flowoplib_appendfilerand, flowop_destruct_generic,
1798615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "deletefile", flowop_init_generic,
1808615SAndrew.W.Wilson@sun.com flowoplib_deletefile, flowop_destruct_generic,
1818615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "writewholefile", flowop_init_generic,
1828615SAndrew.W.Wilson@sun.com flowoplib_writewholefile, flowop_destruct_generic,
1838615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "print", flowop_init_generic,
1848615SAndrew.W.Wilson@sun.com flowoplib_print, flowop_destruct_generic,
1856212Saw148015 /* routine to calculate mean and stddev for output from a randvar */
1866212Saw148015 FLOW_TYPE_OTHER, 0, "testrandvar", flowoplib_testrandvar_init,
1876212Saw148015 flowoplib_testrandvar, flowoplib_testrandvar_destruct
1885184Sek110237 };
1895184Sek110237
1905184Sek110237 /*
1918615SAndrew.W.Wilson@sun.com * Loops through the list of flowops defined in this
1925184Sek110237 * module, and creates and initializes a flowop for each one
1938615SAndrew.W.Wilson@sun.com * by calling flowop_flow_init. As a side effect of calling
1948615SAndrew.W.Wilson@sun.com * flowop_flow_init, the created flowops are placed on the
1955184Sek110237 * master flowop list. All created flowops are set to
1965184Sek110237 * instance "0".
1975184Sek110237 */
1985184Sek110237 void
flowoplib_flowinit()1998615SAndrew.W.Wilson@sun.com flowoplib_flowinit()
2005184Sek110237 {
2018615SAndrew.W.Wilson@sun.com int nops = sizeof (flowoplib_funcs) / sizeof (flowop_proto_t);
2028615SAndrew.W.Wilson@sun.com
2038615SAndrew.W.Wilson@sun.com flowop_flow_init(flowoplib_funcs, nops);
2046084Saw148015 }
2056084Saw148015
2066084Saw148015 /*
2076084Saw148015 * Special total noop destruct
2086084Saw148015 */
2096084Saw148015 /* ARGSUSED */
2106084Saw148015 static void
flowoplib_destruct_noop(flowop_t * flowop)2116084Saw148015 flowoplib_destruct_noop(flowop_t *flowop)
2126084Saw148015 {
2135184Sek110237 }
2145184Sek110237
2155184Sek110237 /*
2165184Sek110237 * Generates a file attribute from flags in the supplied flowop.
2175184Sek110237 * Sets FLOW_ATTR_DIRECTIO and/or FLOW_ATTR_DSYNC as needed.
2185184Sek110237 */
2195184Sek110237 static int
flowoplib_fileattrs(flowop_t * flowop)2205184Sek110237 flowoplib_fileattrs(flowop_t *flowop)
2215184Sek110237 {
2225184Sek110237 int attrs = 0;
2235184Sek110237
2246212Saw148015 if (avd_get_bool(flowop->fo_directio))
2255184Sek110237 attrs |= FLOW_ATTR_DIRECTIO;
2265184Sek110237
2276212Saw148015 if (avd_get_bool(flowop->fo_dsync))
2285184Sek110237 attrs |= FLOW_ATTR_DSYNC;
2295184Sek110237
2305184Sek110237 return (attrs);
2315184Sek110237 }
2325184Sek110237
2335184Sek110237 /*
2348404SAndrew.W.Wilson@sun.com * Obtain a filesetentry for a file. Result placed where filep points.
2358404SAndrew.W.Wilson@sun.com * Supply with a flowop and a flag to indicate whether an existent or
2368404SAndrew.W.Wilson@sun.com * non-existent file is required. Returns FILEBENCH_NORSC if all out
2378404SAndrew.W.Wilson@sun.com * of the appropriate type of directories, FILEBENCH_ERROR if the
2388404SAndrew.W.Wilson@sun.com * flowop does not point to a fileset, and FILEBENCH_OK otherwise.
2398404SAndrew.W.Wilson@sun.com */
2408404SAndrew.W.Wilson@sun.com static int
flowoplib_pickfile(filesetentry_t ** filep,flowop_t * flowop,int flags,int tid)2418404SAndrew.W.Wilson@sun.com flowoplib_pickfile(filesetentry_t **filep, flowop_t *flowop, int flags, int tid)
2428404SAndrew.W.Wilson@sun.com {
2438404SAndrew.W.Wilson@sun.com fileset_t *fileset;
2448404SAndrew.W.Wilson@sun.com int fileindex;
2458404SAndrew.W.Wilson@sun.com
2468404SAndrew.W.Wilson@sun.com if ((fileset = flowop->fo_fileset) == NULL) {
2478404SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "flowop NO fileset");
2488404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
2498404SAndrew.W.Wilson@sun.com }
2508404SAndrew.W.Wilson@sun.com
2518404SAndrew.W.Wilson@sun.com if (flowop->fo_fileindex) {
2528404SAndrew.W.Wilson@sun.com fileindex = (int)(avd_get_dbl(flowop->fo_fileindex) *
2538404SAndrew.W.Wilson@sun.com ((double)(fileset->fs_constentries / 2)));
2548404SAndrew.W.Wilson@sun.com fileindex = fileindex % fileset->fs_constentries;
2558404SAndrew.W.Wilson@sun.com flags |= FILESET_PICKBYINDEX;
2568404SAndrew.W.Wilson@sun.com } else {
2578404SAndrew.W.Wilson@sun.com fileindex = 0;
2588404SAndrew.W.Wilson@sun.com }
2598404SAndrew.W.Wilson@sun.com
2608404SAndrew.W.Wilson@sun.com if ((*filep = fileset_pick(fileset, FILESET_PICKFILE | flags,
2618404SAndrew.W.Wilson@sun.com tid, fileindex)) == NULL) {
2628404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
2638404SAndrew.W.Wilson@sun.com "flowop %s failed to pick file from fileset %s",
2648404SAndrew.W.Wilson@sun.com flowop->fo_name,
2658404SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name));
2668404SAndrew.W.Wilson@sun.com return (FILEBENCH_NORSC);
2678404SAndrew.W.Wilson@sun.com }
2688404SAndrew.W.Wilson@sun.com
2698404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
2708404SAndrew.W.Wilson@sun.com }
2718404SAndrew.W.Wilson@sun.com
2728404SAndrew.W.Wilson@sun.com /*
2738404SAndrew.W.Wilson@sun.com * Obtain a filesetentry for a leaf directory. Result placed where dirp
2748404SAndrew.W.Wilson@sun.com * points. Supply with flowop and a flag to indicate whether an existent
2758404SAndrew.W.Wilson@sun.com * or non-existent leaf directory is required. Returns FILEBENCH_NORSC
2768404SAndrew.W.Wilson@sun.com * if all out of the appropriate type of directories, FILEBENCH_ERROR
2778404SAndrew.W.Wilson@sun.com * if the flowop does not point to a fileset, and FILEBENCH_OK otherwise.
2788404SAndrew.W.Wilson@sun.com */
2798404SAndrew.W.Wilson@sun.com static int
flowoplib_pickleafdir(filesetentry_t ** dirp,flowop_t * flowop,int flags)2808404SAndrew.W.Wilson@sun.com flowoplib_pickleafdir(filesetentry_t **dirp, flowop_t *flowop, int flags)
2818404SAndrew.W.Wilson@sun.com {
2828404SAndrew.W.Wilson@sun.com fileset_t *fileset;
2838404SAndrew.W.Wilson@sun.com int dirindex;
2848404SAndrew.W.Wilson@sun.com
2858404SAndrew.W.Wilson@sun.com if ((fileset = flowop->fo_fileset) == NULL) {
2868404SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "flowop NO fileset");
2878404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
2888404SAndrew.W.Wilson@sun.com }
2898404SAndrew.W.Wilson@sun.com
2908404SAndrew.W.Wilson@sun.com if (flowop->fo_fileindex) {
2918404SAndrew.W.Wilson@sun.com dirindex = (int)(avd_get_dbl(flowop->fo_fileindex) *
2928404SAndrew.W.Wilson@sun.com ((double)(fileset->fs_constleafdirs / 2)));
2938404SAndrew.W.Wilson@sun.com dirindex = dirindex % fileset->fs_constleafdirs;
2948404SAndrew.W.Wilson@sun.com flags |= FILESET_PICKBYINDEX;
2958404SAndrew.W.Wilson@sun.com } else {
2968404SAndrew.W.Wilson@sun.com dirindex = 0;
2978404SAndrew.W.Wilson@sun.com }
2988404SAndrew.W.Wilson@sun.com
2998404SAndrew.W.Wilson@sun.com if ((*dirp = fileset_pick(fileset,
3008404SAndrew.W.Wilson@sun.com FILESET_PICKLEAFDIR | flags, 0, dirindex)) == NULL) {
3018404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
3028404SAndrew.W.Wilson@sun.com "flowop %s failed to pick directory from fileset %s",
3038404SAndrew.W.Wilson@sun.com flowop->fo_name,
3048404SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name));
3058404SAndrew.W.Wilson@sun.com return (FILEBENCH_NORSC);
3068404SAndrew.W.Wilson@sun.com }
3078404SAndrew.W.Wilson@sun.com
3088404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
3098404SAndrew.W.Wilson@sun.com }
3108404SAndrew.W.Wilson@sun.com
3118404SAndrew.W.Wilson@sun.com /*
3125184Sek110237 * Searches for a file descriptor. Tries the flowop's
3135184Sek110237 * fo_fdnumber first and returns with it if it has been
3145184Sek110237 * explicitly set (greater than 0). It next checks to
3155184Sek110237 * see if a rotating file descriptor policy is in effect,
3165184Sek110237 * and if not returns the fdnumber regardless of what
3175184Sek110237 * it is. (note that if it is 0, it just selects to the
3185184Sek110237 * default file descriptor in the threadflow's tf_fd
3195184Sek110237 * array). If the rotating fd policy is in effect, it
3205184Sek110237 * cycles from the end of the tf_fd array to one location
3215184Sek110237 * beyond the maximum needed by the number of entries in
3225184Sek110237 * the associated fileset on each invocation, then starts
3235184Sek110237 * over from the end.
3245184Sek110237 *
3255184Sek110237 * The routine returns an index into the threadflow's
3265184Sek110237 * tf_fd table where the actual file descriptor will be
3275184Sek110237 * found. Note: the calling routine must not call this
3285184Sek110237 * routine if the flowop does not have a fileset, and the
3295184Sek110237 * flowop's fo_fdnumber is zero and fo_rotatefd is
3305184Sek110237 * asserted, or an addressing fault may occur.
3315184Sek110237 */
3325673Saw148015 static int
flowoplib_fdnum(threadflow_t * threadflow,flowop_t * flowop)3335184Sek110237 flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop)
3345184Sek110237 {
3356212Saw148015 fbint_t entries;
3366391Saw148015 int fdnumber = flowop->fo_fdnumber;
3376212Saw148015
3385184Sek110237 /* If the script sets the fd explicitly */
3396391Saw148015 if (fdnumber > 0)
3406391Saw148015 return (fdnumber);
3415184Sek110237
3425184Sek110237 /* If the flowop defaults to persistent fd */
3436212Saw148015 if (!avd_get_bool(flowop->fo_rotatefd))
3446391Saw148015 return (fdnumber);
3456391Saw148015
3466391Saw148015 if (flowop->fo_fileset == NULL) {
3476391Saw148015 filebench_log(LOG_ERROR, "flowop NULL file");
3486391Saw148015 return (FILEBENCH_ERROR);
3496391Saw148015 }
3505184Sek110237
3516212Saw148015 entries = flowop->fo_fileset->fs_constentries;
3526212Saw148015
3535184Sek110237 /* Rotate the fd on each flowop invocation */
3546212Saw148015 if (entries > (THREADFLOW_MAXFD / 2)) {
3555184Sek110237 filebench_log(LOG_ERROR, "Out of file descriptors in flowop %s"
3566286Saw148015 " (too many files : %llu",
3576286Saw148015 flowop->fo_name, (u_longlong_t)entries);
3586084Saw148015 return (FILEBENCH_ERROR);
3595184Sek110237 }
3605184Sek110237
3615184Sek110237 /* First time around */
3625184Sek110237 if (threadflow->tf_fdrotor == 0)
3635184Sek110237 threadflow->tf_fdrotor = THREADFLOW_MAXFD;
3645184Sek110237
3655184Sek110237 /* One fd for every file in the set */
3666212Saw148015 if (entries == (THREADFLOW_MAXFD - threadflow->tf_fdrotor))
3675184Sek110237 threadflow->tf_fdrotor = THREADFLOW_MAXFD;
3685184Sek110237
3695184Sek110237
3705184Sek110237 threadflow->tf_fdrotor--;
3715184Sek110237 filebench_log(LOG_DEBUG_IMPL, "selected fd = %d",
3725184Sek110237 threadflow->tf_fdrotor);
3735184Sek110237 return (threadflow->tf_fdrotor);
3745184Sek110237 }
3755184Sek110237
3765184Sek110237 /*
3775673Saw148015 * Determines the file descriptor to use, and attempts to open
3785673Saw148015 * the file if it is not already open. Also determines the wss
3796084Saw148015 * value. Returns FILEBENCH_ERROR on errors, FILESET_NORSC if
3806084Saw148015 * if flowop_openfile_common couldn't obtain an appropriate file
3816084Saw148015 * from a the fileset, and FILEBENCH_OK otherwise.
3825673Saw148015 */
3835673Saw148015 static int
flowoplib_filesetup(threadflow_t * threadflow,flowop_t * flowop,fbint_t * wssp,fb_fdesc_t ** fdescp)3845673Saw148015 flowoplib_filesetup(threadflow_t *threadflow, flowop_t *flowop,
3858615SAndrew.W.Wilson@sun.com fbint_t *wssp, fb_fdesc_t **fdescp)
3865673Saw148015 {
3875673Saw148015 int fd = flowoplib_fdnum(threadflow, flowop);
3885673Saw148015
3895673Saw148015 if (fd == -1)
3906084Saw148015 return (FILEBENCH_ERROR);
3915673Saw148015
3929326SAndrew.W.Wilson@sun.com /* check for conflicting fdnumber and file name */
3939326SAndrew.W.Wilson@sun.com if ((fd > 0) && (threadflow->tf_fse[fd] != NULL)) {
3949326SAndrew.W.Wilson@sun.com char *fd_based_name;
3959326SAndrew.W.Wilson@sun.com
3969326SAndrew.W.Wilson@sun.com fd_based_name =
3979326SAndrew.W.Wilson@sun.com avd_get_str(threadflow->tf_fse[fd]->fse_fileset->fs_name);
3989326SAndrew.W.Wilson@sun.com
3999326SAndrew.W.Wilson@sun.com if (flowop->fo_filename != NULL) {
4009326SAndrew.W.Wilson@sun.com char *fo_based_name;
4019326SAndrew.W.Wilson@sun.com
4029326SAndrew.W.Wilson@sun.com fo_based_name = avd_get_str(flowop->fo_filename);
4039326SAndrew.W.Wilson@sun.com if (strcmp(fd_based_name, fo_based_name) != 0) {
4049326SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Name of fd refer"
4059326SAndrew.W.Wilson@sun.com "enced fileset name (%s) CONFLICTS with"
4069326SAndrew.W.Wilson@sun.com " flowop supplied fileset name (%s)",
4079326SAndrew.W.Wilson@sun.com fd_based_name, fo_based_name);
4089326SAndrew.W.Wilson@sun.com filebench_shutdown(1);
4099326SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
4109326SAndrew.W.Wilson@sun.com }
4119326SAndrew.W.Wilson@sun.com }
4129326SAndrew.W.Wilson@sun.com }
4139326SAndrew.W.Wilson@sun.com
4148615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr == NULL) {
4156084Saw148015 int ret;
4166084Saw148015
4176084Saw148015 if ((ret = flowoplib_openfile_common(
4186084Saw148015 threadflow, flowop, fd)) != FILEBENCH_OK)
4196084Saw148015 return (ret);
4205673Saw148015
4215673Saw148015 if (threadflow->tf_fse[fd]) {
4225673Saw148015 filebench_log(LOG_DEBUG_IMPL, "opened file %s",
4235673Saw148015 threadflow->tf_fse[fd]->fse_path);
4245673Saw148015 } else {
4255673Saw148015 filebench_log(LOG_DEBUG_IMPL,
4265673Saw148015 "opened device %s/%s",
4276212Saw148015 avd_get_str(flowop->fo_fileset->fs_path),
4286212Saw148015 avd_get_str(flowop->fo_fileset->fs_name));
4295673Saw148015 }
4305673Saw148015 }
4315673Saw148015
4328615SAndrew.W.Wilson@sun.com *fdescp = &(threadflow->tf_fd[fd]);
4335673Saw148015
4346212Saw148015 if ((*wssp = flowop->fo_constwss) == 0) {
4355673Saw148015 if (threadflow->tf_fse[fd])
4365673Saw148015 *wssp = threadflow->tf_fse[fd]->fse_size;
4375673Saw148015 else
4386212Saw148015 *wssp = avd_get_int(flowop->fo_fileset->fs_size);
4395673Saw148015 }
4405673Saw148015
4416084Saw148015 return (FILEBENCH_OK);
4425673Saw148015 }
4435673Saw148015
4445673Saw148015 /*
4455673Saw148015 * Determines the io buffer or random offset into tf_mem for
4466084Saw148015 * the IO operation. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
4475673Saw148015 */
4485673Saw148015 static int
flowoplib_iobufsetup(threadflow_t * threadflow,flowop_t * flowop,caddr_t * iobufp,fbint_t iosize)4495673Saw148015 flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop,
4506212Saw148015 caddr_t *iobufp, fbint_t iosize)
4515673Saw148015 {
4525673Saw148015 long memsize;
4535673Saw148015 size_t memoffset;
4545673Saw148015
4555673Saw148015 if (iosize == 0) {
4565673Saw148015 filebench_log(LOG_ERROR, "zero iosize for thread %s",
4575673Saw148015 flowop->fo_name);
4586084Saw148015 return (FILEBENCH_ERROR);
4595673Saw148015 }
4605673Saw148015
4616212Saw148015 if ((memsize = threadflow->tf_constmemsize) != 0) {
4625673Saw148015
4635673Saw148015 /* use tf_mem for I/O with random offset */
4646212Saw148015 if (filebench_randomno(&memoffset,
4656212Saw148015 memsize, iosize, NULL) == -1) {
4665673Saw148015 filebench_log(LOG_ERROR,
4675673Saw148015 "tf_memsize smaller than IO size for thread %s",
4685673Saw148015 flowop->fo_name);
4696084Saw148015 return (FILEBENCH_ERROR);
4705673Saw148015 }
4715673Saw148015 *iobufp = threadflow->tf_mem + memoffset;
4725673Saw148015
4735673Saw148015 } else {
4745673Saw148015 /* use private I/O buffer */
4755673Saw148015 if ((flowop->fo_buf != NULL) &&
4765673Saw148015 (flowop->fo_buf_size < iosize)) {
4776212Saw148015 /* too small, so free up and re-allocate */
4785673Saw148015 free(flowop->fo_buf);
4795673Saw148015 flowop->fo_buf = NULL;
4805673Saw148015 }
4816212Saw148015
4826212Saw148015 /*
4836212Saw148015 * Allocate memory for the buffer. The memory is freed
4846212Saw148015 * by flowop_destruct_generic() or by this routine if more
4856212Saw148015 * memory is needed for the buffer.
4866212Saw148015 */
4875673Saw148015 if ((flowop->fo_buf == NULL) && ((flowop->fo_buf
4885673Saw148015 = (char *)malloc(iosize)) == NULL))
4896084Saw148015 return (FILEBENCH_ERROR);
4905673Saw148015
4915673Saw148015 flowop->fo_buf_size = iosize;
4925673Saw148015 *iobufp = flowop->fo_buf;
4935673Saw148015 }
4946084Saw148015 return (FILEBENCH_OK);
4955673Saw148015 }
4965673Saw148015
4975673Saw148015 /*
4985673Saw148015 * Determines the file descriptor to use, opens it if necessary, the
4995673Saw148015 * io buffer or random offset into tf_mem for IO operation and the wss
5006084Saw148015 * value. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
5015673Saw148015 */
5028615SAndrew.W.Wilson@sun.com int
flowoplib_iosetup(threadflow_t * threadflow,flowop_t * flowop,fbint_t * wssp,caddr_t * iobufp,fb_fdesc_t ** filedescp,fbint_t iosize)5035673Saw148015 flowoplib_iosetup(threadflow_t *threadflow, flowop_t *flowop,
5048615SAndrew.W.Wilson@sun.com fbint_t *wssp, caddr_t *iobufp, fb_fdesc_t **filedescp, fbint_t iosize)
5055673Saw148015 {
5066084Saw148015 int ret;
5076084Saw148015
5086084Saw148015 if ((ret = flowoplib_filesetup(threadflow, flowop, wssp, filedescp)) !=
5096084Saw148015 FILEBENCH_OK)
5106084Saw148015 return (ret);
5115673Saw148015
5126084Saw148015 if ((ret = flowoplib_iobufsetup(threadflow, flowop, iobufp, iosize)) !=
5136084Saw148015 FILEBENCH_OK)
5146084Saw148015 return (ret);
5155673Saw148015
5166084Saw148015 return (FILEBENCH_OK);
5175673Saw148015 }
5185673Saw148015
5195673Saw148015 /*
5205184Sek110237 * Emulate posix read / pread. If the flowop has a fileset,
5215184Sek110237 * a file descriptor number index is fetched, otherwise a
5225184Sek110237 * supplied fileobj file is used. In either case the specified
5235184Sek110237 * file will be opened if not already open. If the flowop has
5246084Saw148015 * neither a fileset or fileobj, an error is logged and FILEBENCH_ERROR
5255184Sek110237 * returned.
5265184Sek110237 *
5275184Sek110237 * The actual read is done to a random offset in the
5285184Sek110237 * threadflow's thread memory (tf_mem), with a size set by
5295184Sek110237 * fo_iosize and at either a random disk offset within the
5305184Sek110237 * working set size, or at the next sequential location. If
5316084Saw148015 * any errors are encountered, FILEBENCH_ERROR is returned,
5326084Saw148015 * if no appropriate file can be obtained from the fileset then
5336084Saw148015 * FILEBENCH_NORSC is returned, otherise FILEBENCH_OK is returned.
5345184Sek110237 */
5355184Sek110237 static int
flowoplib_read(threadflow_t * threadflow,flowop_t * flowop)5365184Sek110237 flowoplib_read(threadflow_t *threadflow, flowop_t *flowop)
5375184Sek110237 {
5385673Saw148015 caddr_t iobuf;
5396212Saw148015 fbint_t wss;
5406212Saw148015 fbint_t iosize;
5418615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc;
5425184Sek110237 int ret;
5435184Sek110237
5446212Saw148015
5456212Saw148015 iosize = avd_get_int(flowop->fo_iosize);
5466084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
5478615SAndrew.W.Wilson@sun.com &fdesc, iosize)) != FILEBENCH_OK)
5486084Saw148015 return (ret);
5495184Sek110237
5506212Saw148015 if (avd_get_bool(flowop->fo_random)) {
5515184Sek110237 uint64_t fileoffset;
5525184Sek110237
5536212Saw148015 if (filebench_randomno64(&fileoffset,
5546212Saw148015 wss, iosize, NULL) == -1) {
5555184Sek110237 filebench_log(LOG_ERROR,
5565184Sek110237 "file size smaller than IO size for thread %s",
5575184Sek110237 flowop->fo_name);
5586084Saw148015 return (FILEBENCH_ERROR);
5595184Sek110237 }
5605184Sek110237
5615184Sek110237 (void) flowop_beginop(threadflow, flowop);
5628615SAndrew.W.Wilson@sun.com if ((ret = FB_PREAD(fdesc, iobuf,
5636212Saw148015 iosize, (off64_t)fileoffset)) == -1) {
5645673Saw148015 (void) flowop_endop(threadflow, flowop, 0);
5655184Sek110237 filebench_log(LOG_ERROR,
5666286Saw148015 "read file %s failed, offset %llu "
5675673Saw148015 "io buffer %zd: %s",
5686212Saw148015 avd_get_str(flowop->fo_fileset->fs_name),
5696286Saw148015 (u_longlong_t)fileoffset, iobuf, strerror(errno));
5705673Saw148015 flowop_endop(threadflow, flowop, 0);
5716084Saw148015 return (FILEBENCH_ERROR);
5725184Sek110237 }
5735673Saw148015 (void) flowop_endop(threadflow, flowop, ret);
5745184Sek110237
5755184Sek110237 if ((ret == 0))
5768615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_SET);
5775184Sek110237
5785184Sek110237 } else {
5795184Sek110237 (void) flowop_beginop(threadflow, flowop);
5808615SAndrew.W.Wilson@sun.com if ((ret = FB_READ(fdesc, iobuf, iosize)) == -1) {
5816212Saw148015 (void) flowop_endop(threadflow, flowop, 0);
5825184Sek110237 filebench_log(LOG_ERROR,
5835673Saw148015 "read file %s failed, io buffer %zd: %s",
5846212Saw148015 avd_get_str(flowop->fo_fileset->fs_name),
5855673Saw148015 iobuf, strerror(errno));
5865673Saw148015 (void) flowop_endop(threadflow, flowop, 0);
5876084Saw148015 return (FILEBENCH_ERROR);
5885184Sek110237 }
5895673Saw148015 (void) flowop_endop(threadflow, flowop, ret);
5905184Sek110237
5915184Sek110237 if ((ret == 0))
5928615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_SET);
5935184Sek110237 }
5945184Sek110237
5956084Saw148015 return (FILEBENCH_OK);
5965184Sek110237 }
5975184Sek110237
5985184Sek110237 /*
5995184Sek110237 * Initializes a "flowop_block" flowop. Specifically, it
6005184Sek110237 * initializes the flowop's fo_cv and unlocks the fo_lock.
6015184Sek110237 */
6025184Sek110237 static int
flowoplib_block_init(flowop_t * flowop)6035184Sek110237 flowoplib_block_init(flowop_t *flowop)
6045184Sek110237 {
6055184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d block init address %zx",
6065184Sek110237 flowop->fo_name, flowop->fo_instance, &flowop->fo_cv);
6075184Sek110237 (void) pthread_cond_init(&flowop->fo_cv, ipc_condattr());
6085184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock);
6095184Sek110237
6106084Saw148015 return (FILEBENCH_OK);
6115184Sek110237 }
6125184Sek110237
6135184Sek110237 /*
6145184Sek110237 * Blocks the threadflow until woken up by flowoplib_wakeup.
6155184Sek110237 * The routine blocks on the flowop's fo_cv condition variable.
6165184Sek110237 */
6175184Sek110237 static int
flowoplib_block(threadflow_t * threadflow,flowop_t * flowop)6185184Sek110237 flowoplib_block(threadflow_t *threadflow, flowop_t *flowop)
6195184Sek110237 {
6205184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d blocking at address %zx",
6215184Sek110237 flowop->fo_name, flowop->fo_instance, &flowop->fo_cv);
6225184Sek110237 (void) ipc_mutex_lock(&flowop->fo_lock);
6235184Sek110237
6245184Sek110237 flowop_beginop(threadflow, flowop);
6255184Sek110237 (void) pthread_cond_wait(&flowop->fo_cv, &flowop->fo_lock);
6265673Saw148015 flowop_endop(threadflow, flowop, 0);
6275184Sek110237
6285184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d unblocking",
6295184Sek110237 flowop->fo_name, flowop->fo_instance);
6305184Sek110237
6315184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock);
6325184Sek110237
6336084Saw148015 return (FILEBENCH_OK);
6345184Sek110237 }
6355184Sek110237
6365184Sek110237 /*
6375184Sek110237 * Wakes up one or more target blocking flowops.
6385184Sek110237 * Sends broadcasts on the fo_cv condition variables of all
6395184Sek110237 * flowops on the target list, except those that are
6405184Sek110237 * FLOW_MASTER flowops. The target list consists of all
6415184Sek110237 * flowops whose name matches this flowop's "fo_targetname"
6425184Sek110237 * attribute. The target list is generated on the first
6435184Sek110237 * invocation, and the run will be shutdown if no targets
6446084Saw148015 * are found. Otherwise the routine always returns FILEBENCH_OK.
6455184Sek110237 */
6465184Sek110237 static int
flowoplib_wakeup(threadflow_t * threadflow,flowop_t * flowop)6475184Sek110237 flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop)
6485184Sek110237 {
6495184Sek110237 flowop_t *target;
6505184Sek110237
6515184Sek110237 /* if this is the first wakeup, create the wakeup list */
6525184Sek110237 if (flowop->fo_targets == NULL) {
6535184Sek110237 flowop_t *result = flowop_find(flowop->fo_targetname);
6545184Sek110237
6555184Sek110237 flowop->fo_targets = result;
6565184Sek110237 if (result == NULL) {
6575184Sek110237 filebench_log(LOG_ERROR,
6585184Sek110237 "wakeup: could not find op %s for thread %s",
6595184Sek110237 flowop->fo_targetname,
6605184Sek110237 threadflow->tf_name);
6615184Sek110237 filebench_shutdown(1);
6625184Sek110237 }
6635184Sek110237 while (result) {
6645184Sek110237 result->fo_targetnext =
6655184Sek110237 result->fo_resultnext;
6665184Sek110237 result = result->fo_resultnext;
6675184Sek110237 }
6685184Sek110237 }
6695184Sek110237
6705184Sek110237 target = flowop->fo_targets;
6715184Sek110237
6725184Sek110237 /* wakeup the targets */
6735184Sek110237 while (target) {
6745184Sek110237 if (target->fo_instance == FLOW_MASTER) {
6755184Sek110237 target = target->fo_targetnext;
6765184Sek110237 continue;
6775184Sek110237 }
6785184Sek110237 filebench_log(LOG_DEBUG_IMPL,
6795184Sek110237 "wakeup flow %s-%d at address %zx",
6805184Sek110237 target->fo_name,
6815184Sek110237 target->fo_instance,
6825184Sek110237 &target->fo_cv);
6835184Sek110237
6845184Sek110237 flowop_beginop(threadflow, flowop);
6855184Sek110237 (void) ipc_mutex_lock(&target->fo_lock);
6865184Sek110237 (void) pthread_cond_broadcast(&target->fo_cv);
6875184Sek110237 (void) ipc_mutex_unlock(&target->fo_lock);
6885673Saw148015 flowop_endop(threadflow, flowop, 0);
6895184Sek110237
6905184Sek110237 target = target->fo_targetnext;
6915184Sek110237 }
6925184Sek110237
6936084Saw148015 return (FILEBENCH_OK);
6945184Sek110237 }
6955184Sek110237
6965184Sek110237 /*
6975184Sek110237 * "think time" routines. the "hog" routine consumes cpu cycles as
6985184Sek110237 * it "thinks", while the "delay" flowop simply calls sleep() to delay
6995184Sek110237 * for a given number of seconds without consuming cpu cycles.
7005184Sek110237 */
7015184Sek110237
7025184Sek110237
7035184Sek110237 /*
7045184Sek110237 * Consumes CPU cycles and memory bandwidth by looping for
7055184Sek110237 * flowop->fo_value times. With each loop sets memory location
7065184Sek110237 * threadflow->tf_mem to 1.
7075184Sek110237 */
7085184Sek110237 static int
flowoplib_hog(threadflow_t * threadflow,flowop_t * flowop)7095184Sek110237 flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop)
7105184Sek110237 {
7116212Saw148015 uint64_t value = avd_get_int(flowop->fo_value);
7125184Sek110237 int i;
7135184Sek110237
7145673Saw148015 filebench_log(LOG_DEBUG_IMPL, "hog enter");
7155184Sek110237 flowop_beginop(threadflow, flowop);
7165673Saw148015 if (threadflow->tf_mem != NULL) {
7175673Saw148015 for (i = 0; i < value; i++)
7185673Saw148015 *(threadflow->tf_mem) = 1;
7195673Saw148015 }
7205673Saw148015 flowop_endop(threadflow, flowop, 0);
7215184Sek110237 filebench_log(LOG_DEBUG_IMPL, "hog exit");
7226084Saw148015 return (FILEBENCH_OK);
7235184Sek110237 }
7245184Sek110237
7255184Sek110237
7265184Sek110237 /*
7275184Sek110237 * Delays for fo_value seconds.
7285184Sek110237 */
7295184Sek110237 static int
flowoplib_delay(threadflow_t * threadflow,flowop_t * flowop)7305184Sek110237 flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop)
7315184Sek110237 {
7326212Saw148015 int value = avd_get_int(flowop->fo_value);
7335184Sek110237
7345184Sek110237 flowop_beginop(threadflow, flowop);
7355184Sek110237 (void) sleep(value);
7365673Saw148015 flowop_endop(threadflow, flowop, 0);
7376084Saw148015 return (FILEBENCH_OK);
7385184Sek110237 }
7395184Sek110237
7405184Sek110237 /*
7415184Sek110237 * Rate limiting routines. This is the event consuming half of the
7425184Sek110237 * event system. Each of the four following routines will limit the rate
7435184Sek110237 * to one unit of either calls, issued I/O operations, issued filebench
7445184Sek110237 * operations, or I/O bandwidth. Since there is only one event generator,
7455184Sek110237 * the events will be divided amoung multiple instances of an event
7465184Sek110237 * consumer, and further divided among different consumers if more than
7475184Sek110237 * one has been defined. There is no mechanism to enforce equal sharing
7485184Sek110237 * of events.
7495184Sek110237 */
7505184Sek110237
7515184Sek110237 /*
7525184Sek110237 * Completes one invocation per posted event. If eventgen_q
7535184Sek110237 * has an event count greater than zero, one will be removed
7545184Sek110237 * (count decremented), otherwise the calling thread will
7555184Sek110237 * block until another event has been posted. Always returns 0
7565184Sek110237 */
7575184Sek110237 static int
flowoplib_eventlimit(threadflow_t * threadflow,flowop_t * flowop)7585184Sek110237 flowoplib_eventlimit(threadflow_t *threadflow, flowop_t *flowop)
7595184Sek110237 {
7605184Sek110237 /* Immediately bail if not set/enabled */
761*9801SAndrew.W.Wilson@sun.com if (!filebench_shm->shm_eventgen_enabled)
7626084Saw148015 return (FILEBENCH_OK);
7635184Sek110237
7645184Sek110237 if (flowop->fo_initted == 0) {
7655184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
7665184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance);
7675184Sek110237 flowop->fo_initted = 1;
7685184Sek110237 }
7695184Sek110237
7705184Sek110237 flowop_beginop(threadflow, flowop);
771*9801SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_enabled) {
7726391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
7736391Saw148015 if (filebench_shm->shm_eventgen_q > 0) {
7746391Saw148015 filebench_shm->shm_eventgen_q--;
7756391Saw148015 (void) ipc_mutex_unlock(
7766391Saw148015 &filebench_shm->shm_eventgen_lock);
7775184Sek110237 break;
7785184Sek110237 }
7796391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
7806391Saw148015 &filebench_shm->shm_eventgen_lock);
7816391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
7825184Sek110237 }
7835673Saw148015 flowop_endop(threadflow, flowop, 0);
7846084Saw148015 return (FILEBENCH_OK);
7855184Sek110237 }
7865184Sek110237
7876701Saw148015 static int
flowoplib_event_find_target(threadflow_t * threadflow,flowop_t * flowop)7886701Saw148015 flowoplib_event_find_target(threadflow_t *threadflow, flowop_t *flowop)
7896701Saw148015 {
7906701Saw148015 if (flowop->fo_targetname[0] != '\0') {
7916701Saw148015
7926701Saw148015 /* Try to use statistics from specific flowop */
7936701Saw148015 flowop->fo_targets =
7946701Saw148015 flowop_find_from_list(flowop->fo_targetname,
7956701Saw148015 threadflow->tf_thrd_fops);
7966701Saw148015 if (flowop->fo_targets == NULL) {
7976701Saw148015 filebench_log(LOG_ERROR,
7986701Saw148015 "limit target: could not find flowop %s",
7996701Saw148015 flowop->fo_targetname);
8006701Saw148015 filebench_shutdown(1);
8016701Saw148015 return (FILEBENCH_ERROR);
8026701Saw148015 }
8036701Saw148015 } else {
8046701Saw148015 /* use total workload statistics */
8056701Saw148015 flowop->fo_targets = NULL;
8066701Saw148015 }
8076701Saw148015 return (FILEBENCH_OK);
8086701Saw148015 }
8096701Saw148015
8105184Sek110237 /*
8115184Sek110237 * Blocks the calling thread if the number of issued I/O
8125184Sek110237 * operations exceeds the number of posted events, thus
8135184Sek110237 * limiting the average I/O operation rate to the rate
8146084Saw148015 * specified by eventgen_hz. Always returns FILEBENCH_OK.
8155184Sek110237 */
8165184Sek110237 static int
flowoplib_iopslimit(threadflow_t * threadflow,flowop_t * flowop)8175184Sek110237 flowoplib_iopslimit(threadflow_t *threadflow, flowop_t *flowop)
8185184Sek110237 {
8195184Sek110237 uint64_t iops;
8205184Sek110237 uint64_t delta;
8215673Saw148015 uint64_t events;
8225184Sek110237
8235184Sek110237 /* Immediately bail if not set/enabled */
824*9801SAndrew.W.Wilson@sun.com if (!filebench_shm->shm_eventgen_enabled)
8256084Saw148015 return (FILEBENCH_OK);
8265184Sek110237
8275184Sek110237 if (flowop->fo_initted == 0) {
8285184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
8295184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance);
8305184Sek110237 flowop->fo_initted = 1;
8316701Saw148015
8326701Saw148015 if (flowoplib_event_find_target(threadflow, flowop)
8336701Saw148015 == FILEBENCH_ERROR)
8346701Saw148015 return (FILEBENCH_ERROR);
8356701Saw148015
8366701Saw148015 if (flowop->fo_targets && ((flowop->fo_targets->fo_attrs &
8376701Saw148015 (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) {
8386701Saw148015 filebench_log(LOG_ERROR,
8396701Saw148015 "WARNING: Flowop %s does no IO",
8406701Saw148015 flowop->fo_targets->fo_name);
8416701Saw148015 filebench_shutdown(1);
8426701Saw148015 return (FILEBENCH_ERROR);
8436701Saw148015 }
8445184Sek110237 }
8455184Sek110237
8466701Saw148015 if (flowop->fo_targets) {
8476701Saw148015 /*
8486701Saw148015 * Note that fs_count is already the sum of fs_rcount
8496701Saw148015 * and fs_wcount if looking at a single flowop.
8506701Saw148015 */
8516701Saw148015 iops = flowop->fo_targets->fo_stats.fs_count;
8526701Saw148015 } else {
8536701Saw148015 (void) ipc_mutex_lock(&controlstats_lock);
8546701Saw148015 iops = (controlstats.fs_rcount +
8556701Saw148015 controlstats.fs_wcount);
8566701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock);
8576701Saw148015 }
8585184Sek110237
8595184Sek110237 /* Is this the first time around */
8605184Sek110237 if (flowop->fo_tputlast == 0) {
8615184Sek110237 flowop->fo_tputlast = iops;
8626084Saw148015 return (FILEBENCH_OK);
8635184Sek110237 }
8645184Sek110237
8655184Sek110237 delta = iops - flowop->fo_tputlast;
8665184Sek110237 flowop->fo_tputbucket -= delta;
8675184Sek110237 flowop->fo_tputlast = iops;
8685184Sek110237
8695184Sek110237 /* No need to block if the q isn't empty */
8705184Sek110237 if (flowop->fo_tputbucket >= 0LL) {
8715673Saw148015 flowop_endop(threadflow, flowop, 0);
8726084Saw148015 return (FILEBENCH_OK);
8735184Sek110237 }
8745184Sek110237
8755184Sek110237 iops = flowop->fo_tputbucket * -1;
8765184Sek110237 events = iops;
8775184Sek110237
8785184Sek110237 flowop_beginop(threadflow, flowop);
879*9801SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_enabled) {
8805184Sek110237
8816391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
8826391Saw148015 if (filebench_shm->shm_eventgen_q >= events) {
8836391Saw148015 filebench_shm->shm_eventgen_q -= events;
8846391Saw148015 (void) ipc_mutex_unlock(
8856391Saw148015 &filebench_shm->shm_eventgen_lock);
8865184Sek110237 flowop->fo_tputbucket += events;
8875184Sek110237 break;
8885184Sek110237 }
8896391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
8906391Saw148015 &filebench_shm->shm_eventgen_lock);
8916391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
8925184Sek110237 }
8935673Saw148015 flowop_endop(threadflow, flowop, 0);
8945184Sek110237
8956084Saw148015 return (FILEBENCH_OK);
8965184Sek110237 }
8975184Sek110237
8985184Sek110237 /*
8995184Sek110237 * Blocks the calling thread if the number of issued filebench
9005184Sek110237 * operations exceeds the number of posted events, thus limiting
9015184Sek110237 * the average filebench operation rate to the rate specified by
9026084Saw148015 * eventgen_hz. Always returns FILEBENCH_OK.
9035184Sek110237 */
9045184Sek110237 static int
flowoplib_opslimit(threadflow_t * threadflow,flowop_t * flowop)9055184Sek110237 flowoplib_opslimit(threadflow_t *threadflow, flowop_t *flowop)
9065184Sek110237 {
9075184Sek110237 uint64_t ops;
9085184Sek110237 uint64_t delta;
9095673Saw148015 uint64_t events;
9105184Sek110237
9115184Sek110237 /* Immediately bail if not set/enabled */
912*9801SAndrew.W.Wilson@sun.com if (!filebench_shm->shm_eventgen_enabled)
9136084Saw148015 return (FILEBENCH_OK);
9145184Sek110237
9155184Sek110237 if (flowop->fo_initted == 0) {
9165184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
9175184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance);
9185184Sek110237 flowop->fo_initted = 1;
9196701Saw148015
9206701Saw148015 if (flowoplib_event_find_target(threadflow, flowop)
9216701Saw148015 == FILEBENCH_ERROR)
9226701Saw148015 return (FILEBENCH_ERROR);
9235184Sek110237 }
9245184Sek110237
9256701Saw148015 if (flowop->fo_targets) {
9266701Saw148015 ops = flowop->fo_targets->fo_stats.fs_count;
9276701Saw148015 } else {
9286701Saw148015 (void) ipc_mutex_lock(&controlstats_lock);
9296701Saw148015 ops = controlstats.fs_count;
9306701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock);
9316701Saw148015 }
9325184Sek110237
9335184Sek110237 /* Is this the first time around */
9345184Sek110237 if (flowop->fo_tputlast == 0) {
9355184Sek110237 flowop->fo_tputlast = ops;
9366084Saw148015 return (FILEBENCH_OK);
9375184Sek110237 }
9385184Sek110237
9395184Sek110237 delta = ops - flowop->fo_tputlast;
9405184Sek110237 flowop->fo_tputbucket -= delta;
9415184Sek110237 flowop->fo_tputlast = ops;
9425184Sek110237
9435184Sek110237 /* No need to block if the q isn't empty */
9445184Sek110237 if (flowop->fo_tputbucket >= 0LL) {
9455673Saw148015 flowop_endop(threadflow, flowop, 0);
9466084Saw148015 return (FILEBENCH_OK);
9475184Sek110237 }
9485184Sek110237
9495184Sek110237 ops = flowop->fo_tputbucket * -1;
9505184Sek110237 events = ops;
9515184Sek110237
9525184Sek110237 flowop_beginop(threadflow, flowop);
953*9801SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_enabled) {
9546391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
9556391Saw148015 if (filebench_shm->shm_eventgen_q >= events) {
9566391Saw148015 filebench_shm->shm_eventgen_q -= events;
9576391Saw148015 (void) ipc_mutex_unlock(
9586391Saw148015 &filebench_shm->shm_eventgen_lock);
9595184Sek110237 flowop->fo_tputbucket += events;
9605184Sek110237 break;
9615184Sek110237 }
9626391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
9636391Saw148015 &filebench_shm->shm_eventgen_lock);
9646391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
9655184Sek110237 }
9665673Saw148015 flowop_endop(threadflow, flowop, 0);
9675184Sek110237
9686084Saw148015 return (FILEBENCH_OK);
9695184Sek110237 }
9705184Sek110237
9715184Sek110237
9725184Sek110237 /*
9735184Sek110237 * Blocks the calling thread if the number of bytes of I/O
9745184Sek110237 * issued exceeds one megabyte times the number of posted
9755184Sek110237 * events, thus limiting the average I/O byte rate to one
9765184Sek110237 * megabyte times the event rate as set by eventgen_hz.
9776084Saw148015 * Always retuns FILEBENCH_OK.
9785184Sek110237 */
9795184Sek110237 static int
flowoplib_bwlimit(threadflow_t * threadflow,flowop_t * flowop)9805184Sek110237 flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop)
9815184Sek110237 {
9825184Sek110237 uint64_t bytes;
9835184Sek110237 uint64_t delta;
9845673Saw148015 uint64_t events;
9855184Sek110237
9865184Sek110237 /* Immediately bail if not set/enabled */
987*9801SAndrew.W.Wilson@sun.com if (!filebench_shm->shm_eventgen_enabled)
9886084Saw148015 return (FILEBENCH_OK);
9895184Sek110237
9905184Sek110237 if (flowop->fo_initted == 0) {
9915184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
9925184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance);
9935184Sek110237 flowop->fo_initted = 1;
9946701Saw148015
9956701Saw148015 if (flowoplib_event_find_target(threadflow, flowop)
9966701Saw148015 == FILEBENCH_ERROR)
9976701Saw148015 return (FILEBENCH_ERROR);
9986701Saw148015
9996701Saw148015 if ((flowop->fo_targets) &&
10006701Saw148015 ((flowop->fo_targets->fo_attrs &
10016701Saw148015 (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) {
10026701Saw148015 filebench_log(LOG_ERROR,
10036701Saw148015 "WARNING: Flowop %s does no Reads or Writes",
10046701Saw148015 flowop->fo_targets->fo_name);
10056701Saw148015 filebench_shutdown(1);
10066701Saw148015 return (FILEBENCH_ERROR);
10076701Saw148015 }
10085184Sek110237 }
10095184Sek110237
10106701Saw148015 if (flowop->fo_targets) {
10116701Saw148015 /*
10126701Saw148015 * Note that fs_bytes is already the sum of fs_rbytes
10136701Saw148015 * and fs_wbytes if looking at a single flowop.
10146701Saw148015 */
10156701Saw148015 bytes = flowop->fo_targets->fo_stats.fs_bytes;
10166701Saw148015 } else {
10176701Saw148015 (void) ipc_mutex_lock(&controlstats_lock);
10186701Saw148015 bytes = (controlstats.fs_rbytes +
10196701Saw148015 controlstats.fs_wbytes);
10206701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock);
10216701Saw148015 }
10226701Saw148015
10236701Saw148015 /* Is this the first time around? */
10245184Sek110237 if (flowop->fo_tputlast == 0) {
10255184Sek110237 flowop->fo_tputlast = bytes;
10266084Saw148015 return (FILEBENCH_OK);
10275184Sek110237 }
10285184Sek110237
10295184Sek110237 delta = bytes - flowop->fo_tputlast;
10305184Sek110237 flowop->fo_tputbucket -= delta;
10315184Sek110237 flowop->fo_tputlast = bytes;
10325184Sek110237
10335184Sek110237 /* No need to block if the q isn't empty */
10345184Sek110237 if (flowop->fo_tputbucket >= 0LL) {
10355673Saw148015 flowop_endop(threadflow, flowop, 0);
10366084Saw148015 return (FILEBENCH_OK);
10375184Sek110237 }
10385184Sek110237
10395184Sek110237 bytes = flowop->fo_tputbucket * -1;
10405184Sek110237 events = (bytes / MB) + 1;
10415184Sek110237
10426286Saw148015 filebench_log(LOG_DEBUG_IMPL, "%llu bytes, %llu events",
10436286Saw148015 (u_longlong_t)bytes, (u_longlong_t)events);
10445184Sek110237
10455184Sek110237 flowop_beginop(threadflow, flowop);
1046*9801SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_enabled) {
10476391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
10486391Saw148015 if (filebench_shm->shm_eventgen_q >= events) {
10496391Saw148015 filebench_shm->shm_eventgen_q -= events;
10506391Saw148015 (void) ipc_mutex_unlock(
10516391Saw148015 &filebench_shm->shm_eventgen_lock);
10525184Sek110237 flowop->fo_tputbucket += (events * MB);
10535184Sek110237 break;
10545184Sek110237 }
10556391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv,
10566391Saw148015 &filebench_shm->shm_eventgen_lock);
10576391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
10585184Sek110237 }
10595673Saw148015 flowop_endop(threadflow, flowop, 0);
10605184Sek110237
10616084Saw148015 return (FILEBENCH_OK);
10625184Sek110237 }
10635184Sek110237
10645184Sek110237 /*
10655184Sek110237 * These flowops terminate a benchmark run when either the specified
10665184Sek110237 * number of bytes of I/O (flowoplib_finishonbytes) or the specified
10675184Sek110237 * number of I/O operations (flowoplib_finishoncount) have been generated.
10685184Sek110237 */
10695184Sek110237
10705184Sek110237
10715184Sek110237 /*
10725184Sek110237 * Stop filebench run when specified number of I/O bytes have been
10736212Saw148015 * transferred. Compares controlstats.fs_bytes with flowop->value,
10745184Sek110237 * and if greater returns 1, stopping the run, if not, returns 0
10755184Sek110237 * to continue running.
10765184Sek110237 */
10775184Sek110237 static int
flowoplib_finishonbytes(threadflow_t * threadflow,flowop_t * flowop)10785184Sek110237 flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop)
10795184Sek110237 {
10806701Saw148015 uint64_t bytes_io; /* Bytes of I/O delivered so far */
10816701Saw148015 uint64_t byte_lim = flowop->fo_constvalue; /* Total Bytes desired */
10826701Saw148015 /* Uses constant value */
10836701Saw148015
10846701Saw148015 if (flowop->fo_initted == 0) {
10856701Saw148015 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
10866701Saw148015 flowop, threadflow->tf_name, threadflow->tf_instance);
10876701Saw148015 flowop->fo_initted = 1;
10886701Saw148015
10896701Saw148015 if (flowoplib_event_find_target(threadflow, flowop)
10906701Saw148015 == FILEBENCH_ERROR)
10916701Saw148015 return (FILEBENCH_ERROR);
10926701Saw148015
10936701Saw148015 if ((flowop->fo_targets) &&
10946701Saw148015 ((flowop->fo_targets->fo_attrs &
10956701Saw148015 (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) {
10966701Saw148015 filebench_log(LOG_ERROR,
10976701Saw148015 "WARNING: Flowop %s does no Reads or Writes",
10986701Saw148015 flowop->fo_targets->fo_name);
10996701Saw148015 filebench_shutdown(1);
11006701Saw148015 return (FILEBENCH_ERROR);
11016701Saw148015 }
11026701Saw148015 }
11036701Saw148015
11046701Saw148015 if (flowop->fo_targets) {
11056701Saw148015 bytes_io = flowop->fo_targets->fo_stats.fs_bytes;
11066701Saw148015 } else {
11076701Saw148015 (void) ipc_mutex_lock(&controlstats_lock);
11086701Saw148015 bytes_io = controlstats.fs_bytes;
11096701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock);
11106701Saw148015 }
11115184Sek110237
11125184Sek110237 flowop_beginop(threadflow, flowop);
11136701Saw148015 if (bytes_io > byte_lim) {
11145673Saw148015 flowop_endop(threadflow, flowop, 0);
11156084Saw148015 return (FILEBENCH_DONE);
11165184Sek110237 }
11175673Saw148015 flowop_endop(threadflow, flowop, 0);
11185184Sek110237
11196084Saw148015 return (FILEBENCH_OK);
11205184Sek110237 }
11215184Sek110237
11225184Sek110237 /*
11235184Sek110237 * Stop filebench run when specified number of I/O operations have
11245184Sek110237 * been performed. Compares controlstats.fs_count with *flowop->value,
11256084Saw148015 * and if greater returns 1, stopping the run, if not, returns FILEBENCH_OK
11266084Saw148015 * to continue running.
11275184Sek110237 */
11285184Sek110237 static int
flowoplib_finishoncount(threadflow_t * threadflow,flowop_t * flowop)11295184Sek110237 flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop)
11305184Sek110237 {
11315184Sek110237 uint64_t ops;
11326212Saw148015 uint64_t count = flowop->fo_constvalue; /* use constant value */
11335184Sek110237
11346701Saw148015 if (flowop->fo_initted == 0) {
11356701Saw148015 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking",
11366701Saw148015 flowop, threadflow->tf_name, threadflow->tf_instance);
11376701Saw148015 flowop->fo_initted = 1;
11386701Saw148015
11396701Saw148015 if (flowoplib_event_find_target(threadflow, flowop)
11406701Saw148015 == FILEBENCH_ERROR)
11416701Saw148015 return (FILEBENCH_ERROR);
11426701Saw148015 }
11436701Saw148015
11446701Saw148015 if (flowop->fo_targets) {
11456701Saw148015 ops = flowop->fo_targets->fo_stats.fs_count;
11466701Saw148015 } else {
11476701Saw148015 (void) ipc_mutex_lock(&controlstats_lock);
11486701Saw148015 ops = controlstats.fs_count;
11496701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock);
11506701Saw148015 }
11515184Sek110237
11525184Sek110237 flowop_beginop(threadflow, flowop);
11536084Saw148015 if (ops >= count) {
11545673Saw148015 flowop_endop(threadflow, flowop, 0);
11556084Saw148015 return (FILEBENCH_DONE);
11565184Sek110237 }
11575673Saw148015 flowop_endop(threadflow, flowop, 0);
11585184Sek110237
11596084Saw148015 return (FILEBENCH_OK);
11605184Sek110237 }
11615184Sek110237
11625184Sek110237 /*
11635184Sek110237 * Semaphore synchronization using either System V semaphores or
11645184Sek110237 * posix semaphores. If System V semaphores are available, they will be
11655184Sek110237 * used, otherwise posix semaphores will be used.
11665184Sek110237 */
11675184Sek110237
11685184Sek110237
11695184Sek110237 /*
11705184Sek110237 * Initializes the filebench "block on semaphore" flowop.
11715184Sek110237 * If System V semaphores are implemented, the routine
11725184Sek110237 * initializes the System V semaphore subsystem if it hasn't
11735184Sek110237 * already been initialized, also allocates a pair of semids
11745184Sek110237 * and initializes the highwater System V semaphore.
11755184Sek110237 * If no System V semaphores, then does nothing special.
11766084Saw148015 * Returns FILEBENCH_ERROR if it cannot acquire a set of System V semphores
11776084Saw148015 * or if the initial post to the semaphore set fails. Returns FILEBENCH_OK
11785184Sek110237 * on success.
11795184Sek110237 */
11805184Sek110237 static int
flowoplib_semblock_init(flowop_t * flowop)11815184Sek110237 flowoplib_semblock_init(flowop_t *flowop)
11825184Sek110237 {
11835184Sek110237
11845184Sek110237 #ifdef HAVE_SYSV_SEM
11856391Saw148015 int sys_semid;
11865184Sek110237 struct sembuf sbuf[2];
11875184Sek110237 int highwater;
11885184Sek110237
11895184Sek110237 ipc_seminit();
11905184Sek110237
11915184Sek110237 flowop->fo_semid_lw = ipc_semidalloc();
11925184Sek110237 flowop->fo_semid_hw = ipc_semidalloc();
11935184Sek110237
11945184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d semblock init semid=%x",
11955184Sek110237 flowop->fo_name, flowop->fo_instance, flowop->fo_semid_lw);
11965184Sek110237
11976391Saw148015 sys_semid = filebench_shm->shm_sys_semid;
11985184Sek110237
11995184Sek110237 if ((highwater = flowop->fo_semid_hw) == 0)
12006212Saw148015 highwater = flowop->fo_constvalue; /* use constant value */
12015184Sek110237
12025184Sek110237 filebench_log(LOG_DEBUG_IMPL, "setting highwater to : %d", highwater);
12035184Sek110237
12045673Saw148015 sbuf[0].sem_num = (short)highwater;
12056212Saw148015 sbuf[0].sem_op = avd_get_int(flowop->fo_highwater);
12065184Sek110237 sbuf[0].sem_flg = 0;
12076391Saw148015 if ((semop(sys_semid, &sbuf[0], 1) == -1) && errno) {
12085184Sek110237 filebench_log(LOG_ERROR, "semblock init post failed: %s (%d,"
12095184Sek110237 "%d)", strerror(errno), sbuf[0].sem_num, sbuf[0].sem_op);
12106084Saw148015 return (FILEBENCH_ERROR);
12115184Sek110237 }
12125184Sek110237 #else
12135184Sek110237 filebench_log(LOG_DEBUG_IMPL,
12145184Sek110237 "flow %s-%d semblock init with posix semaphore",
12155184Sek110237 flowop->fo_name, flowop->fo_instance);
12165184Sek110237
12175184Sek110237 sem_init(&flowop->fo_sem, 1, 0);
12185184Sek110237 #endif /* HAVE_SYSV_SEM */
12195184Sek110237
12206212Saw148015 if (!(avd_get_bool(flowop->fo_blocking)))
12215184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock);
12225184Sek110237
12236084Saw148015 return (FILEBENCH_OK);
12245184Sek110237 }
12255184Sek110237
12265184Sek110237 /*
12275184Sek110237 * Releases the semids for the System V semaphore allocated
12285184Sek110237 * to this flowop. If not using System V semaphores, then
12296084Saw148015 * it is effectively just a no-op.
12305184Sek110237 */
12315184Sek110237 static void
flowoplib_semblock_destruct(flowop_t * flowop)12325184Sek110237 flowoplib_semblock_destruct(flowop_t *flowop)
12335184Sek110237 {
12345184Sek110237 #ifdef HAVE_SYSV_SEM
12355184Sek110237 ipc_semidfree(flowop->fo_semid_lw);
12365184Sek110237 ipc_semidfree(flowop->fo_semid_hw);
12375184Sek110237 #else
12385184Sek110237 sem_destroy(&flowop->fo_sem);
12395184Sek110237 #endif /* HAVE_SYSV_SEM */
12405184Sek110237 }
12415184Sek110237
12425184Sek110237 /*
12435184Sek110237 * Attempts to pass a System V or posix semaphore as appropriate,
12446084Saw148015 * and blocks if necessary. Returns FILEBENCH_ERROR if a set of System V
12455184Sek110237 * semphores is not available or cannot be acquired, or if the initial
12466084Saw148015 * post to the semaphore set fails. Returns FILEBENCH_OK on success.
12475184Sek110237 */
12485184Sek110237 static int
flowoplib_semblock(threadflow_t * threadflow,flowop_t * flowop)12495184Sek110237 flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop)
12505184Sek110237 {
12515184Sek110237
12525184Sek110237 #ifdef HAVE_SYSV_SEM
12535184Sek110237 struct sembuf sbuf[2];
12546212Saw148015 int value = avd_get_int(flowop->fo_value);
12556391Saw148015 int sys_semid;
12565184Sek110237 struct timespec timeout;
12575184Sek110237
12586391Saw148015 sys_semid = filebench_shm->shm_sys_semid;
12595184Sek110237
12605184Sek110237 filebench_log(LOG_DEBUG_IMPL,
12615184Sek110237 "flow %s-%d sem blocking on id %x num %x value %d",
12626391Saw148015 flowop->fo_name, flowop->fo_instance, sys_semid,
12635184Sek110237 flowop->fo_semid_hw, value);
12645184Sek110237
12655184Sek110237 /* Post, decrement the increment the hw queue */
12665184Sek110237 sbuf[0].sem_num = flowop->fo_semid_hw;
12675673Saw148015 sbuf[0].sem_op = (short)value;
12685184Sek110237 sbuf[0].sem_flg = 0;
12695184Sek110237 sbuf[1].sem_num = flowop->fo_semid_lw;
12705184Sek110237 sbuf[1].sem_op = value * -1;
12715184Sek110237 sbuf[1].sem_flg = 0;
12725184Sek110237 timeout.tv_sec = 600;
12735184Sek110237 timeout.tv_nsec = 0;
12745184Sek110237
12756212Saw148015 if (avd_get_bool(flowop->fo_blocking))
12765184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock);
12775184Sek110237
12785184Sek110237 flowop_beginop(threadflow, flowop);
12795184Sek110237
12805184Sek110237 #ifdef HAVE_SEMTIMEDOP
12816391Saw148015 (void) semtimedop(sys_semid, &sbuf[0], 1, &timeout);
12826391Saw148015 (void) semtimedop(sys_semid, &sbuf[1], 1, &timeout);
12835184Sek110237 #else
12846391Saw148015 (void) semop(sys_semid, &sbuf[0], 1);
12856391Saw148015 (void) semop(sys_semid, &sbuf[1], 1);
12865184Sek110237 #endif /* HAVE_SEMTIMEDOP */
12875184Sek110237
12886212Saw148015 if (avd_get_bool(flowop->fo_blocking))
12895184Sek110237 (void) ipc_mutex_lock(&flowop->fo_lock);
12905184Sek110237
12915673Saw148015 flowop_endop(threadflow, flowop, 0);
12925184Sek110237
12935184Sek110237 #else
12946212Saw148015 int value = avd_get_int(flowop->fo_value);
12955184Sek110237 int i;
12965184Sek110237
12975184Sek110237 filebench_log(LOG_DEBUG_IMPL,
12985184Sek110237 "flow %s-%d sem blocking on posix semaphore",
12995184Sek110237 flowop->fo_name, flowop->fo_instance);
13005184Sek110237
13015184Sek110237 /* Decrement sem by value */
13025184Sek110237 for (i = 0; i < value; i++) {
13035184Sek110237 if (sem_wait(&flowop->fo_sem) == -1) {
13045184Sek110237 filebench_log(LOG_ERROR, "semop wait failed");
13056084Saw148015 return (FILEBENCH_ERROR);
13065184Sek110237 }
13075184Sek110237 }
13085184Sek110237
13095184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d sem unblocking",
13105184Sek110237 flowop->fo_name, flowop->fo_instance);
13115184Sek110237 #endif /* HAVE_SYSV_SEM */
13125184Sek110237
13136084Saw148015 return (FILEBENCH_OK);
13145184Sek110237 }
13155184Sek110237
13165184Sek110237 /*
13176084Saw148015 * Calls ipc_seminit(). Always returns FILEBENCH_OK.
13185184Sek110237 */
13195184Sek110237 /* ARGSUSED */
13205184Sek110237 static int
flowoplib_sempost_init(flowop_t * flowop)13215184Sek110237 flowoplib_sempost_init(flowop_t *flowop)
13225184Sek110237 {
13235184Sek110237 #ifdef HAVE_SYSV_SEM
13245184Sek110237 ipc_seminit();
13255184Sek110237 #endif /* HAVE_SYSV_SEM */
13266084Saw148015 return (FILEBENCH_OK);
13275184Sek110237 }
13285184Sek110237
13295184Sek110237 /*
13305184Sek110237 * Post to a System V or posix semaphore as appropriate.
13315184Sek110237 * On the first call for a given flowop instance, this routine
13325184Sek110237 * will use the fo_targetname attribute to locate all semblock
13335184Sek110237 * flowops that are expecting posts from this flowop. All
13345184Sek110237 * target flowops on this list will have a post operation done
13355184Sek110237 * to their semaphores on each call.
13365184Sek110237 */
13375184Sek110237 static int
flowoplib_sempost(threadflow_t * threadflow,flowop_t * flowop)13385184Sek110237 flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop)
13395184Sek110237 {
13405184Sek110237 flowop_t *target;
13415184Sek110237
13425184Sek110237 filebench_log(LOG_DEBUG_IMPL,
13435184Sek110237 "sempost flow %s-%d",
13445184Sek110237 flowop->fo_name,
13455184Sek110237 flowop->fo_instance);
13465184Sek110237
13475184Sek110237 /* if this is the first post, create the post list */
13485184Sek110237 if (flowop->fo_targets == NULL) {
13495184Sek110237 flowop_t *result = flowop_find(flowop->fo_targetname);
13505184Sek110237
13515184Sek110237 flowop->fo_targets = result;
13525184Sek110237
13535184Sek110237 if (result == NULL) {
13545184Sek110237 filebench_log(LOG_ERROR,
13555184Sek110237 "sempost: could not find op %s for thread %s",
13565184Sek110237 flowop->fo_targetname,
13575184Sek110237 threadflow->tf_name);
13585184Sek110237 filebench_shutdown(1);
13595184Sek110237 }
13605184Sek110237
13615184Sek110237 while (result) {
13625184Sek110237 result->fo_targetnext =
13635184Sek110237 result->fo_resultnext;
13645184Sek110237 result = result->fo_resultnext;
13655184Sek110237 }
13665184Sek110237 }
13675184Sek110237
13685184Sek110237 target = flowop->fo_targets;
13695184Sek110237
13705184Sek110237 flowop_beginop(threadflow, flowop);
13715184Sek110237 /* post to the targets */
13725184Sek110237 while (target) {
13735184Sek110237 #ifdef HAVE_SYSV_SEM
13745184Sek110237 struct sembuf sbuf[2];
13756391Saw148015 int sys_semid;
13765184Sek110237 int blocking;
13775184Sek110237 #else
13785184Sek110237 int i;
13795184Sek110237 #endif /* HAVE_SYSV_SEM */
13805184Sek110237 struct timespec timeout;
13816550Saw148015 int value = (int)avd_get_int(flowop->fo_value);
13825184Sek110237
13835184Sek110237 if (target->fo_instance == FLOW_MASTER) {
13845184Sek110237 target = target->fo_targetnext;
13855184Sek110237 continue;
13865184Sek110237 }
13875184Sek110237
13885184Sek110237 #ifdef HAVE_SYSV_SEM
13895184Sek110237
13905184Sek110237 filebench_log(LOG_DEBUG_IMPL,
13915184Sek110237 "sempost flow %s-%d num %x",
13925184Sek110237 target->fo_name,
13935184Sek110237 target->fo_instance,
13945184Sek110237 target->fo_semid_lw);
13955184Sek110237
13966391Saw148015 sys_semid = filebench_shm->shm_sys_semid;
13975184Sek110237 sbuf[0].sem_num = target->fo_semid_lw;
13985673Saw148015 sbuf[0].sem_op = (short)value;
13995184Sek110237 sbuf[0].sem_flg = 0;
14005184Sek110237 sbuf[1].sem_num = target->fo_semid_hw;
14015184Sek110237 sbuf[1].sem_op = value * -1;
14025184Sek110237 sbuf[1].sem_flg = 0;
14035184Sek110237 timeout.tv_sec = 600;
14045184Sek110237 timeout.tv_nsec = 0;
14055184Sek110237
14066212Saw148015 if (avd_get_bool(flowop->fo_blocking))
14075184Sek110237 blocking = 1;
14085184Sek110237 else
14095184Sek110237 blocking = 0;
14105184Sek110237
14115184Sek110237 #ifdef HAVE_SEMTIMEDOP
14126391Saw148015 if ((semtimedop(sys_semid, &sbuf[0], blocking + 1,
14135184Sek110237 &timeout) == -1) && (errno && (errno != EAGAIN))) {
14145184Sek110237 #else
14156391Saw148015 if ((semop(sys_semid, &sbuf[0], blocking + 1) == -1) &&
14165184Sek110237 (errno && (errno != EAGAIN))) {
14175184Sek110237 #endif /* HAVE_SEMTIMEDOP */
14185184Sek110237 filebench_log(LOG_ERROR, "semop post failed: %s",
14195184Sek110237 strerror(errno));
14206084Saw148015 return (FILEBENCH_ERROR);
14215184Sek110237 }
14225184Sek110237
14235184Sek110237 filebench_log(LOG_DEBUG_IMPL,
14245184Sek110237 "flow %s-%d finished posting",
14255184Sek110237 target->fo_name, target->fo_instance);
14265184Sek110237 #else
14275184Sek110237 filebench_log(LOG_DEBUG_IMPL,
14285184Sek110237 "sempost flow %s-%d to posix semaphore",
14295184Sek110237 target->fo_name,
14305184Sek110237 target->fo_instance);
14315184Sek110237
14325184Sek110237 /* Increment sem by value */
14335184Sek110237 for (i = 0; i < value; i++) {
14345184Sek110237 if (sem_post(&target->fo_sem) == -1) {
14355184Sek110237 filebench_log(LOG_ERROR, "semop post failed");
14366084Saw148015 return (FILEBENCH_ERROR);
14375184Sek110237 }
14385184Sek110237 }
14395184Sek110237
14405184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d unblocking",
14415184Sek110237 target->fo_name, target->fo_instance);
14425184Sek110237 #endif /* HAVE_SYSV_SEM */
14435184Sek110237
14445184Sek110237 target = target->fo_targetnext;
14455184Sek110237 }
14465673Saw148015 flowop_endop(threadflow, flowop, 0);
14475184Sek110237
14486084Saw148015 return (FILEBENCH_OK);
14495184Sek110237 }
14505184Sek110237
14515184Sek110237
14525184Sek110237 /*
14535184Sek110237 * Section for exercising create / open / close / delete operations
14545184Sek110237 * on files within a fileset. For proper operation, the flowop attribute
14555184Sek110237 * "fd", which sets the fo_fdnumber field in the flowop, must be used
14565184Sek110237 * so that the same file is opened and later closed. "fd" is an index
14575184Sek110237 * into a pair of arrays maintained by threadflows, one of which
14585184Sek110237 * contains the operating system assigned file descriptors and the other
14595184Sek110237 * a pointer to the filesetentry whose file the file descriptor
14605184Sek110237 * references. An openfile flowop defined without fd being set will use
14615184Sek110237 * the default (0) fd or, if specified, rotate through fd indices, but
14625184Sek110237 * createfile and closefile must use the default or a specified fd.
14635184Sek110237 * Meanwhile deletefile picks and arbitrary file to delete, regardless
14645184Sek110237 * of fd attribute.
14655184Sek110237 */
14665184Sek110237
14675184Sek110237 /*
14685184Sek110237 * Emulates (and actually does) file open. Obtains a file descriptor
14696084Saw148015 * index, then calls flowoplib_openfile_common() to open. Returns
14706084Saw148015 * FILEBENCH_ERROR if no file descriptor is found, and returns the
14716084Saw148015 * status from flowoplib_openfile_common otherwise (FILEBENCH_ERROR,
14726084Saw148015 * FILEBENCH_NORSC, FILEBENCH_OK).
14735184Sek110237 */
14745184Sek110237 static int
14755184Sek110237 flowoplib_openfile(threadflow_t *threadflow, flowop_t *flowop)
14765184Sek110237 {
14775184Sek110237 int fd = flowoplib_fdnum(threadflow, flowop);
14785184Sek110237
14795184Sek110237 if (fd == -1)
14806084Saw148015 return (FILEBENCH_ERROR);
14815184Sek110237
14825184Sek110237 return (flowoplib_openfile_common(threadflow, flowop, fd));
14835184Sek110237 }
14845184Sek110237
14855184Sek110237 /*
14865184Sek110237 * Common file opening code for filesets. Uses the supplied
14875184Sek110237 * file descriptor index to determine the tf_fd entry to use.
14885184Sek110237 * If the entry is empty (0) and the fileset exists, fileset
14895184Sek110237 * pick is called to select a fileset entry to use. The file
14905184Sek110237 * specified in the filesetentry is opened, and the returned
14915184Sek110237 * operating system file descriptor and a pointer to the
14925184Sek110237 * filesetentry are stored in tf_fd[fd] and tf_fse[fd],
14936084Saw148015 * respectively. Returns FILEBENCH_ERROR on error,
14946084Saw148015 * FILEBENCH_NORSC if no suitable filesetentry can be found,
14956084Saw148015 * and FILEBENCH_OK on success.
14965184Sek110237 */
14975184Sek110237 static int
14985184Sek110237 flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd)
14995184Sek110237 {
15005184Sek110237 filesetentry_t *file;
15016212Saw148015 char *fileset_name;
15025184Sek110237 int tid = 0;
15039326SAndrew.W.Wilson@sun.com int openflag = 0;
15048404SAndrew.W.Wilson@sun.com int err;
15055184Sek110237
15066391Saw148015 if (flowop->fo_fileset == NULL) {
15076391Saw148015 filebench_log(LOG_ERROR, "flowop NULL file");
15086391Saw148015 return (FILEBENCH_ERROR);
15096391Saw148015 }
15106391Saw148015
15116212Saw148015 if ((fileset_name =
15126212Saw148015 avd_get_str(flowop->fo_fileset->fs_name)) == NULL) {
15136212Saw148015 filebench_log(LOG_ERROR,
15146212Saw148015 "flowop %s: fileset has no name", flowop->fo_name);
15156212Saw148015 return (FILEBENCH_ERROR);
15166212Saw148015 }
15176212Saw148015
15185184Sek110237 /*
15199326SAndrew.W.Wilson@sun.com * set the open flag for read only or read/write, as appropriate.
15209326SAndrew.W.Wilson@sun.com */
15219326SAndrew.W.Wilson@sun.com if (avd_get_bool(flowop->fo_fileset->fs_readonly) == TRUE)
15229326SAndrew.W.Wilson@sun.com openflag = O_RDONLY;
15239326SAndrew.W.Wilson@sun.com else
15249326SAndrew.W.Wilson@sun.com openflag = O_RDWR;
15259326SAndrew.W.Wilson@sun.com
15269326SAndrew.W.Wilson@sun.com /*
15275184Sek110237 * If the flowop doesn't default to persistent fd
15285184Sek110237 * then get unique thread ID for use by fileset_pick
15295184Sek110237 */
15306212Saw148015 if (avd_get_bool(flowop->fo_rotatefd))
15315184Sek110237 tid = threadflow->tf_utid;
15325184Sek110237
15338615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr != NULL) {
15345184Sek110237 filebench_log(LOG_ERROR,
15355184Sek110237 "flowop %s attempted to open without closing on fd %d",
15365184Sek110237 flowop->fo_name, fd);
15376084Saw148015 return (FILEBENCH_ERROR);
15385184Sek110237 }
15395184Sek110237
15405673Saw148015 #ifdef HAVE_RAW_SUPPORT
15415673Saw148015 if (flowop->fo_fileset->fs_attrs & FILESET_IS_RAW_DEV) {
15425673Saw148015 int open_attrs = 0;
15435673Saw148015 char name[MAXPATHLEN];
15445673Saw148015
15457946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(name,
15467946SAndrew.W.Wilson@sun.com avd_get_str(flowop->fo_fileset->fs_path), MAXPATHLEN);
15477946SAndrew.W.Wilson@sun.com (void) fb_strlcat(name, "/", MAXPATHLEN);
15487946SAndrew.W.Wilson@sun.com (void) fb_strlcat(name, fileset_name, MAXPATHLEN);
15495673Saw148015
15506212Saw148015 if (avd_get_bool(flowop->fo_dsync)) {
15515673Saw148015 #ifdef sun
15525673Saw148015 open_attrs |= O_DSYNC;
15535673Saw148015 #else
15545673Saw148015 open_attrs |= O_FSYNC;
15555673Saw148015 #endif
15565673Saw148015 }
15575673Saw148015
15585673Saw148015 filebench_log(LOG_DEBUG_SCRIPT,
15595673Saw148015 "open raw device %s flags %d = %d", name, open_attrs, fd);
15605673Saw148015
15618615SAndrew.W.Wilson@sun.com if (FB_OPEN(&(threadflow->tf_fd[fd]), name,
15629326SAndrew.W.Wilson@sun.com openflag | open_attrs, 0666) == FILEBENCH_ERROR) {
15635673Saw148015 filebench_log(LOG_ERROR,
15645673Saw148015 "Failed to open raw device %s: %s",
15655673Saw148015 name, strerror(errno));
15666084Saw148015 return (FILEBENCH_ERROR);
15675673Saw148015 }
15685673Saw148015
15695673Saw148015 /* if running on Solaris, use un-buffered io */
15705673Saw148015 #ifdef sun
15718615SAndrew.W.Wilson@sun.com (void) directio(threadflow->tf_fd[fd].fd_num, DIRECTIO_ON);
15725673Saw148015 #endif
15735673Saw148015
15745673Saw148015 threadflow->tf_fse[fd] = NULL;
15755673Saw148015
15766084Saw148015 return (FILEBENCH_OK);
15775673Saw148015 }
15785673Saw148015 #endif /* HAVE_RAW_SUPPORT */
15795673Saw148015
15808404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop,
15818404SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS, tid)) != FILEBENCH_OK) {
15826084Saw148015 filebench_log(LOG_DEBUG_SCRIPT,
15835184Sek110237 "flowop %s failed to pick file from %s on fd %d",
15846212Saw148015 flowop->fo_name, fileset_name, fd);
15858404SAndrew.W.Wilson@sun.com return (err);
15865184Sek110237 }
15875184Sek110237
15885184Sek110237 threadflow->tf_fse[fd] = file;
15895184Sek110237
15905184Sek110237 flowop_beginop(threadflow, flowop);
15918615SAndrew.W.Wilson@sun.com err = fileset_openfile(&threadflow->tf_fd[fd], flowop->fo_fileset,
15929326SAndrew.W.Wilson@sun.com file, openflag, 0666, flowoplib_fileattrs(flowop));
15935673Saw148015 flowop_endop(threadflow, flowop, 0);
15945184Sek110237
15958615SAndrew.W.Wilson@sun.com if (err == FILEBENCH_ERROR) {
15966212Saw148015 filebench_log(LOG_ERROR, "flowop %s failed to open file %s",
15976212Saw148015 flowop->fo_name, file->fse_path);
15986084Saw148015 return (FILEBENCH_ERROR);
15995184Sek110237 }
16005184Sek110237
16015184Sek110237 filebench_log(LOG_DEBUG_SCRIPT,
16025184Sek110237 "flowop %s: opened %s fd[%d] = %d",
16035184Sek110237 flowop->fo_name, file->fse_path, fd, threadflow->tf_fd[fd]);
16045184Sek110237
16056084Saw148015 return (FILEBENCH_OK);
16065184Sek110237 }
16075184Sek110237
16085184Sek110237 /*
16095184Sek110237 * Emulate create of a file. Uses the flowop's fdnumber to select
16105184Sek110237 * tf_fd and tf_fse array locations to put the created file's file
16118404SAndrew.W.Wilson@sun.com * descriptor and filesetentry respectively. Uses flowoplib_pickfile()
16125184Sek110237 * to select a specific filesetentry whose file does not currently
16135184Sek110237 * exist for the file create operation. Then calls
16145184Sek110237 * fileset_openfile() with the O_CREATE flag set to create the
16156084Saw148015 * file. Returns FILEBENCH_ERROR if the array index specified by fdnumber is
16165184Sek110237 * already in use, the flowop has no associated fileset, or
16175184Sek110237 * the create call fails. Returns 1 if a filesetentry with a
16186084Saw148015 * nonexistent file cannot be found. Returns FILEBENCH_OK on success.
16195184Sek110237 */
16205184Sek110237 static int
16215184Sek110237 flowoplib_createfile(threadflow_t *threadflow, flowop_t *flowop)
16225184Sek110237 {
16235184Sek110237 filesetentry_t *file;
16245184Sek110237 int fd = flowop->fo_fdnumber;
16258404SAndrew.W.Wilson@sun.com int err;
16265184Sek110237
16278615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr != NULL) {
16285184Sek110237 filebench_log(LOG_ERROR,
16295184Sek110237 "flowop %s attempted to create without closing on fd %d",
16305184Sek110237 flowop->fo_name, fd);
16316084Saw148015 return (FILEBENCH_ERROR);
16325184Sek110237 }
16335184Sek110237
16345184Sek110237 if (flowop->fo_fileset == NULL) {
16355184Sek110237 filebench_log(LOG_ERROR, "flowop NULL file");
16366084Saw148015 return (FILEBENCH_ERROR);
16375184Sek110237 }
16385184Sek110237
16399326SAndrew.W.Wilson@sun.com if (avd_get_bool(flowop->fo_fileset->fs_readonly) == TRUE) {
16409326SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Can not CREATE the READONLY file %s",
16419326SAndrew.W.Wilson@sun.com avd_get_str(flowop->fo_fileset->fs_name));
16429326SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
16439326SAndrew.W.Wilson@sun.com }
16449326SAndrew.W.Wilson@sun.com
16459326SAndrew.W.Wilson@sun.com
16465673Saw148015 #ifdef HAVE_RAW_SUPPORT
16475673Saw148015 /* can't be used with raw devices */
16485673Saw148015 if (flowop->fo_fileset->fs_attrs & FILESET_IS_RAW_DEV) {
16495673Saw148015 filebench_log(LOG_ERROR,
16505673Saw148015 "flowop %s attempted to a createfile on RAW device",
16515673Saw148015 flowop->fo_name);
16526084Saw148015 return (FILEBENCH_ERROR);
16535673Saw148015 }
16545673Saw148015 #endif /* HAVE_RAW_SUPPORT */
16555673Saw148015
16568404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop,
16578404SAndrew.W.Wilson@sun.com FILESET_PICKNOEXIST, 0)) != FILEBENCH_OK) {
16586084Saw148015 filebench_log(LOG_DEBUG_SCRIPT,
16596084Saw148015 "flowop %s failed to pick file from fileset %s",
16606212Saw148015 flowop->fo_name,
16616212Saw148015 avd_get_str(flowop->fo_fileset->fs_name));
16628404SAndrew.W.Wilson@sun.com return (err);
16635184Sek110237 }
16645184Sek110237
16655184Sek110237 threadflow->tf_fse[fd] = file;
16665184Sek110237
16675184Sek110237 flowop_beginop(threadflow, flowop);
16688615SAndrew.W.Wilson@sun.com err = fileset_openfile(&threadflow->tf_fd[fd], flowop->fo_fileset,
16695184Sek110237 file, O_RDWR | O_CREAT, 0666, flowoplib_fileattrs(flowop));
16705673Saw148015 flowop_endop(threadflow, flowop, 0);
16715184Sek110237
16728615SAndrew.W.Wilson@sun.com if (err == FILEBENCH_ERROR) {
16735184Sek110237 filebench_log(LOG_ERROR, "failed to create file %s",
16745184Sek110237 flowop->fo_name);
16756084Saw148015 return (FILEBENCH_ERROR);
16765184Sek110237 }
16775184Sek110237
16785184Sek110237 filebench_log(LOG_DEBUG_SCRIPT,
16795184Sek110237 "flowop %s: created %s fd[%d] = %d",
16805184Sek110237 flowop->fo_name, file->fse_path, fd, threadflow->tf_fd[fd]);
16815184Sek110237
16826084Saw148015 return (FILEBENCH_OK);
16835184Sek110237 }
16845184Sek110237
16855184Sek110237 /*
16866391Saw148015 * Emulates delete of a file. If a valid fd is provided, it uses the
16876391Saw148015 * filesetentry stored at that fd location to select the file to be
16886391Saw148015 * deleted, otherwise it picks an arbitrary filesetentry
16896391Saw148015 * whose file exists. It then uses unlink() to delete it and Clears
16906084Saw148015 * the FSE_EXISTS flag for the filesetentry. Returns FILEBENCH_ERROR if the
16916084Saw148015 * flowop has no associated fileset. Returns FILEBENCH_NORSC if an appropriate
16926084Saw148015 * filesetentry cannot be found, and FILEBENCH_OK on success.
16935184Sek110237 */
16945184Sek110237 static int
16955184Sek110237 flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop)
16965184Sek110237 {
16975184Sek110237 filesetentry_t *file;
16985184Sek110237 fileset_t *fileset;
16995184Sek110237 char path[MAXPATHLEN];
17005184Sek110237 char *pathtmp;
17016391Saw148015 int fd = flowop->fo_fdnumber;
17025184Sek110237
17036391Saw148015 /* if fd specified, use it to access file */
17046391Saw148015 if ((fd > 0) && ((file = threadflow->tf_fse[fd]) != NULL)) {
17056391Saw148015
17066391Saw148015 /* indicate that the file will be deleted */
17076391Saw148015 threadflow->tf_fse[fd] = NULL;
17086391Saw148015
17096391Saw148015 /* if here, we still have a valid file pointer */
17106391Saw148015 fileset = file->fse_fileset;
17116391Saw148015 } else {
17128404SAndrew.W.Wilson@sun.com
17136391Saw148015 /* Otherwise, pick arbitrary file */
17146391Saw148015 file = NULL;
17156391Saw148015 fileset = flowop->fo_fileset;
17166391Saw148015 }
17176391Saw148015
17186391Saw148015
17196391Saw148015 if (fileset == NULL) {
17205184Sek110237 filebench_log(LOG_ERROR, "flowop NULL file");
17216084Saw148015 return (FILEBENCH_ERROR);
17225184Sek110237 }
17235184Sek110237
17245673Saw148015 #ifdef HAVE_RAW_SUPPORT
17255673Saw148015 /* can't be used with raw devices */
17266391Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
17275673Saw148015 filebench_log(LOG_ERROR,
17285673Saw148015 "flowop %s attempted a deletefile on RAW device",
17295673Saw148015 flowop->fo_name);
17306084Saw148015 return (FILEBENCH_ERROR);
17315673Saw148015 }
17325673Saw148015 #endif /* HAVE_RAW_SUPPORT */
17335673Saw148015
17346391Saw148015 if (file == NULL) {
17358404SAndrew.W.Wilson@sun.com int err;
17368404SAndrew.W.Wilson@sun.com
17377556SAndrew.W.Wilson@sun.com /* pick arbitrary, existing (allocated) file */
17388404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop,
17398404SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS, 0)) != FILEBENCH_OK) {
17406391Saw148015 filebench_log(LOG_DEBUG_SCRIPT,
17416391Saw148015 "flowop %s failed to pick file", flowop->fo_name);
17428404SAndrew.W.Wilson@sun.com return (err);
17436391Saw148015 }
17446391Saw148015 } else {
17457556SAndrew.W.Wilson@sun.com /* delete specific file. wait for it to be non-busy */
17467556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
17477556SAndrew.W.Wilson@sun.com while (file->fse_flags & FSE_BUSY) {
17487556SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_THRD_WAITNG;
17497556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_thrd_wait_cv,
17507556SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock);
17517556SAndrew.W.Wilson@sun.com }
17527556SAndrew.W.Wilson@sun.com
17537556SAndrew.W.Wilson@sun.com /* File now available, grab it for deletion */
17547556SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_BUSY;
17557556SAndrew.W.Wilson@sun.com fileset->fs_idle_files--;
17567556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
17575184Sek110237 }
17585184Sek110237
17598404SAndrew.W.Wilson@sun.com /* don't delete if anyone (other than me) has file open */
17608615SAndrew.W.Wilson@sun.com if ((fd > 0) && (threadflow->tf_fd[fd].fd_num > 0)) {
17618404SAndrew.W.Wilson@sun.com if (file->fse_open_cnt > 1) {
17628404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
17638404SAndrew.W.Wilson@sun.com "flowop %s can't delete file opened by other"
17648404SAndrew.W.Wilson@sun.com " threads at fd = %d", flowop->fo_name, fd);
17658404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, 0);
17668404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
17678404SAndrew.W.Wilson@sun.com } else {
17688404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
17698404SAndrew.W.Wilson@sun.com "flowop %s deleting still open file at fd = %d",
17708404SAndrew.W.Wilson@sun.com flowop->fo_name, fd);
17718404SAndrew.W.Wilson@sun.com }
17728404SAndrew.W.Wilson@sun.com } else if (file->fse_open_cnt > 0) {
17738404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
17748404SAndrew.W.Wilson@sun.com "flowop %s can't delete file opened by other"
17758404SAndrew.W.Wilson@sun.com " threads at fd = %d, open count = %d",
17768404SAndrew.W.Wilson@sun.com flowop->fo_name, fd, file->fse_open_cnt);
17778404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, 0);
17788404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
17798404SAndrew.W.Wilson@sun.com }
17808404SAndrew.W.Wilson@sun.com
17817946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
17827946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
17837946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
17845184Sek110237 pathtmp = fileset_resolvepath(file);
17857946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
17865184Sek110237 free(pathtmp);
17875184Sek110237
17887556SAndrew.W.Wilson@sun.com /* delete the selected file */
17895184Sek110237 flowop_beginop(threadflow, flowop);
17908615SAndrew.W.Wilson@sun.com (void) FB_UNLINK(path);
17915673Saw148015 flowop_endop(threadflow, flowop, 0);
17927556SAndrew.W.Wilson@sun.com
17937556SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy and no longer exists */
17948404SAndrew.W.Wilson@sun.com fileset_unbusy(file, TRUE, FALSE, -file->fse_open_cnt);
17955184Sek110237
17965184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "deleted file %s", file->fse_path);
17975184Sek110237
17986084Saw148015 return (FILEBENCH_OK);
17995184Sek110237 }
18005184Sek110237
18015184Sek110237 /*
18025184Sek110237 * Emulates fsync of a file. Obtains the file descriptor index
18035184Sek110237 * from the flowop, obtains the actual file descriptor from
18045184Sek110237 * the threadflow's table, checks to be sure it is still an
18056084Saw148015 * open file, then does an fsync operation on it. Returns FILEBENCH_ERROR
18066084Saw148015 * if the file no longer is open, FILEBENCH_OK otherwise.
18075184Sek110237 */
18085184Sek110237 static int
18095184Sek110237 flowoplib_fsync(threadflow_t *threadflow, flowop_t *flowop)
18105184Sek110237 {
18115184Sek110237 filesetentry_t *file;
18125184Sek110237 int fd = flowop->fo_fdnumber;
18135184Sek110237
18148615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr == NULL) {
18155184Sek110237 filebench_log(LOG_ERROR,
18165184Sek110237 "flowop %s attempted to fsync a closed fd %d",
18175184Sek110237 flowop->fo_name, fd);
18186084Saw148015 return (FILEBENCH_ERROR);
18195184Sek110237 }
18205184Sek110237
18215673Saw148015 file = threadflow->tf_fse[fd];
18225673Saw148015
18235673Saw148015 if ((file == NULL) ||
18245673Saw148015 (file->fse_fileset->fs_attrs & FILESET_IS_RAW_DEV)) {
18255673Saw148015 filebench_log(LOG_ERROR,
18265673Saw148015 "flowop %s attempted to a fsync a RAW device",
18275673Saw148015 flowop->fo_name);
18286084Saw148015 return (FILEBENCH_ERROR);
18295673Saw148015 }
18305673Saw148015
18315184Sek110237 /* Measure time to fsync */
18325184Sek110237 flowop_beginop(threadflow, flowop);
18338615SAndrew.W.Wilson@sun.com (void) FB_FSYNC(&threadflow->tf_fd[fd]);
18345673Saw148015 flowop_endop(threadflow, flowop, 0);
18355184Sek110237
18365184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "fsync file %s", file->fse_path);
18375184Sek110237
18386084Saw148015 return (FILEBENCH_OK);
18395184Sek110237 }
18405184Sek110237
18415184Sek110237 /*
18425184Sek110237 * Emulate fsync of an entire fileset. Search through the
18435184Sek110237 * threadflow's file descriptor array, doing fsync() on each
18445184Sek110237 * open file that belongs to the flowop's fileset. Always
18456084Saw148015 * returns FILEBENCH_OK.
18465184Sek110237 */
18475184Sek110237 static int
18485184Sek110237 flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop)
18495184Sek110237 {
18505184Sek110237 int fd;
18515184Sek110237
18525184Sek110237 for (fd = 0; fd < THREADFLOW_MAXFD; fd++) {
18535184Sek110237 filesetentry_t *file;
18545184Sek110237
18555184Sek110237 /* Match the file set to fsync */
18565184Sek110237 if ((threadflow->tf_fse[fd] == NULL) ||
18575184Sek110237 (flowop->fo_fileset != threadflow->tf_fse[fd]->fse_fileset))
18585184Sek110237 continue;
18595184Sek110237
18605184Sek110237 /* Measure time to fsync */
18615184Sek110237 flowop_beginop(threadflow, flowop);
18628615SAndrew.W.Wilson@sun.com (void) FB_FSYNC(&threadflow->tf_fd[fd]);
18635673Saw148015 flowop_endop(threadflow, flowop, 0);
18645184Sek110237
18655184Sek110237 file = threadflow->tf_fse[fd];
18665184Sek110237
18675184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "fsync file %s",
18685184Sek110237 file->fse_path);
18695184Sek110237 }
18705184Sek110237
18716084Saw148015 return (FILEBENCH_OK);
18725184Sek110237 }
18735184Sek110237
18745184Sek110237 /*
18755184Sek110237 * Emulate close of a file. Obtains the file descriptor index
18765184Sek110237 * from the flowop, obtains the actual file descriptor from the
18775184Sek110237 * threadflow's table, checks to be sure it is still an open
18785184Sek110237 * file, then does a close operation on it. Then sets the
18795184Sek110237 * threadflow file descriptor table entry to 0, and the file set
18806084Saw148015 * entry pointer to NULL. Returns FILEBENCH_ERROR if the file was not open,
18816084Saw148015 * FILEBENCH_OK otherwise.
18825184Sek110237 */
18835184Sek110237 static int
18845184Sek110237 flowoplib_closefile(threadflow_t *threadflow, flowop_t *flowop)
18855184Sek110237 {
18865184Sek110237 filesetentry_t *file;
18878404SAndrew.W.Wilson@sun.com fileset_t *fileset;
18885184Sek110237 int fd = flowop->fo_fdnumber;
18895184Sek110237
18908615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr == NULL) {
18915184Sek110237 filebench_log(LOG_ERROR,
18925184Sek110237 "flowop %s attempted to close an already closed fd %d",
18935184Sek110237 flowop->fo_name, fd);
18946084Saw148015 return (FILEBENCH_ERROR);
18955184Sek110237 }
18965184Sek110237
18978404SAndrew.W.Wilson@sun.com file = threadflow->tf_fse[fd];
18988404SAndrew.W.Wilson@sun.com fileset = file->fse_fileset;
18998404SAndrew.W.Wilson@sun.com
19008404SAndrew.W.Wilson@sun.com /* Wait for it to be non-busy */
19018404SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
19028404SAndrew.W.Wilson@sun.com while (file->fse_flags & FSE_BUSY) {
19038404SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_THRD_WAITNG;
19048404SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_thrd_wait_cv,
19058404SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock);
19068404SAndrew.W.Wilson@sun.com }
19078404SAndrew.W.Wilson@sun.com
19088404SAndrew.W.Wilson@sun.com /* File now available, grab it for closing */
19098404SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_BUSY;
19108404SAndrew.W.Wilson@sun.com
19118404SAndrew.W.Wilson@sun.com /* if last open, set declare idle */
19128404SAndrew.W.Wilson@sun.com if (file->fse_open_cnt == 1)
19138404SAndrew.W.Wilson@sun.com fileset->fs_idle_files--;
19148404SAndrew.W.Wilson@sun.com
19158404SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
19168404SAndrew.W.Wilson@sun.com
19175184Sek110237 /* Measure time to close */
19185184Sek110237 flowop_beginop(threadflow, flowop);
19198615SAndrew.W.Wilson@sun.com (void) FB_CLOSE(&threadflow->tf_fd[fd]);
19205673Saw148015 flowop_endop(threadflow, flowop, 0);
19215184Sek110237
19228404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, -1);
19235184Sek110237
19248615SAndrew.W.Wilson@sun.com threadflow->tf_fd[fd].fd_ptr = NULL;
19255184Sek110237
19265184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "closed file %s", file->fse_path);
19275184Sek110237
19286084Saw148015 return (FILEBENCH_OK);
19295184Sek110237 }
19305184Sek110237
19315184Sek110237 /*
19327946SAndrew.W.Wilson@sun.com * Obtain the full pathname of the directory described by the filesetentry
19337946SAndrew.W.Wilson@sun.com * indicated by "dir", and copy it into the character array pointed to by
19347946SAndrew.W.Wilson@sun.com * path. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
19357946SAndrew.W.Wilson@sun.com */
19367946SAndrew.W.Wilson@sun.com static int
19377946SAndrew.W.Wilson@sun.com flowoplib_getdirpath(filesetentry_t *dir, char *path)
19387946SAndrew.W.Wilson@sun.com {
19397946SAndrew.W.Wilson@sun.com char *fileset_path;
19407946SAndrew.W.Wilson@sun.com char *fileset_name;
19417946SAndrew.W.Wilson@sun.com char *part_path;
19427946SAndrew.W.Wilson@sun.com
19437946SAndrew.W.Wilson@sun.com if ((fileset_path = avd_get_str(dir->fse_fileset->fs_path)) == NULL) {
19447946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Fileset path not set");
19457946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
19467946SAndrew.W.Wilson@sun.com }
19477946SAndrew.W.Wilson@sun.com
19487946SAndrew.W.Wilson@sun.com if ((fileset_name = avd_get_str(dir->fse_fileset->fs_name)) == NULL) {
19497946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Fileset name not set");
19507946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
19517946SAndrew.W.Wilson@sun.com }
19527946SAndrew.W.Wilson@sun.com
19537946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
19547946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
19557946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, fileset_name, MAXPATHLEN);
19567946SAndrew.W.Wilson@sun.com
19577946SAndrew.W.Wilson@sun.com if ((part_path = fileset_resolvepath(dir)) == NULL)
19587946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
19597946SAndrew.W.Wilson@sun.com
19607946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, part_path, MAXPATHLEN);
19617946SAndrew.W.Wilson@sun.com free(part_path);
19627946SAndrew.W.Wilson@sun.com
19637946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
19647946SAndrew.W.Wilson@sun.com }
19657946SAndrew.W.Wilson@sun.com
19667946SAndrew.W.Wilson@sun.com /*
19677946SAndrew.W.Wilson@sun.com * Use mkdir to create a directory. Obtains the fileset name from the
19687946SAndrew.W.Wilson@sun.com * flowop, selects a non-existent leaf directory and obtains its full
19697946SAndrew.W.Wilson@sun.com * path, then uses mkdir to create it on the storage subsystem (make it
19707946SAndrew.W.Wilson@sun.com * existent). Returns FILEBENCH_NORSC is there are no more non-existent
19717946SAndrew.W.Wilson@sun.com * directories in the fileset, FILEBENCH_ERROR on other errors, and
19727946SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success.
19737946SAndrew.W.Wilson@sun.com */
19747946SAndrew.W.Wilson@sun.com static int
19757946SAndrew.W.Wilson@sun.com flowoplib_makedir(threadflow_t *threadflow, flowop_t *flowop)
19767946SAndrew.W.Wilson@sun.com {
19777946SAndrew.W.Wilson@sun.com filesetentry_t *dir;
19787946SAndrew.W.Wilson@sun.com int ret;
19797946SAndrew.W.Wilson@sun.com char full_path[MAXPATHLEN];
19807946SAndrew.W.Wilson@sun.com
19817946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_pickleafdir(&dir, flowop,
19827946SAndrew.W.Wilson@sun.com FILESET_PICKNOEXIST)) != FILEBENCH_OK)
19837946SAndrew.W.Wilson@sun.com return (ret);
19847946SAndrew.W.Wilson@sun.com
19857946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
19867946SAndrew.W.Wilson@sun.com return (ret);
19877946SAndrew.W.Wilson@sun.com
19887946SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop);
19898615SAndrew.W.Wilson@sun.com (void) FB_MKDIR(full_path, 0755);
19907946SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0);
19917946SAndrew.W.Wilson@sun.com
19927946SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy and now exists */
19938404SAndrew.W.Wilson@sun.com fileset_unbusy(dir, TRUE, TRUE, 0);
19947946SAndrew.W.Wilson@sun.com
19957946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
19967946SAndrew.W.Wilson@sun.com }
19977946SAndrew.W.Wilson@sun.com
19987946SAndrew.W.Wilson@sun.com /*
19997946SAndrew.W.Wilson@sun.com * Use rmdir to delete a directory. Obtains the fileset name from the
20007946SAndrew.W.Wilson@sun.com * flowop, selects an existent leaf directory and obtains its full path,
20017946SAndrew.W.Wilson@sun.com * then uses rmdir to remove it from the storage subsystem (make it
20027946SAndrew.W.Wilson@sun.com * non-existent). Returns FILEBENCH_NORSC is there are no more existent
20037946SAndrew.W.Wilson@sun.com * directories in the fileset, FILEBENCH_ERROR on other errors, and
20047946SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success.
20057946SAndrew.W.Wilson@sun.com */
20067946SAndrew.W.Wilson@sun.com static int
20077946SAndrew.W.Wilson@sun.com flowoplib_removedir(threadflow_t *threadflow, flowop_t *flowop)
20087946SAndrew.W.Wilson@sun.com {
20097946SAndrew.W.Wilson@sun.com filesetentry_t *dir;
20107946SAndrew.W.Wilson@sun.com int ret;
20117946SAndrew.W.Wilson@sun.com char full_path[MAXPATHLEN];
20127946SAndrew.W.Wilson@sun.com
20137946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_pickleafdir(&dir, flowop,
20147946SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS)) != FILEBENCH_OK)
20157946SAndrew.W.Wilson@sun.com return (ret);
20167946SAndrew.W.Wilson@sun.com
20177946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
20187946SAndrew.W.Wilson@sun.com return (ret);
20197946SAndrew.W.Wilson@sun.com
20207946SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop);
20218615SAndrew.W.Wilson@sun.com (void) FB_RMDIR(full_path);
20227946SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0);
20237946SAndrew.W.Wilson@sun.com
20247946SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy and no longer exists */
20258404SAndrew.W.Wilson@sun.com fileset_unbusy(dir, TRUE, FALSE, 0);
20267946SAndrew.W.Wilson@sun.com
20277946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
20287946SAndrew.W.Wilson@sun.com }
20297946SAndrew.W.Wilson@sun.com
20307946SAndrew.W.Wilson@sun.com /*
20317946SAndrew.W.Wilson@sun.com * Use opendir(), multiple readdir() calls, and closedir() to list the
20327946SAndrew.W.Wilson@sun.com * contents of a directory. Obtains the fileset name from the
20337946SAndrew.W.Wilson@sun.com * flowop, selects a normal subdirectory (which always exist) and obtains
20347946SAndrew.W.Wilson@sun.com * its full path, then uses opendir() to get a DIR handle to it from the
20357946SAndrew.W.Wilson@sun.com * file system, a readdir() loop to access each directory entry, and
20367946SAndrew.W.Wilson@sun.com * finally cleans up with a closedir(). The latency reported is the total
20377946SAndrew.W.Wilson@sun.com * for all this activity, and it also reports the total number of bytes
20387946SAndrew.W.Wilson@sun.com * in the entries as the amount "read". Returns FILEBENCH_ERROR on errors,
20397946SAndrew.W.Wilson@sun.com * and FILEBENCH_OK on success.
20407946SAndrew.W.Wilson@sun.com */
20417946SAndrew.W.Wilson@sun.com static int
20427946SAndrew.W.Wilson@sun.com flowoplib_listdir(threadflow_t *threadflow, flowop_t *flowop)
20437946SAndrew.W.Wilson@sun.com {
20447946SAndrew.W.Wilson@sun.com fileset_t *fileset;
20457946SAndrew.W.Wilson@sun.com filesetentry_t *dir;
20468615SAndrew.W.Wilson@sun.com DIR *dir_handle;
20477946SAndrew.W.Wilson@sun.com struct dirent *direntp;
20487946SAndrew.W.Wilson@sun.com int dir_bytes = 0;
20497946SAndrew.W.Wilson@sun.com int ret;
20507946SAndrew.W.Wilson@sun.com char full_path[MAXPATHLEN];
20517946SAndrew.W.Wilson@sun.com
20527946SAndrew.W.Wilson@sun.com if ((fileset = flowop->fo_fileset) == NULL) {
20537946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "flowop NO fileset");
20547946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
20557946SAndrew.W.Wilson@sun.com }
20567946SAndrew.W.Wilson@sun.com
20578404SAndrew.W.Wilson@sun.com if ((dir = fileset_pick(fileset, FILESET_PICKDIR, 0, 0)) == NULL) {
20587946SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
20597946SAndrew.W.Wilson@sun.com "flowop %s failed to pick directory from fileset %s",
20607946SAndrew.W.Wilson@sun.com flowop->fo_name,
20617946SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name));
20628404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
20637946SAndrew.W.Wilson@sun.com }
20647946SAndrew.W.Wilson@sun.com
20657946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
20667946SAndrew.W.Wilson@sun.com return (ret);
20677946SAndrew.W.Wilson@sun.com
20687946SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop);
20697946SAndrew.W.Wilson@sun.com
20707946SAndrew.W.Wilson@sun.com /* open the directory */
20718615SAndrew.W.Wilson@sun.com if ((dir_handle = FB_OPENDIR(full_path)) == NULL) {
20727946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
20737946SAndrew.W.Wilson@sun.com "flowop %s failed to open directory in fileset %s\n",
20747946SAndrew.W.Wilson@sun.com flowop->fo_name, avd_get_str(fileset->fs_name));
20757946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
20767946SAndrew.W.Wilson@sun.com }
20777946SAndrew.W.Wilson@sun.com
20787946SAndrew.W.Wilson@sun.com /* read through the directory entries */
20798615SAndrew.W.Wilson@sun.com while ((direntp = FB_READDIR(dir_handle)) != NULL) {
20807946SAndrew.W.Wilson@sun.com dir_bytes += (strlen(direntp->d_name) +
20817946SAndrew.W.Wilson@sun.com sizeof (struct dirent) - 1);
20827946SAndrew.W.Wilson@sun.com }
20837946SAndrew.W.Wilson@sun.com
20847946SAndrew.W.Wilson@sun.com /* close the directory */
20858615SAndrew.W.Wilson@sun.com (void) FB_CLOSEDIR(dir_handle);
20867946SAndrew.W.Wilson@sun.com
20877946SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, dir_bytes);
20887946SAndrew.W.Wilson@sun.com
20897946SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy */
20908404SAndrew.W.Wilson@sun.com fileset_unbusy(dir, FALSE, FALSE, 0);
20917946SAndrew.W.Wilson@sun.com
20927946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
20937946SAndrew.W.Wilson@sun.com }
20947946SAndrew.W.Wilson@sun.com
20957946SAndrew.W.Wilson@sun.com /*
20965184Sek110237 * Emulate stat of a file. Picks an arbitrary filesetentry with
20975184Sek110237 * an existing file from the flowop's fileset, then performs a
20986084Saw148015 * stat() operation on it. Returns FILEBENCH_ERROR if the flowop has no
20996084Saw148015 * associated fileset. Returns FILEBENCH_NORSC if an appropriate filesetentry
21006084Saw148015 * cannot be found, and FILEBENCH_OK on success.
21015184Sek110237 */
21025184Sek110237 static int
21035184Sek110237 flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop)
21045184Sek110237 {
21055184Sek110237 filesetentry_t *file;
21065184Sek110237 fileset_t *fileset;
21078615SAndrew.W.Wilson@sun.com struct stat64 statbuf;
21087556SAndrew.W.Wilson@sun.com int fd = flowop->fo_fdnumber;
21097556SAndrew.W.Wilson@sun.com
21107556SAndrew.W.Wilson@sun.com /* if fd specified and the file is open, use it to access file */
21118615SAndrew.W.Wilson@sun.com if ((fd > 0) && (threadflow->tf_fd[fd].fd_num > 0)) {
21127556SAndrew.W.Wilson@sun.com
21137556SAndrew.W.Wilson@sun.com /* check whether file handle still valid */
21147556SAndrew.W.Wilson@sun.com if ((file = threadflow->tf_fse[fd]) == NULL) {
21157556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
21167556SAndrew.W.Wilson@sun.com "flowop %s trying to stat NULL file at fd = %d",
21177556SAndrew.W.Wilson@sun.com flowop->fo_name, fd);
21187556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
21197556SAndrew.W.Wilson@sun.com }
21207556SAndrew.W.Wilson@sun.com
21217556SAndrew.W.Wilson@sun.com /* if here, we still have a valid file pointer */
21227556SAndrew.W.Wilson@sun.com fileset = file->fse_fileset;
21237556SAndrew.W.Wilson@sun.com } else {
21247556SAndrew.W.Wilson@sun.com /* Otherwise, pick arbitrary file */
21257556SAndrew.W.Wilson@sun.com file = NULL;
21267556SAndrew.W.Wilson@sun.com fileset = flowop->fo_fileset;
21277556SAndrew.W.Wilson@sun.com }
21287556SAndrew.W.Wilson@sun.com
21297556SAndrew.W.Wilson@sun.com if (fileset == NULL) {
21307556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
21317556SAndrew.W.Wilson@sun.com "statfile with no fileset specified");
21327556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
21337556SAndrew.W.Wilson@sun.com }
21347556SAndrew.W.Wilson@sun.com
21357556SAndrew.W.Wilson@sun.com #ifdef HAVE_RAW_SUPPORT
21367556SAndrew.W.Wilson@sun.com /* can't be used with raw devices */
21377556SAndrew.W.Wilson@sun.com if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
21387556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
21397556SAndrew.W.Wilson@sun.com "flowop %s attempted do a statfile on a RAW device",
21407556SAndrew.W.Wilson@sun.com flowop->fo_name);
21416084Saw148015 return (FILEBENCH_ERROR);
21425184Sek110237 }
21437556SAndrew.W.Wilson@sun.com #endif /* HAVE_RAW_SUPPORT */
21447556SAndrew.W.Wilson@sun.com
21457556SAndrew.W.Wilson@sun.com if (file == NULL) {
21467556SAndrew.W.Wilson@sun.com char path[MAXPATHLEN];
21477556SAndrew.W.Wilson@sun.com char *pathtmp;
21488404SAndrew.W.Wilson@sun.com int err;
21497556SAndrew.W.Wilson@sun.com
21507556SAndrew.W.Wilson@sun.com /* pick arbitrary, existing (allocated) file */
21518404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop,
21528404SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS, 0)) != FILEBENCH_OK) {
21537556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
21547556SAndrew.W.Wilson@sun.com "Statfile flowop %s failed to pick file",
21557556SAndrew.W.Wilson@sun.com flowop->fo_name);
21568404SAndrew.W.Wilson@sun.com return (err);
21577556SAndrew.W.Wilson@sun.com }
21587556SAndrew.W.Wilson@sun.com
21597556SAndrew.W.Wilson@sun.com /* resolve path and do a stat on file */
21607946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path),
21617946SAndrew.W.Wilson@sun.com MAXPATHLEN);
21627946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
21637946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name),
21647946SAndrew.W.Wilson@sun.com MAXPATHLEN);
21657556SAndrew.W.Wilson@sun.com pathtmp = fileset_resolvepath(file);
21667946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
21677556SAndrew.W.Wilson@sun.com free(pathtmp);
21687556SAndrew.W.Wilson@sun.com
21697556SAndrew.W.Wilson@sun.com /* stat the file */
21707556SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop);
21718615SAndrew.W.Wilson@sun.com if (FB_STAT(path, &statbuf) == -1)
21727556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
21737556SAndrew.W.Wilson@sun.com "statfile flowop %s failed", flowop->fo_name);
21747556SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0);
21757556SAndrew.W.Wilson@sun.com
21768404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, 0);
21777556SAndrew.W.Wilson@sun.com } else {
21787556SAndrew.W.Wilson@sun.com /* stat specific file */
21797556SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop);
21808615SAndrew.W.Wilson@sun.com if (FB_FSTAT(&threadflow->tf_fd[fd], &statbuf) == -1)
21817556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
21827556SAndrew.W.Wilson@sun.com "statfile flowop %s failed", flowop->fo_name);
21837556SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0);
21847556SAndrew.W.Wilson@sun.com
21855184Sek110237 }
21865184Sek110237
21876084Saw148015 return (FILEBENCH_OK);
21885184Sek110237 }
21895184Sek110237
21905184Sek110237
21915184Sek110237 /*
21925184Sek110237 * Additional reads and writes. Read and write whole files, write
21935184Sek110237 * and append to files. Some of these work with both fileobjs and
21945184Sek110237 * filesets, others only with filesets. The flowoplib_write routine
21955184Sek110237 * writes from thread memory, while the others read or write using
21965184Sek110237 * fo_buf memory. Note that both flowoplib_read() and
21975184Sek110237 * flowoplib_aiowrite() use thread memory as well.
21985184Sek110237 */
21995184Sek110237
22005184Sek110237
22015184Sek110237 /*
22025673Saw148015 * Emulate a read of a whole file. The file must be open with
22035673Saw148015 * file descriptor and filesetentry stored at the locations indexed
22045673Saw148015 * by the flowop's fdnumber. It then seeks to the beginning of the
22055673Saw148015 * associated file, and reads fs_iosize bytes at a time until the end
22066084Saw148015 * of the file. Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if
22076084Saw148015 * out of files, and FILEBENCH_OK on success.
22085184Sek110237 */
22095184Sek110237 static int
22105184Sek110237 flowoplib_readwholefile(threadflow_t *threadflow, flowop_t *flowop)
22115184Sek110237 {
22125673Saw148015 caddr_t iobuf;
22135184Sek110237 off64_t bytes = 0;
22148615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc;
22156212Saw148015 uint64_t wss;
22166212Saw148015 fbint_t iosize;
22175184Sek110237 int ret;
22186212Saw148015 char zerordbuf;
22195184Sek110237
22205673Saw148015 /* get the file to use */
22216084Saw148015 if ((ret = flowoplib_filesetup(threadflow, flowop, &wss,
22228615SAndrew.W.Wilson@sun.com &fdesc)) != FILEBENCH_OK)
22236084Saw148015 return (ret);
22245184Sek110237
22255673Saw148015 /* an I/O size of zero means read entire working set with one I/O */
22266212Saw148015 if ((iosize = avd_get_int(flowop->fo_iosize)) == 0)
22275673Saw148015 iosize = wss;
22285184Sek110237
22296212Saw148015 /*
22306212Saw148015 * The file may actually be 0 bytes long, in which case skip
22316212Saw148015 * the buffer set up call (which would fail) and substitute
22326212Saw148015 * a small buffer, which won't really be used.
22336212Saw148015 */
22346212Saw148015 if (iosize == 0) {
22356212Saw148015 iobuf = (caddr_t)&zerordbuf;
22366212Saw148015 filebench_log(LOG_DEBUG_SCRIPT,
22376212Saw148015 "flowop %s read zero length file", flowop->fo_name);
22386212Saw148015 } else {
22396212Saw148015 if (flowoplib_iobufsetup(threadflow, flowop, &iobuf,
22406212Saw148015 iosize) != 0)
22416212Saw148015 return (FILEBENCH_ERROR);
22426212Saw148015 }
22435184Sek110237
22445184Sek110237 /* Measure time to read bytes */
22455184Sek110237 flowop_beginop(threadflow, flowop);
22468615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_SET);
22478615SAndrew.W.Wilson@sun.com while ((ret = FB_READ(fdesc, iobuf, iosize)) > 0)
22485184Sek110237 bytes += ret;
22495184Sek110237
22505673Saw148015 flowop_endop(threadflow, flowop, bytes);
22515184Sek110237
22525184Sek110237 if (ret < 0) {
22535184Sek110237 filebench_log(LOG_ERROR,
22546391Saw148015 "readwhole fail Failed to read whole file: %s",
22556391Saw148015 strerror(errno));
22566084Saw148015 return (FILEBENCH_ERROR);
22575184Sek110237 }
22585184Sek110237
22596084Saw148015 return (FILEBENCH_OK);
22605184Sek110237 }
22615184Sek110237
22625184Sek110237 /*
22635184Sek110237 * Emulate a write to a file of size fo_iosize. Will write
22645184Sek110237 * to a file from a fileset if the flowop's fo_fileset field
22655184Sek110237 * specifies one or its fdnumber is non zero. Otherwise it
22665184Sek110237 * will write to a fileobj file, if one exists. If the file
22675184Sek110237 * is not currently open, the routine will attempt to open
22685184Sek110237 * it. The flowop's fo_wss parameter will be used to set the
22695184Sek110237 * maximum file size if it is non-zero, otherwise the
22705184Sek110237 * filesetentry's fse_size will be used. A random memory
22715184Sek110237 * buffer offset is calculated, and, if fo_random is TRUE,
22725184Sek110237 * a random file offset is used for the write. Otherwise the
22736084Saw148015 * write is to the next sequential location. Returns
22746084Saw148015 * FILEBENCH_ERROR on errors, FILEBENCH_NORSC if iosetup can't
22756084Saw148015 * obtain a file, or FILEBENCH_OK on success.
22765184Sek110237 */
22775184Sek110237 static int
22785184Sek110237 flowoplib_write(threadflow_t *threadflow, flowop_t *flowop)
22795184Sek110237 {
22805673Saw148015 caddr_t iobuf;
22816212Saw148015 fbint_t wss;
22826212Saw148015 fbint_t iosize;
22838615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc;
22846084Saw148015 int ret;
22855184Sek110237
22866212Saw148015 iosize = avd_get_int(flowop->fo_iosize);
22876084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
22888615SAndrew.W.Wilson@sun.com &fdesc, iosize)) != FILEBENCH_OK)
22896084Saw148015 return (ret);
22905184Sek110237
22916212Saw148015 if (avd_get_bool(flowop->fo_random)) {
22925184Sek110237 uint64_t fileoffset;
22935184Sek110237
22945184Sek110237 if (filebench_randomno64(&fileoffset,
22956212Saw148015 wss, iosize, NULL) == -1) {
22965184Sek110237 filebench_log(LOG_ERROR,
22975184Sek110237 "file size smaller than IO size for thread %s",
22985184Sek110237 flowop->fo_name);
22996084Saw148015 return (FILEBENCH_ERROR);
23005184Sek110237 }
23015184Sek110237 flowop_beginop(threadflow, flowop);
23028615SAndrew.W.Wilson@sun.com if (FB_PWRITE(fdesc, iobuf,
23036212Saw148015 iosize, (off64_t)fileoffset) == -1) {
23045184Sek110237 filebench_log(LOG_ERROR, "write failed, "
23056286Saw148015 "offset %llu io buffer %zd: %s",
23066286Saw148015 (u_longlong_t)fileoffset, iobuf, strerror(errno));
23075673Saw148015 flowop_endop(threadflow, flowop, 0);
23086084Saw148015 return (FILEBENCH_ERROR);
23095184Sek110237 }
23106212Saw148015 flowop_endop(threadflow, flowop, iosize);
23115184Sek110237 } else {
23125184Sek110237 flowop_beginop(threadflow, flowop);
23138615SAndrew.W.Wilson@sun.com if (FB_WRITE(fdesc, iobuf, iosize) == -1) {
23145184Sek110237 filebench_log(LOG_ERROR,
23155673Saw148015 "write failed, io buffer %zd: %s",
23165673Saw148015 iobuf, strerror(errno));
23175673Saw148015 flowop_endop(threadflow, flowop, 0);
23186084Saw148015 return (FILEBENCH_ERROR);
23195184Sek110237 }
23206212Saw148015 flowop_endop(threadflow, flowop, iosize);
23215184Sek110237 }
23225184Sek110237
23236084Saw148015 return (FILEBENCH_OK);
23245184Sek110237 }
23255184Sek110237
23265184Sek110237 /*
23275184Sek110237 * Emulate a write of a whole file. The size of the file
23285673Saw148015 * is taken from a filesetentry identified by fo_srcfdnumber or
23295673Saw148015 * from the working set size, while the file descriptor used is
23305673Saw148015 * identified by fo_fdnumber. Does multiple writes of fo_iosize
23316084Saw148015 * length length until full file has been written. Returns FILEBENCH_ERROR on
23326084Saw148015 * error, FILEBENCH_NORSC if out of files, FILEBENCH_OK on success.
23335184Sek110237 */
23345184Sek110237 static int
23355184Sek110237 flowoplib_writewholefile(threadflow_t *threadflow, flowop_t *flowop)
23365184Sek110237 {
23375673Saw148015 caddr_t iobuf;
23385184Sek110237 filesetentry_t *file;
23395184Sek110237 int wsize;
23405184Sek110237 off64_t seek;
23415184Sek110237 off64_t bytes = 0;
23425673Saw148015 uint64_t wss;
23436212Saw148015 fbint_t iosize;
23448615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc;
23455184Sek110237 int srcfd = flowop->fo_srcfdnumber;
23465184Sek110237 int ret;
23476212Saw148015 char zerowrtbuf;
23485184Sek110237
23495673Saw148015 /* get the file to use */
23506084Saw148015 if ((ret = flowoplib_filesetup(threadflow, flowop, &wss,
23518615SAndrew.W.Wilson@sun.com &fdesc)) != FILEBENCH_OK)
23526084Saw148015 return (ret);
23535184Sek110237
23546212Saw148015 /* an I/O size of zero means write entire working set with one I/O */
23556212Saw148015 if ((iosize = avd_get_int(flowop->fo_iosize)) == 0)
23565673Saw148015 iosize = wss;
23575184Sek110237
23586212Saw148015 /*
23596212Saw148015 * The file may actually be 0 bytes long, in which case skip
23606212Saw148015 * the buffer set up call (which would fail) and substitute
23616212Saw148015 * a small buffer, which won't really be used.
23626212Saw148015 */
23636212Saw148015 if (iosize == 0) {
23646212Saw148015 iobuf = (caddr_t)&zerowrtbuf;
23656212Saw148015 filebench_log(LOG_DEBUG_SCRIPT,
23666212Saw148015 "flowop %s wrote zero length file", flowop->fo_name);
23676212Saw148015 } else {
23686212Saw148015 if (flowoplib_iobufsetup(threadflow, flowop, &iobuf,
23696212Saw148015 iosize) != 0)
23706212Saw148015 return (FILEBENCH_ERROR);
23716212Saw148015 }
23725184Sek110237
23735184Sek110237 file = threadflow->tf_fse[srcfd];
23745673Saw148015 if ((srcfd != 0) && (file == NULL)) {
23755673Saw148015 filebench_log(LOG_ERROR, "flowop %s: NULL src file",
23765184Sek110237 flowop->fo_name);
23776084Saw148015 return (FILEBENCH_ERROR);
23785184Sek110237 }
23795184Sek110237
23805673Saw148015 if (file)
23815673Saw148015 wss = file->fse_size;
23825673Saw148015
23835673Saw148015 wsize = (int)MIN(wss, iosize);
23845184Sek110237
23855184Sek110237 /* Measure time to write bytes */
23865184Sek110237 flowop_beginop(threadflow, flowop);
23875673Saw148015 for (seek = 0; seek < wss; seek += wsize) {
23888615SAndrew.W.Wilson@sun.com ret = FB_WRITE(fdesc, iobuf, wsize);
23895184Sek110237 if (ret != wsize) {
23905184Sek110237 filebench_log(LOG_ERROR,
23915184Sek110237 "Failed to write %d bytes on fd %d: %s",
23928615SAndrew.W.Wilson@sun.com wsize, fdesc->fd_num, strerror(errno));
23935673Saw148015 flowop_endop(threadflow, flowop, 0);
23946084Saw148015 return (FILEBENCH_ERROR);
23955184Sek110237 }
23965673Saw148015 wsize = (int)MIN(wss - seek, iosize);
23975184Sek110237 bytes += ret;
23985184Sek110237 }
23995673Saw148015 flowop_endop(threadflow, flowop, bytes);
24005184Sek110237
24016084Saw148015 return (FILEBENCH_OK);
24025184Sek110237 }
24035184Sek110237
24045184Sek110237
24055184Sek110237 /*
24065184Sek110237 * Emulate a fixed size append to a file. Will append data to
24075184Sek110237 * a file chosen from a fileset if the flowop's fo_fileset
24085184Sek110237 * field specifies one or if its fdnumber is non zero.
24095184Sek110237 * Otherwise it will write to a fileobj file, if one exists.
24105184Sek110237 * The flowop's fo_wss parameter will be used to set the
24115184Sek110237 * maximum file size if it is non-zero, otherwise the
24125184Sek110237 * filesetentry's fse_size will be used. A random memory
24135184Sek110237 * buffer offset is calculated, then a logical seek to the
24145184Sek110237 * end of file is done followed by a write of fo_iosize
24155184Sek110237 * bytes. Writes are actually done from fo_buf, rather than
24165184Sek110237 * tf_mem as is done with flowoplib_write(), and no check
24175184Sek110237 * is made to see if fo_iosize exceeds the size of fo_buf.
24186084Saw148015 * Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if out of
24196084Saw148015 * files in the fileset, FILEBENCH_OK on success.
24205184Sek110237 */
24215184Sek110237 static int
24225184Sek110237 flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop)
24235184Sek110237 {
24245673Saw148015 caddr_t iobuf;
24258615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc;
24266212Saw148015 fbint_t wss;
24276212Saw148015 fbint_t iosize;
24285184Sek110237 int ret;
24295184Sek110237
24306212Saw148015 iosize = avd_get_int(flowop->fo_iosize);
24316084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
24328615SAndrew.W.Wilson@sun.com &fdesc, iosize)) != FILEBENCH_OK)
24336084Saw148015 return (ret);
24345184Sek110237
24355184Sek110237 /* XXX wss is not being used */
24365184Sek110237
24375184Sek110237 /* Measure time to write bytes */
24385184Sek110237 flowop_beginop(threadflow, flowop);
24398615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_END);
24408615SAndrew.W.Wilson@sun.com ret = FB_WRITE(fdesc, iobuf, iosize);
24415673Saw148015 if (ret != iosize) {
24425184Sek110237 filebench_log(LOG_ERROR,
24436286Saw148015 "Failed to write %llu bytes on fd %d: %s",
24448615SAndrew.W.Wilson@sun.com (u_longlong_t)iosize, fdesc->fd_num, strerror(errno));
24456212Saw148015 flowop_endop(threadflow, flowop, ret);
24466084Saw148015 return (FILEBENCH_ERROR);
24475184Sek110237 }
24486212Saw148015 flowop_endop(threadflow, flowop, ret);
24495184Sek110237
24506084Saw148015 return (FILEBENCH_OK);
24515184Sek110237 }
24525184Sek110237
24535184Sek110237 /*
24545184Sek110237 * Emulate a random size append to a file. Will append data
24555184Sek110237 * to a file chosen from a fileset if the flowop's fo_fileset
24565184Sek110237 * field specifies one or if its fdnumber is non zero. Otherwise
24575184Sek110237 * it will write to a fileobj file, if one exists. The flowop's
24585184Sek110237 * fo_wss parameter will be used to set the maximum file size
24595184Sek110237 * if it is non-zero, otherwise the filesetentry's fse_size
24605184Sek110237 * will be used. A random transfer size (but at most fo_iosize
24615184Sek110237 * bytes) and a random memory offset are calculated. A logical
24625184Sek110237 * seek to the end of file is done, then writes of up to
24635184Sek110237 * FILE_ALLOC_BLOCK in size are done until the full transfer
24645184Sek110237 * size has been written. Writes are actually done from fo_buf,
24655184Sek110237 * rather than tf_mem as is done with flowoplib_write().
24666084Saw148015 * Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if out of
24676084Saw148015 * files in the fileset, FILEBENCH_OK on success.
24685184Sek110237 */
24695184Sek110237 static int
24705184Sek110237 flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop)
24715184Sek110237 {
24725673Saw148015 caddr_t iobuf;
24735184Sek110237 uint64_t appendsize;
24748615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc;
24756212Saw148015 fbint_t wss;
24766212Saw148015 fbint_t iosize;
24776212Saw148015 int ret = 0;
24785184Sek110237
24796212Saw148015 if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) {
24806212Saw148015 filebench_log(LOG_ERROR, "zero iosize for flowop %s",
24816212Saw148015 flowop->fo_name);
24826212Saw148015 return (FILEBENCH_ERROR);
24836212Saw148015 }
24846212Saw148015
24856212Saw148015 if (filebench_randomno64(&appendsize, iosize, 1LL, NULL) != 0)
24866084Saw148015 return (FILEBENCH_ERROR);
24875184Sek110237
24885673Saw148015 /* skip if attempting zero length append */
24895673Saw148015 if (appendsize == 0) {
24905673Saw148015 flowop_beginop(threadflow, flowop);
24915673Saw148015 flowop_endop(threadflow, flowop, 0LL);
24926084Saw148015 return (FILEBENCH_OK);
24935673Saw148015 }
24945184Sek110237
24956084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf,
24968615SAndrew.W.Wilson@sun.com &fdesc, appendsize)) != FILEBENCH_OK)
24976084Saw148015 return (ret);
24985673Saw148015
24995184Sek110237 /* XXX wss is not being used */
25005184Sek110237
25015673Saw148015 /* Measure time to write bytes */
25025673Saw148015 flowop_beginop(threadflow, flowop);
25035673Saw148015
25048615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_END);
25058615SAndrew.W.Wilson@sun.com ret = FB_WRITE(fdesc, iobuf, appendsize);
25065673Saw148015 if (ret != appendsize) {
25075673Saw148015 filebench_log(LOG_ERROR,
25086286Saw148015 "Failed to write %llu bytes on fd %d: %s",
25098615SAndrew.W.Wilson@sun.com (u_longlong_t)appendsize, fdesc->fd_num, strerror(errno));
25105673Saw148015 flowop_endop(threadflow, flowop, 0);
25116084Saw148015 return (FILEBENCH_ERROR);
25125184Sek110237 }
25135184Sek110237
25145673Saw148015 flowop_endop(threadflow, flowop, appendsize);
25155184Sek110237
25166084Saw148015 return (FILEBENCH_OK);
25175184Sek110237 }
25185184Sek110237
25196212Saw148015 typedef struct testrandvar_priv {
25206212Saw148015 uint64_t sample_count;
25216212Saw148015 double val_sum;
25226212Saw148015 double sqr_sum;
25236212Saw148015 } testrandvar_priv_t;
25246212Saw148015
25256212Saw148015 /*
25266212Saw148015 * flowop to calculate various statistics from the number stream
25276212Saw148015 * produced by a random variable. This allows verification that the
25286212Saw148015 * random distribution used to define the random variable is producing
25296212Saw148015 * the expected distribution of random numbers.
25306212Saw148015 */
25316212Saw148015 /* ARGSUSED */
25326212Saw148015 static int
25336212Saw148015 flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop)
25346212Saw148015 {
25356212Saw148015 testrandvar_priv_t *mystats;
25366212Saw148015 double value;
25376212Saw148015
25386212Saw148015 if ((mystats = (testrandvar_priv_t *)flowop->fo_private) == NULL) {
25396212Saw148015 filebench_log(LOG_ERROR, "testrandvar not initialized\n");
25406212Saw148015 filebench_shutdown(1);
25416212Saw148015 return (-1);
25426212Saw148015 }
25436212Saw148015
25446212Saw148015 value = avd_get_dbl(flowop->fo_value);
25456212Saw148015
25466212Saw148015 mystats->sample_count++;
25476212Saw148015 mystats->val_sum += value;
25486212Saw148015 mystats->sqr_sum += (value * value);
25496212Saw148015
25506212Saw148015 return (0);
25516212Saw148015 }
25526212Saw148015
25536212Saw148015 /*
25546212Saw148015 * Initialize the private data area used to accumulate the statistics
25556212Saw148015 */
25566212Saw148015 static int
25576212Saw148015 flowoplib_testrandvar_init(flowop_t *flowop)
25586212Saw148015 {
25596212Saw148015 testrandvar_priv_t *mystats;
25606212Saw148015
25616212Saw148015 if ((mystats = (testrandvar_priv_t *)
25626212Saw148015 malloc(sizeof (testrandvar_priv_t))) == NULL) {
25636212Saw148015 filebench_log(LOG_ERROR, "could not initialize testrandvar");
25646212Saw148015 filebench_shutdown(1);
25656212Saw148015 return (-1);
25666212Saw148015 }
25676212Saw148015
25686212Saw148015 mystats->sample_count = 0;
25696212Saw148015 mystats->val_sum = 0;
25706212Saw148015 mystats->sqr_sum = 0;
25716212Saw148015 flowop->fo_private = (void *)mystats;
25726212Saw148015
25736212Saw148015 (void) ipc_mutex_unlock(&flowop->fo_lock);
25746212Saw148015 return (0);
25756212Saw148015 }
25766212Saw148015
25776212Saw148015 /*
25786212Saw148015 * Print out the accumulated statistics, and free the private storage
25796212Saw148015 */
25806212Saw148015 static void
25816212Saw148015 flowoplib_testrandvar_destruct(flowop_t *flowop)
25826212Saw148015 {
25836212Saw148015 testrandvar_priv_t *mystats;
25846212Saw148015 double mean, std_dev, dbl_count;
25856212Saw148015
25866212Saw148015 (void) ipc_mutex_lock(&flowop->fo_lock);
25876212Saw148015 if ((mystats = (testrandvar_priv_t *)
25886212Saw148015 flowop->fo_private) == NULL) {
25896212Saw148015 (void) ipc_mutex_unlock(&flowop->fo_lock);
25906212Saw148015 return;
25916212Saw148015 }
25926212Saw148015
25936212Saw148015 flowop->fo_private = NULL;
25946212Saw148015 (void) ipc_mutex_unlock(&flowop->fo_lock);
25956212Saw148015
25966212Saw148015 dbl_count = (double)mystats->sample_count;
25976212Saw148015 mean = mystats->val_sum / dbl_count;
25986212Saw148015 std_dev = sqrt((mystats->sqr_sum / dbl_count) - (mean * mean)) / mean;
25996212Saw148015
26006212Saw148015 filebench_log(LOG_VERBOSE,
26016286Saw148015 "testrandvar: ops = %llu, mean = %8.2lf, stddev = %8.2lf",
26026286Saw148015 (u_longlong_t)mystats->sample_count, mean, std_dev);
26036212Saw148015 free(mystats);
26046212Saw148015 }
26055184Sek110237
26065184Sek110237 /*
26077556SAndrew.W.Wilson@sun.com * prints message to the console from within a thread
26087556SAndrew.W.Wilson@sun.com */
26097556SAndrew.W.Wilson@sun.com static int
26107556SAndrew.W.Wilson@sun.com flowoplib_print(threadflow_t *threadflow, flowop_t *flowop)
26117556SAndrew.W.Wilson@sun.com {
26127556SAndrew.W.Wilson@sun.com procflow_t *procflow;
26137556SAndrew.W.Wilson@sun.com
26147556SAndrew.W.Wilson@sun.com procflow = threadflow->tf_process;
26157556SAndrew.W.Wilson@sun.com filebench_log(LOG_INFO,
26167556SAndrew.W.Wilson@sun.com "Message from process (%s,%d), thread (%s,%d): %s",
26177556SAndrew.W.Wilson@sun.com procflow->pf_name, procflow->pf_instance,
26187556SAndrew.W.Wilson@sun.com threadflow->tf_name, threadflow->tf_instance,
26197556SAndrew.W.Wilson@sun.com avd_get_str(flowop->fo_value));
26207556SAndrew.W.Wilson@sun.com
26217556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
26227556SAndrew.W.Wilson@sun.com }
26237556SAndrew.W.Wilson@sun.com
26247556SAndrew.W.Wilson@sun.com /*
26255184Sek110237 * Prints usage information for flowop operations.
26265184Sek110237 */
26275184Sek110237 void
26285184Sek110237 flowoplib_usage()
26295184Sek110237 {
26305184Sek110237 (void) fprintf(stderr,
26315184Sek110237 "flowop [openfile|createfile] name=<name>,fileset=<fname>\n");
26325184Sek110237 (void) fprintf(stderr,
26335184Sek110237 " [,fd=<file desc num>]\n");
26345184Sek110237 (void) fprintf(stderr, "\n");
26355184Sek110237 (void) fprintf(stderr,
26365184Sek110237 "flowop closefile name=<name>,fd=<file desc num>]\n");
26375184Sek110237 (void) fprintf(stderr, "\n");
26385184Sek110237 (void) fprintf(stderr, "flowop deletefile name=<name>\n");
26395184Sek110237 (void) fprintf(stderr, " [,fileset=<fname>]\n");
26405184Sek110237 (void) fprintf(stderr,
26415184Sek110237 " [,fd=<file desc num>]\n");
26425184Sek110237 (void) fprintf(stderr, "\n");
26435184Sek110237 (void) fprintf(stderr, "flowop statfile name=<name>\n");
26445184Sek110237 (void) fprintf(stderr, " [,fileset=<fname>]\n");
26455184Sek110237 (void) fprintf(stderr,
26465184Sek110237 " [,fd=<file desc num>]\n");
26475184Sek110237 (void) fprintf(stderr, "\n");
26485184Sek110237 (void) fprintf(stderr,
26495184Sek110237 "flowop fsync name=<name>,fd=<file desc num>]\n");
26505184Sek110237 (void) fprintf(stderr, "\n");
26515184Sek110237 (void) fprintf(stderr,
26525184Sek110237 "flowop fsyncset name=<name>,fileset=<fname>]\n");
26535184Sek110237 (void) fprintf(stderr, "\n");
26545184Sek110237 (void) fprintf(stderr, "flowop [write|read|aiowrite] name=<name>, \n");
26555184Sek110237 (void) fprintf(stderr,
26565184Sek110237 " filename|fileset=<fname>,\n");
26575184Sek110237 (void) fprintf(stderr, " iosize=<size>\n");
26585184Sek110237 (void) fprintf(stderr, " [,directio]\n");
26595184Sek110237 (void) fprintf(stderr, " [,dsync]\n");
26605184Sek110237 (void) fprintf(stderr, " [,iters=<count>]\n");
26615184Sek110237 (void) fprintf(stderr, " [,random]\n");
26625184Sek110237 (void) fprintf(stderr, " [,opennext]\n");
26635184Sek110237 (void) fprintf(stderr, " [,workingset=<size>]\n");
26645184Sek110237 (void) fprintf(stderr,
26655184Sek110237 "flowop [appendfile|appendfilerand] name=<name>, \n");
26665184Sek110237 (void) fprintf(stderr,
26675184Sek110237 " filename|fileset=<fname>,\n");
26685184Sek110237 (void) fprintf(stderr, " iosize=<size>\n");
26695184Sek110237 (void) fprintf(stderr, " [,dsync]\n");
26705184Sek110237 (void) fprintf(stderr, " [,iters=<count>]\n");
26715184Sek110237 (void) fprintf(stderr, " [,workingset=<size>]\n");
26725184Sek110237 (void) fprintf(stderr,
26735184Sek110237 "flowop [readwholefile|writewholefile] name=<name>, \n");
26745184Sek110237 (void) fprintf(stderr,
26755184Sek110237 " filename|fileset=<fname>,\n");
26765184Sek110237 (void) fprintf(stderr, " iosize=<size>\n");
26775184Sek110237 (void) fprintf(stderr, " [,dsync]\n");
26785184Sek110237 (void) fprintf(stderr, " [,iters=<count>]\n");
26795184Sek110237 (void) fprintf(stderr, "\n");
26805184Sek110237 (void) fprintf(stderr, "flowop aiowait name=<name>,target="
26815184Sek110237 "<aiowrite-flowop>\n");
26825184Sek110237 (void) fprintf(stderr, "\n");
26835184Sek110237 (void) fprintf(stderr, "flowop sempost name=<name>,"
26845184Sek110237 "target=<semblock-flowop>,\n");
26855184Sek110237 (void) fprintf(stderr,
26865184Sek110237 " value=<increment-to-post>\n");
26875184Sek110237 (void) fprintf(stderr, "\n");
26885184Sek110237 (void) fprintf(stderr, "flowop semblock name=<name>,value="
26895184Sek110237 "<decrement-to-receive>,\n");
26905184Sek110237 (void) fprintf(stderr, " highwater="
26915184Sek110237 "<inbound-queue-max>\n");
26925184Sek110237 (void) fprintf(stderr, "\n");
26935184Sek110237 (void) fprintf(stderr, "flowop block name=<name>\n");
26945184Sek110237 (void) fprintf(stderr, "\n");
26955184Sek110237 (void) fprintf(stderr,
26965184Sek110237 "flowop wakeup name=<name>,target=<block-flowop>,\n");
26975184Sek110237 (void) fprintf(stderr, "\n");
26985184Sek110237 (void) fprintf(stderr,
26995184Sek110237 "flowop hog name=<name>,value=<number-of-mem-ops>\n");
27005184Sek110237 (void) fprintf(stderr,
27015184Sek110237 "flowop delay name=<name>,value=<number-of-seconds>\n");
27025184Sek110237 (void) fprintf(stderr, "\n");
27035184Sek110237 (void) fprintf(stderr, "flowop eventlimit name=<name>\n");
27045184Sek110237 (void) fprintf(stderr, "flowop bwlimit name=<name>,value=<mb/s>\n");
27055184Sek110237 (void) fprintf(stderr, "flowop iopslimit name=<name>,value=<iop/s>\n");
27065184Sek110237 (void) fprintf(stderr,
27075184Sek110237 "flowop finishoncount name=<name>,value=<ops/s>\n");
27085184Sek110237 (void) fprintf(stderr,
27095184Sek110237 "flowop finishonbytes name=<name>,value=<bytes>\n");
27105184Sek110237 (void) fprintf(stderr, "\n");
27115184Sek110237 (void) fprintf(stderr, "\n");
27125184Sek110237 }
2713