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_UINT_T 535184Sek110237 #define uint_t unsigned int 545184Sek110237 #endif /* HAVE_UINT_T */ 555184Sek110237 565184Sek110237 #ifndef HAVE_SYSV_SEM 575184Sek110237 #include <semaphore.h> 585184Sek110237 #endif /* HAVE_SYSV_SEM */ 595184Sek110237 605184Sek110237 #include "filebench.h" 615184Sek110237 #include "flowop.h" 625184Sek110237 #include "fileset.h" 636212Saw148015 #include "fb_random.h" 647946SAndrew.W.Wilson@sun.com #include "utils.h" 658615SAndrew.W.Wilson@sun.com #include "fsplug.h" 668615SAndrew.W.Wilson@sun.com 675184Sek110237 /* 685184Sek110237 * These routines implement the flowops from the f language. Each 695184Sek110237 * flowop has has a name such as "read", and a set of function pointers 705184Sek110237 * to call for initialization, execution and destruction of the flowop. 715184Sek110237 * The table flowoplib_funcs[] contains a flowoplib struct for each 725184Sek110237 * implemented flowop. Most flowops use a generic initialization function 735184Sek110237 * and all currently use a generic destruction function. All flowop 745184Sek110237 * functions referenced from the table are in this file, though, of 755184Sek110237 * course, they often call functions from other files. 765184Sek110237 * 775184Sek110237 * The flowop_init() routine uses the flowoplib_funcs[] table to 785184Sek110237 * create an initial set of "instance 0" flowops, one for each type of 795184Sek110237 * flowop, from which all other flowops are derived. These "instance 0" 805184Sek110237 * flowops are initialized with information from the table including 815184Sek110237 * pointers for their fo_init, fo_func and fo_destroy functions. When 825184Sek110237 * a flowop definition is encountered in an f language script, the 835184Sek110237 * "type" of flowop, such as "read" is used to search for the 845184Sek110237 * "instance 0" flowop named "read", then a new flowop is allocated 855184Sek110237 * which inherits its function pointers and other initial properties 865184Sek110237 * from the instance 0 flowop, and is given a new name as specified 875184Sek110237 * by the "name=" attribute. 885184Sek110237 */ 895184Sek110237 906084Saw148015 static void flowoplib_destruct_noop(flowop_t *flowop); 915184Sek110237 static int flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop); 927556SAndrew.W.Wilson@sun.com static int flowoplib_print(threadflow_t *threadflow, flowop_t *flowop); 935184Sek110237 static int flowoplib_write(threadflow_t *threadflow, flowop_t *flowop); 945184Sek110237 static int flowoplib_read(threadflow_t *threadflow, flowop_t *flowop); 955184Sek110237 static int flowoplib_block_init(flowop_t *flowop); 965184Sek110237 static int flowoplib_block(threadflow_t *threadflow, flowop_t *flowop); 975184Sek110237 static int flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop); 985184Sek110237 static int flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop); 995184Sek110237 static int flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop); 1005184Sek110237 static int flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop); 1015184Sek110237 static int flowoplib_sempost_init(flowop_t *flowop); 1025184Sek110237 static int flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop); 1035184Sek110237 static int flowoplib_semblock_init(flowop_t *flowop); 1045184Sek110237 static void flowoplib_semblock_destruct(flowop_t *flowop); 1055184Sek110237 static int flowoplib_eventlimit(threadflow_t *, flowop_t *flowop); 1065184Sek110237 static int flowoplib_bwlimit(threadflow_t *, flowop_t *flowop); 1075184Sek110237 static int flowoplib_iopslimit(threadflow_t *, flowop_t *flowop); 1085184Sek110237 static int flowoplib_opslimit(threadflow_t *, flowop_t *flowop); 1095184Sek110237 static int flowoplib_openfile(threadflow_t *, flowop_t *flowop); 1105184Sek110237 static int flowoplib_openfile_common(threadflow_t *, flowop_t *flowop, int fd); 1115184Sek110237 static int flowoplib_createfile(threadflow_t *, flowop_t *flowop); 1125184Sek110237 static int flowoplib_closefile(threadflow_t *, flowop_t *flowop); 1137946SAndrew.W.Wilson@sun.com static int flowoplib_makedir(threadflow_t *, flowop_t *flowop); 1147946SAndrew.W.Wilson@sun.com static int flowoplib_removedir(threadflow_t *, flowop_t *flowop); 1157946SAndrew.W.Wilson@sun.com static int flowoplib_listdir(threadflow_t *, flowop_t *flowop); 1165184Sek110237 static int flowoplib_fsync(threadflow_t *, flowop_t *flowop); 1175184Sek110237 static int flowoplib_readwholefile(threadflow_t *, flowop_t *flowop); 1185184Sek110237 static int flowoplib_writewholefile(threadflow_t *, flowop_t *flowop); 1195184Sek110237 static int flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop); 1205184Sek110237 static int flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop); 1215184Sek110237 static int flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop); 1225184Sek110237 static int flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop); 1235184Sek110237 static int flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop); 1245184Sek110237 static int flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop); 1255184Sek110237 static int flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop); 1266212Saw148015 static int flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop); 1276212Saw148015 static int flowoplib_testrandvar_init(flowop_t *flowop); 1286212Saw148015 static void flowoplib_testrandvar_destruct(flowop_t *flowop); 1295184Sek110237 1308615SAndrew.W.Wilson@sun.com static flowop_proto_t flowoplib_funcs[] = { 1318615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "write", flowop_init_generic, 1328615SAndrew.W.Wilson@sun.com flowoplib_write, flowop_destruct_generic, 1338615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_READ, "read", flowop_init_generic, 1348615SAndrew.W.Wilson@sun.com flowoplib_read, flowop_destruct_generic, 1355184Sek110237 FLOW_TYPE_SYNC, 0, "block", flowoplib_block_init, 1368615SAndrew.W.Wilson@sun.com flowoplib_block, flowop_destruct_generic, 1378615SAndrew.W.Wilson@sun.com FLOW_TYPE_SYNC, 0, "wakeup", flowop_init_generic, 1388615SAndrew.W.Wilson@sun.com flowoplib_wakeup, flowop_destruct_generic, 1395184Sek110237 FLOW_TYPE_SYNC, 0, "semblock", flowoplib_semblock_init, 1405184Sek110237 flowoplib_semblock, flowoplib_semblock_destruct, 1415184Sek110237 FLOW_TYPE_SYNC, 0, "sempost", flowoplib_sempost_init, 1426084Saw148015 flowoplib_sempost, flowoplib_destruct_noop, 1438615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "hog", flowop_init_generic, 1448615SAndrew.W.Wilson@sun.com flowoplib_hog, flowop_destruct_generic, 1458615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "delay", flowop_init_generic, 1468615SAndrew.W.Wilson@sun.com flowoplib_delay, flowop_destruct_generic, 1478615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "eventlimit", flowop_init_generic, 1488615SAndrew.W.Wilson@sun.com flowoplib_eventlimit, flowop_destruct_generic, 1498615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "bwlimit", flowop_init_generic, 1508615SAndrew.W.Wilson@sun.com flowoplib_bwlimit, flowop_destruct_generic, 1518615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "iopslimit", flowop_init_generic, 1528615SAndrew.W.Wilson@sun.com flowoplib_iopslimit, flowop_destruct_generic, 1538615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "opslimit", flowop_init_generic, 1548615SAndrew.W.Wilson@sun.com flowoplib_opslimit, flowop_destruct_generic, 1558615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "finishoncount", flowop_init_generic, 1568615SAndrew.W.Wilson@sun.com flowoplib_finishoncount, flowop_destruct_generic, 1578615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "finishonbytes", flowop_init_generic, 1588615SAndrew.W.Wilson@sun.com flowoplib_finishonbytes, flowop_destruct_generic, 1598615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "openfile", flowop_init_generic, 1608615SAndrew.W.Wilson@sun.com flowoplib_openfile, flowop_destruct_generic, 1618615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "createfile", flowop_init_generic, 1628615SAndrew.W.Wilson@sun.com flowoplib_createfile, flowop_destruct_generic, 1638615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "closefile", flowop_init_generic, 1648615SAndrew.W.Wilson@sun.com flowoplib_closefile, flowop_destruct_generic, 1658615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "makedir", flowop_init_generic, 1668615SAndrew.W.Wilson@sun.com flowoplib_makedir, flowop_destruct_generic, 1678615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "removedir", flowop_init_generic, 1688615SAndrew.W.Wilson@sun.com flowoplib_removedir, flowop_destruct_generic, 1698615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "listdir", flowop_init_generic, 1708615SAndrew.W.Wilson@sun.com flowoplib_listdir, flowop_destruct_generic, 1718615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "fsync", flowop_init_generic, 1728615SAndrew.W.Wilson@sun.com flowoplib_fsync, flowop_destruct_generic, 1738615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "fsyncset", flowop_init_generic, 1748615SAndrew.W.Wilson@sun.com flowoplib_fsyncset, flowop_destruct_generic, 1758615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "statfile", flowop_init_generic, 1768615SAndrew.W.Wilson@sun.com flowoplib_statfile, flowop_destruct_generic, 1778615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_READ, "readwholefile", flowop_init_generic, 1788615SAndrew.W.Wilson@sun.com flowoplib_readwholefile, flowop_destruct_generic, 1798615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "appendfile", flowop_init_generic, 1808615SAndrew.W.Wilson@sun.com flowoplib_appendfile, flowop_destruct_generic, 1818615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "appendfilerand", flowop_init_generic, 1828615SAndrew.W.Wilson@sun.com flowoplib_appendfilerand, flowop_destruct_generic, 1838615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, 0, "deletefile", flowop_init_generic, 1848615SAndrew.W.Wilson@sun.com flowoplib_deletefile, flowop_destruct_generic, 1858615SAndrew.W.Wilson@sun.com FLOW_TYPE_IO, FLOW_ATTR_WRITE, "writewholefile", flowop_init_generic, 1868615SAndrew.W.Wilson@sun.com flowoplib_writewholefile, flowop_destruct_generic, 1878615SAndrew.W.Wilson@sun.com FLOW_TYPE_OTHER, 0, "print", flowop_init_generic, 1888615SAndrew.W.Wilson@sun.com flowoplib_print, flowop_destruct_generic, 1896212Saw148015 /* routine to calculate mean and stddev for output from a randvar */ 1906212Saw148015 FLOW_TYPE_OTHER, 0, "testrandvar", flowoplib_testrandvar_init, 1916212Saw148015 flowoplib_testrandvar, flowoplib_testrandvar_destruct 1925184Sek110237 }; 1935184Sek110237 1945184Sek110237 /* 1958615SAndrew.W.Wilson@sun.com * Loops through the list of flowops defined in this 1965184Sek110237 * module, and creates and initializes a flowop for each one 1978615SAndrew.W.Wilson@sun.com * by calling flowop_flow_init. As a side effect of calling 1988615SAndrew.W.Wilson@sun.com * flowop_flow_init, the created flowops are placed on the 1995184Sek110237 * master flowop list. All created flowops are set to 2005184Sek110237 * instance "0". 2015184Sek110237 */ 2025184Sek110237 void 2038615SAndrew.W.Wilson@sun.com flowoplib_flowinit() 2045184Sek110237 { 2058615SAndrew.W.Wilson@sun.com int nops = sizeof (flowoplib_funcs) / sizeof (flowop_proto_t); 2068615SAndrew.W.Wilson@sun.com 2078615SAndrew.W.Wilson@sun.com flowop_flow_init(flowoplib_funcs, nops); 2086084Saw148015 } 2096084Saw148015 2106084Saw148015 /* 2116084Saw148015 * Special total noop destruct 2126084Saw148015 */ 2136084Saw148015 /* ARGSUSED */ 2146084Saw148015 static void 2156084Saw148015 flowoplib_destruct_noop(flowop_t *flowop) 2166084Saw148015 { 2175184Sek110237 } 2185184Sek110237 2195184Sek110237 /* 2205184Sek110237 * Generates a file attribute from flags in the supplied flowop. 2215184Sek110237 * Sets FLOW_ATTR_DIRECTIO and/or FLOW_ATTR_DSYNC as needed. 2225184Sek110237 */ 2235184Sek110237 static int 2245184Sek110237 flowoplib_fileattrs(flowop_t *flowop) 2255184Sek110237 { 2265184Sek110237 int attrs = 0; 2275184Sek110237 2286212Saw148015 if (avd_get_bool(flowop->fo_directio)) 2295184Sek110237 attrs |= FLOW_ATTR_DIRECTIO; 2305184Sek110237 2316212Saw148015 if (avd_get_bool(flowop->fo_dsync)) 2325184Sek110237 attrs |= FLOW_ATTR_DSYNC; 2335184Sek110237 2345184Sek110237 return (attrs); 2355184Sek110237 } 2365184Sek110237 2375184Sek110237 /* 2388404SAndrew.W.Wilson@sun.com * Obtain a filesetentry for a file. Result placed where filep points. 2398404SAndrew.W.Wilson@sun.com * Supply with a flowop and a flag to indicate whether an existent or 2408404SAndrew.W.Wilson@sun.com * non-existent file is required. Returns FILEBENCH_NORSC if all out 2418404SAndrew.W.Wilson@sun.com * of the appropriate type of directories, FILEBENCH_ERROR if the 2428404SAndrew.W.Wilson@sun.com * flowop does not point to a fileset, and FILEBENCH_OK otherwise. 2438404SAndrew.W.Wilson@sun.com */ 2448404SAndrew.W.Wilson@sun.com static int 2458404SAndrew.W.Wilson@sun.com flowoplib_pickfile(filesetentry_t **filep, flowop_t *flowop, int flags, int tid) 2468404SAndrew.W.Wilson@sun.com { 2478404SAndrew.W.Wilson@sun.com fileset_t *fileset; 2488404SAndrew.W.Wilson@sun.com int fileindex; 2498404SAndrew.W.Wilson@sun.com 2508404SAndrew.W.Wilson@sun.com if ((fileset = flowop->fo_fileset) == NULL) { 2518404SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "flowop NO fileset"); 2528404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2538404SAndrew.W.Wilson@sun.com } 2548404SAndrew.W.Wilson@sun.com 2558404SAndrew.W.Wilson@sun.com if (flowop->fo_fileindex) { 2568404SAndrew.W.Wilson@sun.com fileindex = (int)(avd_get_dbl(flowop->fo_fileindex) * 2578404SAndrew.W.Wilson@sun.com ((double)(fileset->fs_constentries / 2))); 2588404SAndrew.W.Wilson@sun.com fileindex = fileindex % fileset->fs_constentries; 2598404SAndrew.W.Wilson@sun.com flags |= FILESET_PICKBYINDEX; 2608404SAndrew.W.Wilson@sun.com } else { 2618404SAndrew.W.Wilson@sun.com fileindex = 0; 2628404SAndrew.W.Wilson@sun.com } 2638404SAndrew.W.Wilson@sun.com 2648404SAndrew.W.Wilson@sun.com if ((*filep = fileset_pick(fileset, FILESET_PICKFILE | flags, 2658404SAndrew.W.Wilson@sun.com tid, fileindex)) == NULL) { 2668404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 2678404SAndrew.W.Wilson@sun.com "flowop %s failed to pick file from fileset %s", 2688404SAndrew.W.Wilson@sun.com flowop->fo_name, 2698404SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name)); 2708404SAndrew.W.Wilson@sun.com return (FILEBENCH_NORSC); 2718404SAndrew.W.Wilson@sun.com } 2728404SAndrew.W.Wilson@sun.com 2738404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 2748404SAndrew.W.Wilson@sun.com } 2758404SAndrew.W.Wilson@sun.com 2768404SAndrew.W.Wilson@sun.com /* 2778404SAndrew.W.Wilson@sun.com * Obtain a filesetentry for a leaf directory. Result placed where dirp 2788404SAndrew.W.Wilson@sun.com * points. Supply with flowop and a flag to indicate whether an existent 2798404SAndrew.W.Wilson@sun.com * or non-existent leaf directory is required. Returns FILEBENCH_NORSC 2808404SAndrew.W.Wilson@sun.com * if all out of the appropriate type of directories, FILEBENCH_ERROR 2818404SAndrew.W.Wilson@sun.com * if the flowop does not point to a fileset, and FILEBENCH_OK otherwise. 2828404SAndrew.W.Wilson@sun.com */ 2838404SAndrew.W.Wilson@sun.com static int 2848404SAndrew.W.Wilson@sun.com flowoplib_pickleafdir(filesetentry_t **dirp, flowop_t *flowop, int flags) 2858404SAndrew.W.Wilson@sun.com { 2868404SAndrew.W.Wilson@sun.com fileset_t *fileset; 2878404SAndrew.W.Wilson@sun.com int dirindex; 2888404SAndrew.W.Wilson@sun.com 2898404SAndrew.W.Wilson@sun.com if ((fileset = flowop->fo_fileset) == NULL) { 2908404SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "flowop NO fileset"); 2918404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2928404SAndrew.W.Wilson@sun.com } 2938404SAndrew.W.Wilson@sun.com 2948404SAndrew.W.Wilson@sun.com if (flowop->fo_fileindex) { 2958404SAndrew.W.Wilson@sun.com dirindex = (int)(avd_get_dbl(flowop->fo_fileindex) * 2968404SAndrew.W.Wilson@sun.com ((double)(fileset->fs_constleafdirs / 2))); 2978404SAndrew.W.Wilson@sun.com dirindex = dirindex % fileset->fs_constleafdirs; 2988404SAndrew.W.Wilson@sun.com flags |= FILESET_PICKBYINDEX; 2998404SAndrew.W.Wilson@sun.com } else { 3008404SAndrew.W.Wilson@sun.com dirindex = 0; 3018404SAndrew.W.Wilson@sun.com } 3028404SAndrew.W.Wilson@sun.com 3038404SAndrew.W.Wilson@sun.com if ((*dirp = fileset_pick(fileset, 3048404SAndrew.W.Wilson@sun.com FILESET_PICKLEAFDIR | flags, 0, dirindex)) == NULL) { 3058404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 3068404SAndrew.W.Wilson@sun.com "flowop %s failed to pick directory from fileset %s", 3078404SAndrew.W.Wilson@sun.com flowop->fo_name, 3088404SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name)); 3098404SAndrew.W.Wilson@sun.com return (FILEBENCH_NORSC); 3108404SAndrew.W.Wilson@sun.com } 3118404SAndrew.W.Wilson@sun.com 3128404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 3138404SAndrew.W.Wilson@sun.com } 3148404SAndrew.W.Wilson@sun.com 3158404SAndrew.W.Wilson@sun.com /* 3165184Sek110237 * Searches for a file descriptor. Tries the flowop's 3175184Sek110237 * fo_fdnumber first and returns with it if it has been 3185184Sek110237 * explicitly set (greater than 0). It next checks to 3195184Sek110237 * see if a rotating file descriptor policy is in effect, 3205184Sek110237 * and if not returns the fdnumber regardless of what 3215184Sek110237 * it is. (note that if it is 0, it just selects to the 3225184Sek110237 * default file descriptor in the threadflow's tf_fd 3235184Sek110237 * array). If the rotating fd policy is in effect, it 3245184Sek110237 * cycles from the end of the tf_fd array to one location 3255184Sek110237 * beyond the maximum needed by the number of entries in 3265184Sek110237 * the associated fileset on each invocation, then starts 3275184Sek110237 * over from the end. 3285184Sek110237 * 3295184Sek110237 * The routine returns an index into the threadflow's 3305184Sek110237 * tf_fd table where the actual file descriptor will be 3315184Sek110237 * found. Note: the calling routine must not call this 3325184Sek110237 * routine if the flowop does not have a fileset, and the 3335184Sek110237 * flowop's fo_fdnumber is zero and fo_rotatefd is 3345184Sek110237 * asserted, or an addressing fault may occur. 3355184Sek110237 */ 3365673Saw148015 static int 3375184Sek110237 flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop) 3385184Sek110237 { 3396212Saw148015 fbint_t entries; 3406391Saw148015 int fdnumber = flowop->fo_fdnumber; 3416212Saw148015 3425184Sek110237 /* If the script sets the fd explicitly */ 3436391Saw148015 if (fdnumber > 0) 3446391Saw148015 return (fdnumber); 3455184Sek110237 3465184Sek110237 /* If the flowop defaults to persistent fd */ 3476212Saw148015 if (!avd_get_bool(flowop->fo_rotatefd)) 3486391Saw148015 return (fdnumber); 3496391Saw148015 3506391Saw148015 if (flowop->fo_fileset == NULL) { 3516391Saw148015 filebench_log(LOG_ERROR, "flowop NULL file"); 3526391Saw148015 return (FILEBENCH_ERROR); 3536391Saw148015 } 3545184Sek110237 3556212Saw148015 entries = flowop->fo_fileset->fs_constentries; 3566212Saw148015 3575184Sek110237 /* Rotate the fd on each flowop invocation */ 3586212Saw148015 if (entries > (THREADFLOW_MAXFD / 2)) { 3595184Sek110237 filebench_log(LOG_ERROR, "Out of file descriptors in flowop %s" 3606286Saw148015 " (too many files : %llu", 3616286Saw148015 flowop->fo_name, (u_longlong_t)entries); 3626084Saw148015 return (FILEBENCH_ERROR); 3635184Sek110237 } 3645184Sek110237 3655184Sek110237 /* First time around */ 3665184Sek110237 if (threadflow->tf_fdrotor == 0) 3675184Sek110237 threadflow->tf_fdrotor = THREADFLOW_MAXFD; 3685184Sek110237 3695184Sek110237 /* One fd for every file in the set */ 3706212Saw148015 if (entries == (THREADFLOW_MAXFD - threadflow->tf_fdrotor)) 3715184Sek110237 threadflow->tf_fdrotor = THREADFLOW_MAXFD; 3725184Sek110237 3735184Sek110237 3745184Sek110237 threadflow->tf_fdrotor--; 3755184Sek110237 filebench_log(LOG_DEBUG_IMPL, "selected fd = %d", 3765184Sek110237 threadflow->tf_fdrotor); 3775184Sek110237 return (threadflow->tf_fdrotor); 3785184Sek110237 } 3795184Sek110237 3805184Sek110237 /* 3815673Saw148015 * Determines the file descriptor to use, and attempts to open 3825673Saw148015 * the file if it is not already open. Also determines the wss 3836084Saw148015 * value. Returns FILEBENCH_ERROR on errors, FILESET_NORSC if 3846084Saw148015 * if flowop_openfile_common couldn't obtain an appropriate file 3856084Saw148015 * from a the fileset, and FILEBENCH_OK otherwise. 3865673Saw148015 */ 3875673Saw148015 static int 3885673Saw148015 flowoplib_filesetup(threadflow_t *threadflow, flowop_t *flowop, 3898615SAndrew.W.Wilson@sun.com fbint_t *wssp, fb_fdesc_t **fdescp) 3905673Saw148015 { 3915673Saw148015 int fd = flowoplib_fdnum(threadflow, flowop); 3925673Saw148015 3935673Saw148015 if (fd == -1) 3946084Saw148015 return (FILEBENCH_ERROR); 3955673Saw148015 396*9326SAndrew.W.Wilson@sun.com /* check for conflicting fdnumber and file name */ 397*9326SAndrew.W.Wilson@sun.com if ((fd > 0) && (threadflow->tf_fse[fd] != NULL)) { 398*9326SAndrew.W.Wilson@sun.com char *fd_based_name; 399*9326SAndrew.W.Wilson@sun.com 400*9326SAndrew.W.Wilson@sun.com fd_based_name = 401*9326SAndrew.W.Wilson@sun.com avd_get_str(threadflow->tf_fse[fd]->fse_fileset->fs_name); 402*9326SAndrew.W.Wilson@sun.com 403*9326SAndrew.W.Wilson@sun.com if (flowop->fo_filename != NULL) { 404*9326SAndrew.W.Wilson@sun.com char *fo_based_name; 405*9326SAndrew.W.Wilson@sun.com 406*9326SAndrew.W.Wilson@sun.com fo_based_name = avd_get_str(flowop->fo_filename); 407*9326SAndrew.W.Wilson@sun.com if (strcmp(fd_based_name, fo_based_name) != 0) { 408*9326SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Name of fd refer" 409*9326SAndrew.W.Wilson@sun.com "enced fileset name (%s) CONFLICTS with" 410*9326SAndrew.W.Wilson@sun.com " flowop supplied fileset name (%s)", 411*9326SAndrew.W.Wilson@sun.com fd_based_name, fo_based_name); 412*9326SAndrew.W.Wilson@sun.com filebench_shutdown(1); 413*9326SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 414*9326SAndrew.W.Wilson@sun.com } 415*9326SAndrew.W.Wilson@sun.com } 416*9326SAndrew.W.Wilson@sun.com } 417*9326SAndrew.W.Wilson@sun.com 4188615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr == NULL) { 4196084Saw148015 int ret; 4206084Saw148015 4216084Saw148015 if ((ret = flowoplib_openfile_common( 4226084Saw148015 threadflow, flowop, fd)) != FILEBENCH_OK) 4236084Saw148015 return (ret); 4245673Saw148015 4255673Saw148015 if (threadflow->tf_fse[fd]) { 4265673Saw148015 filebench_log(LOG_DEBUG_IMPL, "opened file %s", 4275673Saw148015 threadflow->tf_fse[fd]->fse_path); 4285673Saw148015 } else { 4295673Saw148015 filebench_log(LOG_DEBUG_IMPL, 4305673Saw148015 "opened device %s/%s", 4316212Saw148015 avd_get_str(flowop->fo_fileset->fs_path), 4326212Saw148015 avd_get_str(flowop->fo_fileset->fs_name)); 4335673Saw148015 } 4345673Saw148015 } 4355673Saw148015 4368615SAndrew.W.Wilson@sun.com *fdescp = &(threadflow->tf_fd[fd]); 4375673Saw148015 4386212Saw148015 if ((*wssp = flowop->fo_constwss) == 0) { 4395673Saw148015 if (threadflow->tf_fse[fd]) 4405673Saw148015 *wssp = threadflow->tf_fse[fd]->fse_size; 4415673Saw148015 else 4426212Saw148015 *wssp = avd_get_int(flowop->fo_fileset->fs_size); 4435673Saw148015 } 4445673Saw148015 4456084Saw148015 return (FILEBENCH_OK); 4465673Saw148015 } 4475673Saw148015 4485673Saw148015 /* 4495673Saw148015 * Determines the io buffer or random offset into tf_mem for 4506084Saw148015 * the IO operation. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise. 4515673Saw148015 */ 4525673Saw148015 static int 4535673Saw148015 flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop, 4546212Saw148015 caddr_t *iobufp, fbint_t iosize) 4555673Saw148015 { 4565673Saw148015 long memsize; 4575673Saw148015 size_t memoffset; 4585673Saw148015 4595673Saw148015 if (iosize == 0) { 4605673Saw148015 filebench_log(LOG_ERROR, "zero iosize for thread %s", 4615673Saw148015 flowop->fo_name); 4626084Saw148015 return (FILEBENCH_ERROR); 4635673Saw148015 } 4645673Saw148015 4656212Saw148015 if ((memsize = threadflow->tf_constmemsize) != 0) { 4665673Saw148015 4675673Saw148015 /* use tf_mem for I/O with random offset */ 4686212Saw148015 if (filebench_randomno(&memoffset, 4696212Saw148015 memsize, iosize, NULL) == -1) { 4705673Saw148015 filebench_log(LOG_ERROR, 4715673Saw148015 "tf_memsize smaller than IO size for thread %s", 4725673Saw148015 flowop->fo_name); 4736084Saw148015 return (FILEBENCH_ERROR); 4745673Saw148015 } 4755673Saw148015 *iobufp = threadflow->tf_mem + memoffset; 4765673Saw148015 4775673Saw148015 } else { 4785673Saw148015 /* use private I/O buffer */ 4795673Saw148015 if ((flowop->fo_buf != NULL) && 4805673Saw148015 (flowop->fo_buf_size < iosize)) { 4816212Saw148015 /* too small, so free up and re-allocate */ 4825673Saw148015 free(flowop->fo_buf); 4835673Saw148015 flowop->fo_buf = NULL; 4845673Saw148015 } 4856212Saw148015 4866212Saw148015 /* 4876212Saw148015 * Allocate memory for the buffer. The memory is freed 4886212Saw148015 * by flowop_destruct_generic() or by this routine if more 4896212Saw148015 * memory is needed for the buffer. 4906212Saw148015 */ 4915673Saw148015 if ((flowop->fo_buf == NULL) && ((flowop->fo_buf 4925673Saw148015 = (char *)malloc(iosize)) == NULL)) 4936084Saw148015 return (FILEBENCH_ERROR); 4945673Saw148015 4955673Saw148015 flowop->fo_buf_size = iosize; 4965673Saw148015 *iobufp = flowop->fo_buf; 4975673Saw148015 } 4986084Saw148015 return (FILEBENCH_OK); 4995673Saw148015 } 5005673Saw148015 5015673Saw148015 /* 5025673Saw148015 * Determines the file descriptor to use, opens it if necessary, the 5035673Saw148015 * io buffer or random offset into tf_mem for IO operation and the wss 5046084Saw148015 * value. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise. 5055673Saw148015 */ 5068615SAndrew.W.Wilson@sun.com int 5075673Saw148015 flowoplib_iosetup(threadflow_t *threadflow, flowop_t *flowop, 5088615SAndrew.W.Wilson@sun.com fbint_t *wssp, caddr_t *iobufp, fb_fdesc_t **filedescp, fbint_t iosize) 5095673Saw148015 { 5106084Saw148015 int ret; 5116084Saw148015 5126084Saw148015 if ((ret = flowoplib_filesetup(threadflow, flowop, wssp, filedescp)) != 5136084Saw148015 FILEBENCH_OK) 5146084Saw148015 return (ret); 5155673Saw148015 5166084Saw148015 if ((ret = flowoplib_iobufsetup(threadflow, flowop, iobufp, iosize)) != 5176084Saw148015 FILEBENCH_OK) 5186084Saw148015 return (ret); 5195673Saw148015 5206084Saw148015 return (FILEBENCH_OK); 5215673Saw148015 } 5225673Saw148015 5235673Saw148015 /* 5245184Sek110237 * Emulate posix read / pread. If the flowop has a fileset, 5255184Sek110237 * a file descriptor number index is fetched, otherwise a 5265184Sek110237 * supplied fileobj file is used. In either case the specified 5275184Sek110237 * file will be opened if not already open. If the flowop has 5286084Saw148015 * neither a fileset or fileobj, an error is logged and FILEBENCH_ERROR 5295184Sek110237 * returned. 5305184Sek110237 * 5315184Sek110237 * The actual read is done to a random offset in the 5325184Sek110237 * threadflow's thread memory (tf_mem), with a size set by 5335184Sek110237 * fo_iosize and at either a random disk offset within the 5345184Sek110237 * working set size, or at the next sequential location. If 5356084Saw148015 * any errors are encountered, FILEBENCH_ERROR is returned, 5366084Saw148015 * if no appropriate file can be obtained from the fileset then 5376084Saw148015 * FILEBENCH_NORSC is returned, otherise FILEBENCH_OK is returned. 5385184Sek110237 */ 5395184Sek110237 static int 5405184Sek110237 flowoplib_read(threadflow_t *threadflow, flowop_t *flowop) 5415184Sek110237 { 5425673Saw148015 caddr_t iobuf; 5436212Saw148015 fbint_t wss; 5446212Saw148015 fbint_t iosize; 5458615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc; 5465184Sek110237 int ret; 5475184Sek110237 5486212Saw148015 5496212Saw148015 iosize = avd_get_int(flowop->fo_iosize); 5506084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, 5518615SAndrew.W.Wilson@sun.com &fdesc, iosize)) != FILEBENCH_OK) 5526084Saw148015 return (ret); 5535184Sek110237 5546212Saw148015 if (avd_get_bool(flowop->fo_random)) { 5555184Sek110237 uint64_t fileoffset; 5565184Sek110237 5576212Saw148015 if (filebench_randomno64(&fileoffset, 5586212Saw148015 wss, iosize, NULL) == -1) { 5595184Sek110237 filebench_log(LOG_ERROR, 5605184Sek110237 "file size smaller than IO size for thread %s", 5615184Sek110237 flowop->fo_name); 5626084Saw148015 return (FILEBENCH_ERROR); 5635184Sek110237 } 5645184Sek110237 5655184Sek110237 (void) flowop_beginop(threadflow, flowop); 5668615SAndrew.W.Wilson@sun.com if ((ret = FB_PREAD(fdesc, iobuf, 5676212Saw148015 iosize, (off64_t)fileoffset)) == -1) { 5685673Saw148015 (void) flowop_endop(threadflow, flowop, 0); 5695184Sek110237 filebench_log(LOG_ERROR, 5706286Saw148015 "read file %s failed, offset %llu " 5715673Saw148015 "io buffer %zd: %s", 5726212Saw148015 avd_get_str(flowop->fo_fileset->fs_name), 5736286Saw148015 (u_longlong_t)fileoffset, iobuf, strerror(errno)); 5745673Saw148015 flowop_endop(threadflow, flowop, 0); 5756084Saw148015 return (FILEBENCH_ERROR); 5765184Sek110237 } 5775673Saw148015 (void) flowop_endop(threadflow, flowop, ret); 5785184Sek110237 5795184Sek110237 if ((ret == 0)) 5808615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_SET); 5815184Sek110237 5825184Sek110237 } else { 5835184Sek110237 (void) flowop_beginop(threadflow, flowop); 5848615SAndrew.W.Wilson@sun.com if ((ret = FB_READ(fdesc, iobuf, iosize)) == -1) { 5856212Saw148015 (void) flowop_endop(threadflow, flowop, 0); 5865184Sek110237 filebench_log(LOG_ERROR, 5875673Saw148015 "read file %s failed, io buffer %zd: %s", 5886212Saw148015 avd_get_str(flowop->fo_fileset->fs_name), 5895673Saw148015 iobuf, strerror(errno)); 5905673Saw148015 (void) flowop_endop(threadflow, flowop, 0); 5916084Saw148015 return (FILEBENCH_ERROR); 5925184Sek110237 } 5935673Saw148015 (void) flowop_endop(threadflow, flowop, ret); 5945184Sek110237 5955184Sek110237 if ((ret == 0)) 5968615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_SET); 5975184Sek110237 } 5985184Sek110237 5996084Saw148015 return (FILEBENCH_OK); 6005184Sek110237 } 6015184Sek110237 6025184Sek110237 /* 6035184Sek110237 * Initializes a "flowop_block" flowop. Specifically, it 6045184Sek110237 * initializes the flowop's fo_cv and unlocks the fo_lock. 6055184Sek110237 */ 6065184Sek110237 static int 6075184Sek110237 flowoplib_block_init(flowop_t *flowop) 6085184Sek110237 { 6095184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d block init address %zx", 6105184Sek110237 flowop->fo_name, flowop->fo_instance, &flowop->fo_cv); 6115184Sek110237 (void) pthread_cond_init(&flowop->fo_cv, ipc_condattr()); 6125184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock); 6135184Sek110237 6146084Saw148015 return (FILEBENCH_OK); 6155184Sek110237 } 6165184Sek110237 6175184Sek110237 /* 6185184Sek110237 * Blocks the threadflow until woken up by flowoplib_wakeup. 6195184Sek110237 * The routine blocks on the flowop's fo_cv condition variable. 6205184Sek110237 */ 6215184Sek110237 static int 6225184Sek110237 flowoplib_block(threadflow_t *threadflow, flowop_t *flowop) 6235184Sek110237 { 6245184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d blocking at address %zx", 6255184Sek110237 flowop->fo_name, flowop->fo_instance, &flowop->fo_cv); 6265184Sek110237 (void) ipc_mutex_lock(&flowop->fo_lock); 6275184Sek110237 6285184Sek110237 flowop_beginop(threadflow, flowop); 6295184Sek110237 (void) pthread_cond_wait(&flowop->fo_cv, &flowop->fo_lock); 6305673Saw148015 flowop_endop(threadflow, flowop, 0); 6315184Sek110237 6325184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d unblocking", 6335184Sek110237 flowop->fo_name, flowop->fo_instance); 6345184Sek110237 6355184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock); 6365184Sek110237 6376084Saw148015 return (FILEBENCH_OK); 6385184Sek110237 } 6395184Sek110237 6405184Sek110237 /* 6415184Sek110237 * Wakes up one or more target blocking flowops. 6425184Sek110237 * Sends broadcasts on the fo_cv condition variables of all 6435184Sek110237 * flowops on the target list, except those that are 6445184Sek110237 * FLOW_MASTER flowops. The target list consists of all 6455184Sek110237 * flowops whose name matches this flowop's "fo_targetname" 6465184Sek110237 * attribute. The target list is generated on the first 6475184Sek110237 * invocation, and the run will be shutdown if no targets 6486084Saw148015 * are found. Otherwise the routine always returns FILEBENCH_OK. 6495184Sek110237 */ 6505184Sek110237 static int 6515184Sek110237 flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop) 6525184Sek110237 { 6535184Sek110237 flowop_t *target; 6545184Sek110237 6555184Sek110237 /* if this is the first wakeup, create the wakeup list */ 6565184Sek110237 if (flowop->fo_targets == NULL) { 6575184Sek110237 flowop_t *result = flowop_find(flowop->fo_targetname); 6585184Sek110237 6595184Sek110237 flowop->fo_targets = result; 6605184Sek110237 if (result == NULL) { 6615184Sek110237 filebench_log(LOG_ERROR, 6625184Sek110237 "wakeup: could not find op %s for thread %s", 6635184Sek110237 flowop->fo_targetname, 6645184Sek110237 threadflow->tf_name); 6655184Sek110237 filebench_shutdown(1); 6665184Sek110237 } 6675184Sek110237 while (result) { 6685184Sek110237 result->fo_targetnext = 6695184Sek110237 result->fo_resultnext; 6705184Sek110237 result = result->fo_resultnext; 6715184Sek110237 } 6725184Sek110237 } 6735184Sek110237 6745184Sek110237 target = flowop->fo_targets; 6755184Sek110237 6765184Sek110237 /* wakeup the targets */ 6775184Sek110237 while (target) { 6785184Sek110237 if (target->fo_instance == FLOW_MASTER) { 6795184Sek110237 target = target->fo_targetnext; 6805184Sek110237 continue; 6815184Sek110237 } 6825184Sek110237 filebench_log(LOG_DEBUG_IMPL, 6835184Sek110237 "wakeup flow %s-%d at address %zx", 6845184Sek110237 target->fo_name, 6855184Sek110237 target->fo_instance, 6865184Sek110237 &target->fo_cv); 6875184Sek110237 6885184Sek110237 flowop_beginop(threadflow, flowop); 6895184Sek110237 (void) ipc_mutex_lock(&target->fo_lock); 6905184Sek110237 (void) pthread_cond_broadcast(&target->fo_cv); 6915184Sek110237 (void) ipc_mutex_unlock(&target->fo_lock); 6925673Saw148015 flowop_endop(threadflow, flowop, 0); 6935184Sek110237 6945184Sek110237 target = target->fo_targetnext; 6955184Sek110237 } 6965184Sek110237 6976084Saw148015 return (FILEBENCH_OK); 6985184Sek110237 } 6995184Sek110237 7005184Sek110237 /* 7015184Sek110237 * "think time" routines. the "hog" routine consumes cpu cycles as 7025184Sek110237 * it "thinks", while the "delay" flowop simply calls sleep() to delay 7035184Sek110237 * for a given number of seconds without consuming cpu cycles. 7045184Sek110237 */ 7055184Sek110237 7065184Sek110237 7075184Sek110237 /* 7085184Sek110237 * Consumes CPU cycles and memory bandwidth by looping for 7095184Sek110237 * flowop->fo_value times. With each loop sets memory location 7105184Sek110237 * threadflow->tf_mem to 1. 7115184Sek110237 */ 7125184Sek110237 static int 7135184Sek110237 flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop) 7145184Sek110237 { 7156212Saw148015 uint64_t value = avd_get_int(flowop->fo_value); 7165184Sek110237 int i; 7175184Sek110237 7185673Saw148015 filebench_log(LOG_DEBUG_IMPL, "hog enter"); 7195184Sek110237 flowop_beginop(threadflow, flowop); 7205673Saw148015 if (threadflow->tf_mem != NULL) { 7215673Saw148015 for (i = 0; i < value; i++) 7225673Saw148015 *(threadflow->tf_mem) = 1; 7235673Saw148015 } 7245673Saw148015 flowop_endop(threadflow, flowop, 0); 7255184Sek110237 filebench_log(LOG_DEBUG_IMPL, "hog exit"); 7266084Saw148015 return (FILEBENCH_OK); 7275184Sek110237 } 7285184Sek110237 7295184Sek110237 7305184Sek110237 /* 7315184Sek110237 * Delays for fo_value seconds. 7325184Sek110237 */ 7335184Sek110237 static int 7345184Sek110237 flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop) 7355184Sek110237 { 7366212Saw148015 int value = avd_get_int(flowop->fo_value); 7375184Sek110237 7385184Sek110237 flowop_beginop(threadflow, flowop); 7395184Sek110237 (void) sleep(value); 7405673Saw148015 flowop_endop(threadflow, flowop, 0); 7416084Saw148015 return (FILEBENCH_OK); 7425184Sek110237 } 7435184Sek110237 7445184Sek110237 /* 7455184Sek110237 * Rate limiting routines. This is the event consuming half of the 7465184Sek110237 * event system. Each of the four following routines will limit the rate 7475184Sek110237 * to one unit of either calls, issued I/O operations, issued filebench 7485184Sek110237 * operations, or I/O bandwidth. Since there is only one event generator, 7495184Sek110237 * the events will be divided amoung multiple instances of an event 7505184Sek110237 * consumer, and further divided among different consumers if more than 7515184Sek110237 * one has been defined. There is no mechanism to enforce equal sharing 7525184Sek110237 * of events. 7535184Sek110237 */ 7545184Sek110237 7555184Sek110237 /* 7565184Sek110237 * Completes one invocation per posted event. If eventgen_q 7575184Sek110237 * has an event count greater than zero, one will be removed 7585184Sek110237 * (count decremented), otherwise the calling thread will 7595184Sek110237 * block until another event has been posted. Always returns 0 7605184Sek110237 */ 7615184Sek110237 static int 7625184Sek110237 flowoplib_eventlimit(threadflow_t *threadflow, flowop_t *flowop) 7635184Sek110237 { 7645184Sek110237 /* Immediately bail if not set/enabled */ 7657946SAndrew.W.Wilson@sun.com if (filebench_shm->shm_eventgen_hz == NULL) 7666084Saw148015 return (FILEBENCH_OK); 7675184Sek110237 7685184Sek110237 if (flowop->fo_initted == 0) { 7695184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking", 7705184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance); 7715184Sek110237 flowop->fo_initted = 1; 7725184Sek110237 } 7735184Sek110237 7745184Sek110237 flowop_beginop(threadflow, flowop); 7757946SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_hz != NULL) { 7766391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock); 7776391Saw148015 if (filebench_shm->shm_eventgen_q > 0) { 7786391Saw148015 filebench_shm->shm_eventgen_q--; 7796391Saw148015 (void) ipc_mutex_unlock( 7806391Saw148015 &filebench_shm->shm_eventgen_lock); 7815184Sek110237 break; 7825184Sek110237 } 7836391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv, 7846391Saw148015 &filebench_shm->shm_eventgen_lock); 7856391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock); 7865184Sek110237 } 7875673Saw148015 flowop_endop(threadflow, flowop, 0); 7886084Saw148015 return (FILEBENCH_OK); 7895184Sek110237 } 7905184Sek110237 7916701Saw148015 static int 7926701Saw148015 flowoplib_event_find_target(threadflow_t *threadflow, flowop_t *flowop) 7936701Saw148015 { 7946701Saw148015 if (flowop->fo_targetname[0] != '\0') { 7956701Saw148015 7966701Saw148015 /* Try to use statistics from specific flowop */ 7976701Saw148015 flowop->fo_targets = 7986701Saw148015 flowop_find_from_list(flowop->fo_targetname, 7996701Saw148015 threadflow->tf_thrd_fops); 8006701Saw148015 if (flowop->fo_targets == NULL) { 8016701Saw148015 filebench_log(LOG_ERROR, 8026701Saw148015 "limit target: could not find flowop %s", 8036701Saw148015 flowop->fo_targetname); 8046701Saw148015 filebench_shutdown(1); 8056701Saw148015 return (FILEBENCH_ERROR); 8066701Saw148015 } 8076701Saw148015 } else { 8086701Saw148015 /* use total workload statistics */ 8096701Saw148015 flowop->fo_targets = NULL; 8106701Saw148015 } 8116701Saw148015 return (FILEBENCH_OK); 8126701Saw148015 } 8136701Saw148015 8145184Sek110237 /* 8155184Sek110237 * Blocks the calling thread if the number of issued I/O 8165184Sek110237 * operations exceeds the number of posted events, thus 8175184Sek110237 * limiting the average I/O operation rate to the rate 8186084Saw148015 * specified by eventgen_hz. Always returns FILEBENCH_OK. 8195184Sek110237 */ 8205184Sek110237 static int 8215184Sek110237 flowoplib_iopslimit(threadflow_t *threadflow, flowop_t *flowop) 8225184Sek110237 { 8235184Sek110237 uint64_t iops; 8245184Sek110237 uint64_t delta; 8255673Saw148015 uint64_t events; 8265184Sek110237 8275184Sek110237 /* Immediately bail if not set/enabled */ 8287946SAndrew.W.Wilson@sun.com if (filebench_shm->shm_eventgen_hz == NULL) 8296084Saw148015 return (FILEBENCH_OK); 8305184Sek110237 8315184Sek110237 if (flowop->fo_initted == 0) { 8325184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking", 8335184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance); 8345184Sek110237 flowop->fo_initted = 1; 8356701Saw148015 8366701Saw148015 if (flowoplib_event_find_target(threadflow, flowop) 8376701Saw148015 == FILEBENCH_ERROR) 8386701Saw148015 return (FILEBENCH_ERROR); 8396701Saw148015 8406701Saw148015 if (flowop->fo_targets && ((flowop->fo_targets->fo_attrs & 8416701Saw148015 (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) { 8426701Saw148015 filebench_log(LOG_ERROR, 8436701Saw148015 "WARNING: Flowop %s does no IO", 8446701Saw148015 flowop->fo_targets->fo_name); 8456701Saw148015 filebench_shutdown(1); 8466701Saw148015 return (FILEBENCH_ERROR); 8476701Saw148015 } 8485184Sek110237 } 8495184Sek110237 8506701Saw148015 if (flowop->fo_targets) { 8516701Saw148015 /* 8526701Saw148015 * Note that fs_count is already the sum of fs_rcount 8536701Saw148015 * and fs_wcount if looking at a single flowop. 8546701Saw148015 */ 8556701Saw148015 iops = flowop->fo_targets->fo_stats.fs_count; 8566701Saw148015 } else { 8576701Saw148015 (void) ipc_mutex_lock(&controlstats_lock); 8586701Saw148015 iops = (controlstats.fs_rcount + 8596701Saw148015 controlstats.fs_wcount); 8606701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock); 8616701Saw148015 } 8625184Sek110237 8635184Sek110237 /* Is this the first time around */ 8645184Sek110237 if (flowop->fo_tputlast == 0) { 8655184Sek110237 flowop->fo_tputlast = iops; 8666084Saw148015 return (FILEBENCH_OK); 8675184Sek110237 } 8685184Sek110237 8695184Sek110237 delta = iops - flowop->fo_tputlast; 8705184Sek110237 flowop->fo_tputbucket -= delta; 8715184Sek110237 flowop->fo_tputlast = iops; 8725184Sek110237 8735184Sek110237 /* No need to block if the q isn't empty */ 8745184Sek110237 if (flowop->fo_tputbucket >= 0LL) { 8755673Saw148015 flowop_endop(threadflow, flowop, 0); 8766084Saw148015 return (FILEBENCH_OK); 8775184Sek110237 } 8785184Sek110237 8795184Sek110237 iops = flowop->fo_tputbucket * -1; 8805184Sek110237 events = iops; 8815184Sek110237 8825184Sek110237 flowop_beginop(threadflow, flowop); 8837946SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_hz != NULL) { 8845184Sek110237 8856391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock); 8866391Saw148015 if (filebench_shm->shm_eventgen_q >= events) { 8876391Saw148015 filebench_shm->shm_eventgen_q -= events; 8886391Saw148015 (void) ipc_mutex_unlock( 8896391Saw148015 &filebench_shm->shm_eventgen_lock); 8905184Sek110237 flowop->fo_tputbucket += events; 8915184Sek110237 break; 8925184Sek110237 } 8936391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv, 8946391Saw148015 &filebench_shm->shm_eventgen_lock); 8956391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock); 8965184Sek110237 } 8975673Saw148015 flowop_endop(threadflow, flowop, 0); 8985184Sek110237 8996084Saw148015 return (FILEBENCH_OK); 9005184Sek110237 } 9015184Sek110237 9025184Sek110237 /* 9035184Sek110237 * Blocks the calling thread if the number of issued filebench 9045184Sek110237 * operations exceeds the number of posted events, thus limiting 9055184Sek110237 * the average filebench operation rate to the rate specified by 9066084Saw148015 * eventgen_hz. Always returns FILEBENCH_OK. 9075184Sek110237 */ 9085184Sek110237 static int 9095184Sek110237 flowoplib_opslimit(threadflow_t *threadflow, flowop_t *flowop) 9105184Sek110237 { 9115184Sek110237 uint64_t ops; 9125184Sek110237 uint64_t delta; 9135673Saw148015 uint64_t events; 9145184Sek110237 9155184Sek110237 /* Immediately bail if not set/enabled */ 9167946SAndrew.W.Wilson@sun.com if (filebench_shm->shm_eventgen_hz == NULL) 9176084Saw148015 return (FILEBENCH_OK); 9185184Sek110237 9195184Sek110237 if (flowop->fo_initted == 0) { 9205184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking", 9215184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance); 9225184Sek110237 flowop->fo_initted = 1; 9236701Saw148015 9246701Saw148015 if (flowoplib_event_find_target(threadflow, flowop) 9256701Saw148015 == FILEBENCH_ERROR) 9266701Saw148015 return (FILEBENCH_ERROR); 9275184Sek110237 } 9285184Sek110237 9296701Saw148015 if (flowop->fo_targets) { 9306701Saw148015 ops = flowop->fo_targets->fo_stats.fs_count; 9316701Saw148015 } else { 9326701Saw148015 (void) ipc_mutex_lock(&controlstats_lock); 9336701Saw148015 ops = controlstats.fs_count; 9346701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock); 9356701Saw148015 } 9365184Sek110237 9375184Sek110237 /* Is this the first time around */ 9385184Sek110237 if (flowop->fo_tputlast == 0) { 9395184Sek110237 flowop->fo_tputlast = ops; 9406084Saw148015 return (FILEBENCH_OK); 9415184Sek110237 } 9425184Sek110237 9435184Sek110237 delta = ops - flowop->fo_tputlast; 9445184Sek110237 flowop->fo_tputbucket -= delta; 9455184Sek110237 flowop->fo_tputlast = ops; 9465184Sek110237 9475184Sek110237 /* No need to block if the q isn't empty */ 9485184Sek110237 if (flowop->fo_tputbucket >= 0LL) { 9495673Saw148015 flowop_endop(threadflow, flowop, 0); 9506084Saw148015 return (FILEBENCH_OK); 9515184Sek110237 } 9525184Sek110237 9535184Sek110237 ops = flowop->fo_tputbucket * -1; 9545184Sek110237 events = ops; 9555184Sek110237 9565184Sek110237 flowop_beginop(threadflow, flowop); 9577946SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_hz != NULL) { 9586391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock); 9596391Saw148015 if (filebench_shm->shm_eventgen_q >= events) { 9606391Saw148015 filebench_shm->shm_eventgen_q -= events; 9616391Saw148015 (void) ipc_mutex_unlock( 9626391Saw148015 &filebench_shm->shm_eventgen_lock); 9635184Sek110237 flowop->fo_tputbucket += events; 9645184Sek110237 break; 9655184Sek110237 } 9666391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv, 9676391Saw148015 &filebench_shm->shm_eventgen_lock); 9686391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock); 9695184Sek110237 } 9705673Saw148015 flowop_endop(threadflow, flowop, 0); 9715184Sek110237 9726084Saw148015 return (FILEBENCH_OK); 9735184Sek110237 } 9745184Sek110237 9755184Sek110237 9765184Sek110237 /* 9775184Sek110237 * Blocks the calling thread if the number of bytes of I/O 9785184Sek110237 * issued exceeds one megabyte times the number of posted 9795184Sek110237 * events, thus limiting the average I/O byte rate to one 9805184Sek110237 * megabyte times the event rate as set by eventgen_hz. 9816084Saw148015 * Always retuns FILEBENCH_OK. 9825184Sek110237 */ 9835184Sek110237 static int 9845184Sek110237 flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop) 9855184Sek110237 { 9865184Sek110237 uint64_t bytes; 9875184Sek110237 uint64_t delta; 9885673Saw148015 uint64_t events; 9895184Sek110237 9905184Sek110237 /* Immediately bail if not set/enabled */ 9917946SAndrew.W.Wilson@sun.com if (filebench_shm->shm_eventgen_hz == NULL) 9926084Saw148015 return (FILEBENCH_OK); 9935184Sek110237 9945184Sek110237 if (flowop->fo_initted == 0) { 9955184Sek110237 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking", 9965184Sek110237 flowop, threadflow->tf_name, threadflow->tf_instance); 9975184Sek110237 flowop->fo_initted = 1; 9986701Saw148015 9996701Saw148015 if (flowoplib_event_find_target(threadflow, flowop) 10006701Saw148015 == FILEBENCH_ERROR) 10016701Saw148015 return (FILEBENCH_ERROR); 10026701Saw148015 10036701Saw148015 if ((flowop->fo_targets) && 10046701Saw148015 ((flowop->fo_targets->fo_attrs & 10056701Saw148015 (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) { 10066701Saw148015 filebench_log(LOG_ERROR, 10076701Saw148015 "WARNING: Flowop %s does no Reads or Writes", 10086701Saw148015 flowop->fo_targets->fo_name); 10096701Saw148015 filebench_shutdown(1); 10106701Saw148015 return (FILEBENCH_ERROR); 10116701Saw148015 } 10125184Sek110237 } 10135184Sek110237 10146701Saw148015 if (flowop->fo_targets) { 10156701Saw148015 /* 10166701Saw148015 * Note that fs_bytes is already the sum of fs_rbytes 10176701Saw148015 * and fs_wbytes if looking at a single flowop. 10186701Saw148015 */ 10196701Saw148015 bytes = flowop->fo_targets->fo_stats.fs_bytes; 10206701Saw148015 } else { 10216701Saw148015 (void) ipc_mutex_lock(&controlstats_lock); 10226701Saw148015 bytes = (controlstats.fs_rbytes + 10236701Saw148015 controlstats.fs_wbytes); 10246701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock); 10256701Saw148015 } 10266701Saw148015 10276701Saw148015 /* Is this the first time around? */ 10285184Sek110237 if (flowop->fo_tputlast == 0) { 10295184Sek110237 flowop->fo_tputlast = bytes; 10306084Saw148015 return (FILEBENCH_OK); 10315184Sek110237 } 10325184Sek110237 10335184Sek110237 delta = bytes - flowop->fo_tputlast; 10345184Sek110237 flowop->fo_tputbucket -= delta; 10355184Sek110237 flowop->fo_tputlast = bytes; 10365184Sek110237 10375184Sek110237 /* No need to block if the q isn't empty */ 10385184Sek110237 if (flowop->fo_tputbucket >= 0LL) { 10395673Saw148015 flowop_endop(threadflow, flowop, 0); 10406084Saw148015 return (FILEBENCH_OK); 10415184Sek110237 } 10425184Sek110237 10435184Sek110237 bytes = flowop->fo_tputbucket * -1; 10445184Sek110237 events = (bytes / MB) + 1; 10455184Sek110237 10466286Saw148015 filebench_log(LOG_DEBUG_IMPL, "%llu bytes, %llu events", 10476286Saw148015 (u_longlong_t)bytes, (u_longlong_t)events); 10485184Sek110237 10495184Sek110237 flowop_beginop(threadflow, flowop); 10507946SAndrew.W.Wilson@sun.com while (filebench_shm->shm_eventgen_hz != NULL) { 10516391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock); 10526391Saw148015 if (filebench_shm->shm_eventgen_q >= events) { 10536391Saw148015 filebench_shm->shm_eventgen_q -= events; 10546391Saw148015 (void) ipc_mutex_unlock( 10556391Saw148015 &filebench_shm->shm_eventgen_lock); 10565184Sek110237 flowop->fo_tputbucket += (events * MB); 10575184Sek110237 break; 10585184Sek110237 } 10596391Saw148015 (void) pthread_cond_wait(&filebench_shm->shm_eventgen_cv, 10606391Saw148015 &filebench_shm->shm_eventgen_lock); 10616391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock); 10625184Sek110237 } 10635673Saw148015 flowop_endop(threadflow, flowop, 0); 10645184Sek110237 10656084Saw148015 return (FILEBENCH_OK); 10665184Sek110237 } 10675184Sek110237 10685184Sek110237 /* 10695184Sek110237 * These flowops terminate a benchmark run when either the specified 10705184Sek110237 * number of bytes of I/O (flowoplib_finishonbytes) or the specified 10715184Sek110237 * number of I/O operations (flowoplib_finishoncount) have been generated. 10725184Sek110237 */ 10735184Sek110237 10745184Sek110237 10755184Sek110237 /* 10765184Sek110237 * Stop filebench run when specified number of I/O bytes have been 10776212Saw148015 * transferred. Compares controlstats.fs_bytes with flowop->value, 10785184Sek110237 * and if greater returns 1, stopping the run, if not, returns 0 10795184Sek110237 * to continue running. 10805184Sek110237 */ 10815184Sek110237 static int 10825184Sek110237 flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop) 10835184Sek110237 { 10846701Saw148015 uint64_t bytes_io; /* Bytes of I/O delivered so far */ 10856701Saw148015 uint64_t byte_lim = flowop->fo_constvalue; /* Total Bytes desired */ 10866701Saw148015 /* Uses constant value */ 10876701Saw148015 10886701Saw148015 if (flowop->fo_initted == 0) { 10896701Saw148015 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking", 10906701Saw148015 flowop, threadflow->tf_name, threadflow->tf_instance); 10916701Saw148015 flowop->fo_initted = 1; 10926701Saw148015 10936701Saw148015 if (flowoplib_event_find_target(threadflow, flowop) 10946701Saw148015 == FILEBENCH_ERROR) 10956701Saw148015 return (FILEBENCH_ERROR); 10966701Saw148015 10976701Saw148015 if ((flowop->fo_targets) && 10986701Saw148015 ((flowop->fo_targets->fo_attrs & 10996701Saw148015 (FLOW_ATTR_READ | FLOW_ATTR_WRITE)) == 0)) { 11006701Saw148015 filebench_log(LOG_ERROR, 11016701Saw148015 "WARNING: Flowop %s does no Reads or Writes", 11026701Saw148015 flowop->fo_targets->fo_name); 11036701Saw148015 filebench_shutdown(1); 11046701Saw148015 return (FILEBENCH_ERROR); 11056701Saw148015 } 11066701Saw148015 } 11076701Saw148015 11086701Saw148015 if (flowop->fo_targets) { 11096701Saw148015 bytes_io = flowop->fo_targets->fo_stats.fs_bytes; 11106701Saw148015 } else { 11116701Saw148015 (void) ipc_mutex_lock(&controlstats_lock); 11126701Saw148015 bytes_io = controlstats.fs_bytes; 11136701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock); 11146701Saw148015 } 11155184Sek110237 11165184Sek110237 flowop_beginop(threadflow, flowop); 11176701Saw148015 if (bytes_io > byte_lim) { 11185673Saw148015 flowop_endop(threadflow, flowop, 0); 11196084Saw148015 return (FILEBENCH_DONE); 11205184Sek110237 } 11215673Saw148015 flowop_endop(threadflow, flowop, 0); 11225184Sek110237 11236084Saw148015 return (FILEBENCH_OK); 11245184Sek110237 } 11255184Sek110237 11265184Sek110237 /* 11275184Sek110237 * Stop filebench run when specified number of I/O operations have 11285184Sek110237 * been performed. Compares controlstats.fs_count with *flowop->value, 11296084Saw148015 * and if greater returns 1, stopping the run, if not, returns FILEBENCH_OK 11306084Saw148015 * to continue running. 11315184Sek110237 */ 11325184Sek110237 static int 11335184Sek110237 flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop) 11345184Sek110237 { 11355184Sek110237 uint64_t ops; 11366212Saw148015 uint64_t count = flowop->fo_constvalue; /* use constant value */ 11375184Sek110237 11386701Saw148015 if (flowop->fo_initted == 0) { 11396701Saw148015 filebench_log(LOG_DEBUG_IMPL, "rate %zx %s-%d locking", 11406701Saw148015 flowop, threadflow->tf_name, threadflow->tf_instance); 11416701Saw148015 flowop->fo_initted = 1; 11426701Saw148015 11436701Saw148015 if (flowoplib_event_find_target(threadflow, flowop) 11446701Saw148015 == FILEBENCH_ERROR) 11456701Saw148015 return (FILEBENCH_ERROR); 11466701Saw148015 } 11476701Saw148015 11486701Saw148015 if (flowop->fo_targets) { 11496701Saw148015 ops = flowop->fo_targets->fo_stats.fs_count; 11506701Saw148015 } else { 11516701Saw148015 (void) ipc_mutex_lock(&controlstats_lock); 11526701Saw148015 ops = controlstats.fs_count; 11536701Saw148015 (void) ipc_mutex_unlock(&controlstats_lock); 11546701Saw148015 } 11555184Sek110237 11565184Sek110237 flowop_beginop(threadflow, flowop); 11576084Saw148015 if (ops >= count) { 11585673Saw148015 flowop_endop(threadflow, flowop, 0); 11596084Saw148015 return (FILEBENCH_DONE); 11605184Sek110237 } 11615673Saw148015 flowop_endop(threadflow, flowop, 0); 11625184Sek110237 11636084Saw148015 return (FILEBENCH_OK); 11645184Sek110237 } 11655184Sek110237 11665184Sek110237 /* 11675184Sek110237 * Semaphore synchronization using either System V semaphores or 11685184Sek110237 * posix semaphores. If System V semaphores are available, they will be 11695184Sek110237 * used, otherwise posix semaphores will be used. 11705184Sek110237 */ 11715184Sek110237 11725184Sek110237 11735184Sek110237 /* 11745184Sek110237 * Initializes the filebench "block on semaphore" flowop. 11755184Sek110237 * If System V semaphores are implemented, the routine 11765184Sek110237 * initializes the System V semaphore subsystem if it hasn't 11775184Sek110237 * already been initialized, also allocates a pair of semids 11785184Sek110237 * and initializes the highwater System V semaphore. 11795184Sek110237 * If no System V semaphores, then does nothing special. 11806084Saw148015 * Returns FILEBENCH_ERROR if it cannot acquire a set of System V semphores 11816084Saw148015 * or if the initial post to the semaphore set fails. Returns FILEBENCH_OK 11825184Sek110237 * on success. 11835184Sek110237 */ 11845184Sek110237 static int 11855184Sek110237 flowoplib_semblock_init(flowop_t *flowop) 11865184Sek110237 { 11875184Sek110237 11885184Sek110237 #ifdef HAVE_SYSV_SEM 11896391Saw148015 int sys_semid; 11905184Sek110237 struct sembuf sbuf[2]; 11915184Sek110237 int highwater; 11925184Sek110237 11935184Sek110237 ipc_seminit(); 11945184Sek110237 11955184Sek110237 flowop->fo_semid_lw = ipc_semidalloc(); 11965184Sek110237 flowop->fo_semid_hw = ipc_semidalloc(); 11975184Sek110237 11985184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d semblock init semid=%x", 11995184Sek110237 flowop->fo_name, flowop->fo_instance, flowop->fo_semid_lw); 12005184Sek110237 12016391Saw148015 sys_semid = filebench_shm->shm_sys_semid; 12025184Sek110237 12035184Sek110237 if ((highwater = flowop->fo_semid_hw) == 0) 12046212Saw148015 highwater = flowop->fo_constvalue; /* use constant value */ 12055184Sek110237 12065184Sek110237 filebench_log(LOG_DEBUG_IMPL, "setting highwater to : %d", highwater); 12075184Sek110237 12085673Saw148015 sbuf[0].sem_num = (short)highwater; 12096212Saw148015 sbuf[0].sem_op = avd_get_int(flowop->fo_highwater); 12105184Sek110237 sbuf[0].sem_flg = 0; 12116391Saw148015 if ((semop(sys_semid, &sbuf[0], 1) == -1) && errno) { 12125184Sek110237 filebench_log(LOG_ERROR, "semblock init post failed: %s (%d," 12135184Sek110237 "%d)", strerror(errno), sbuf[0].sem_num, sbuf[0].sem_op); 12146084Saw148015 return (FILEBENCH_ERROR); 12155184Sek110237 } 12165184Sek110237 #else 12175184Sek110237 filebench_log(LOG_DEBUG_IMPL, 12185184Sek110237 "flow %s-%d semblock init with posix semaphore", 12195184Sek110237 flowop->fo_name, flowop->fo_instance); 12205184Sek110237 12215184Sek110237 sem_init(&flowop->fo_sem, 1, 0); 12225184Sek110237 #endif /* HAVE_SYSV_SEM */ 12235184Sek110237 12246212Saw148015 if (!(avd_get_bool(flowop->fo_blocking))) 12255184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock); 12265184Sek110237 12276084Saw148015 return (FILEBENCH_OK); 12285184Sek110237 } 12295184Sek110237 12305184Sek110237 /* 12315184Sek110237 * Releases the semids for the System V semaphore allocated 12325184Sek110237 * to this flowop. If not using System V semaphores, then 12336084Saw148015 * it is effectively just a no-op. 12345184Sek110237 */ 12355184Sek110237 static void 12365184Sek110237 flowoplib_semblock_destruct(flowop_t *flowop) 12375184Sek110237 { 12385184Sek110237 #ifdef HAVE_SYSV_SEM 12395184Sek110237 ipc_semidfree(flowop->fo_semid_lw); 12405184Sek110237 ipc_semidfree(flowop->fo_semid_hw); 12415184Sek110237 #else 12425184Sek110237 sem_destroy(&flowop->fo_sem); 12435184Sek110237 #endif /* HAVE_SYSV_SEM */ 12445184Sek110237 } 12455184Sek110237 12465184Sek110237 /* 12475184Sek110237 * Attempts to pass a System V or posix semaphore as appropriate, 12486084Saw148015 * and blocks if necessary. Returns FILEBENCH_ERROR if a set of System V 12495184Sek110237 * semphores is not available or cannot be acquired, or if the initial 12506084Saw148015 * post to the semaphore set fails. Returns FILEBENCH_OK on success. 12515184Sek110237 */ 12525184Sek110237 static int 12535184Sek110237 flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop) 12545184Sek110237 { 12555184Sek110237 12565184Sek110237 #ifdef HAVE_SYSV_SEM 12575184Sek110237 struct sembuf sbuf[2]; 12586212Saw148015 int value = avd_get_int(flowop->fo_value); 12596391Saw148015 int sys_semid; 12605184Sek110237 struct timespec timeout; 12615184Sek110237 12626391Saw148015 sys_semid = filebench_shm->shm_sys_semid; 12635184Sek110237 12645184Sek110237 filebench_log(LOG_DEBUG_IMPL, 12655184Sek110237 "flow %s-%d sem blocking on id %x num %x value %d", 12666391Saw148015 flowop->fo_name, flowop->fo_instance, sys_semid, 12675184Sek110237 flowop->fo_semid_hw, value); 12685184Sek110237 12695184Sek110237 /* Post, decrement the increment the hw queue */ 12705184Sek110237 sbuf[0].sem_num = flowop->fo_semid_hw; 12715673Saw148015 sbuf[0].sem_op = (short)value; 12725184Sek110237 sbuf[0].sem_flg = 0; 12735184Sek110237 sbuf[1].sem_num = flowop->fo_semid_lw; 12745184Sek110237 sbuf[1].sem_op = value * -1; 12755184Sek110237 sbuf[1].sem_flg = 0; 12765184Sek110237 timeout.tv_sec = 600; 12775184Sek110237 timeout.tv_nsec = 0; 12785184Sek110237 12796212Saw148015 if (avd_get_bool(flowop->fo_blocking)) 12805184Sek110237 (void) ipc_mutex_unlock(&flowop->fo_lock); 12815184Sek110237 12825184Sek110237 flowop_beginop(threadflow, flowop); 12835184Sek110237 12845184Sek110237 #ifdef HAVE_SEMTIMEDOP 12856391Saw148015 (void) semtimedop(sys_semid, &sbuf[0], 1, &timeout); 12866391Saw148015 (void) semtimedop(sys_semid, &sbuf[1], 1, &timeout); 12875184Sek110237 #else 12886391Saw148015 (void) semop(sys_semid, &sbuf[0], 1); 12896391Saw148015 (void) semop(sys_semid, &sbuf[1], 1); 12905184Sek110237 #endif /* HAVE_SEMTIMEDOP */ 12915184Sek110237 12926212Saw148015 if (avd_get_bool(flowop->fo_blocking)) 12935184Sek110237 (void) ipc_mutex_lock(&flowop->fo_lock); 12945184Sek110237 12955673Saw148015 flowop_endop(threadflow, flowop, 0); 12965184Sek110237 12975184Sek110237 #else 12986212Saw148015 int value = avd_get_int(flowop->fo_value); 12995184Sek110237 int i; 13005184Sek110237 13015184Sek110237 filebench_log(LOG_DEBUG_IMPL, 13025184Sek110237 "flow %s-%d sem blocking on posix semaphore", 13035184Sek110237 flowop->fo_name, flowop->fo_instance); 13045184Sek110237 13055184Sek110237 /* Decrement sem by value */ 13065184Sek110237 for (i = 0; i < value; i++) { 13075184Sek110237 if (sem_wait(&flowop->fo_sem) == -1) { 13085184Sek110237 filebench_log(LOG_ERROR, "semop wait failed"); 13096084Saw148015 return (FILEBENCH_ERROR); 13105184Sek110237 } 13115184Sek110237 } 13125184Sek110237 13135184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d sem unblocking", 13145184Sek110237 flowop->fo_name, flowop->fo_instance); 13155184Sek110237 #endif /* HAVE_SYSV_SEM */ 13165184Sek110237 13176084Saw148015 return (FILEBENCH_OK); 13185184Sek110237 } 13195184Sek110237 13205184Sek110237 /* 13216084Saw148015 * Calls ipc_seminit(). Always returns FILEBENCH_OK. 13225184Sek110237 */ 13235184Sek110237 /* ARGSUSED */ 13245184Sek110237 static int 13255184Sek110237 flowoplib_sempost_init(flowop_t *flowop) 13265184Sek110237 { 13275184Sek110237 #ifdef HAVE_SYSV_SEM 13285184Sek110237 ipc_seminit(); 13295184Sek110237 #endif /* HAVE_SYSV_SEM */ 13306084Saw148015 return (FILEBENCH_OK); 13315184Sek110237 } 13325184Sek110237 13335184Sek110237 /* 13345184Sek110237 * Post to a System V or posix semaphore as appropriate. 13355184Sek110237 * On the first call for a given flowop instance, this routine 13365184Sek110237 * will use the fo_targetname attribute to locate all semblock 13375184Sek110237 * flowops that are expecting posts from this flowop. All 13385184Sek110237 * target flowops on this list will have a post operation done 13395184Sek110237 * to their semaphores on each call. 13405184Sek110237 */ 13415184Sek110237 static int 13425184Sek110237 flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop) 13435184Sek110237 { 13445184Sek110237 flowop_t *target; 13455184Sek110237 13465184Sek110237 filebench_log(LOG_DEBUG_IMPL, 13475184Sek110237 "sempost flow %s-%d", 13485184Sek110237 flowop->fo_name, 13495184Sek110237 flowop->fo_instance); 13505184Sek110237 13515184Sek110237 /* if this is the first post, create the post list */ 13525184Sek110237 if (flowop->fo_targets == NULL) { 13535184Sek110237 flowop_t *result = flowop_find(flowop->fo_targetname); 13545184Sek110237 13555184Sek110237 flowop->fo_targets = result; 13565184Sek110237 13575184Sek110237 if (result == NULL) { 13585184Sek110237 filebench_log(LOG_ERROR, 13595184Sek110237 "sempost: could not find op %s for thread %s", 13605184Sek110237 flowop->fo_targetname, 13615184Sek110237 threadflow->tf_name); 13625184Sek110237 filebench_shutdown(1); 13635184Sek110237 } 13645184Sek110237 13655184Sek110237 while (result) { 13665184Sek110237 result->fo_targetnext = 13675184Sek110237 result->fo_resultnext; 13685184Sek110237 result = result->fo_resultnext; 13695184Sek110237 } 13705184Sek110237 } 13715184Sek110237 13725184Sek110237 target = flowop->fo_targets; 13735184Sek110237 13745184Sek110237 flowop_beginop(threadflow, flowop); 13755184Sek110237 /* post to the targets */ 13765184Sek110237 while (target) { 13775184Sek110237 #ifdef HAVE_SYSV_SEM 13785184Sek110237 struct sembuf sbuf[2]; 13796391Saw148015 int sys_semid; 13805184Sek110237 int blocking; 13815184Sek110237 #else 13825184Sek110237 int i; 13835184Sek110237 #endif /* HAVE_SYSV_SEM */ 13845184Sek110237 struct timespec timeout; 13856550Saw148015 int value = (int)avd_get_int(flowop->fo_value); 13865184Sek110237 13875184Sek110237 if (target->fo_instance == FLOW_MASTER) { 13885184Sek110237 target = target->fo_targetnext; 13895184Sek110237 continue; 13905184Sek110237 } 13915184Sek110237 13925184Sek110237 #ifdef HAVE_SYSV_SEM 13935184Sek110237 13945184Sek110237 filebench_log(LOG_DEBUG_IMPL, 13955184Sek110237 "sempost flow %s-%d num %x", 13965184Sek110237 target->fo_name, 13975184Sek110237 target->fo_instance, 13985184Sek110237 target->fo_semid_lw); 13995184Sek110237 14006391Saw148015 sys_semid = filebench_shm->shm_sys_semid; 14015184Sek110237 sbuf[0].sem_num = target->fo_semid_lw; 14025673Saw148015 sbuf[0].sem_op = (short)value; 14035184Sek110237 sbuf[0].sem_flg = 0; 14045184Sek110237 sbuf[1].sem_num = target->fo_semid_hw; 14055184Sek110237 sbuf[1].sem_op = value * -1; 14065184Sek110237 sbuf[1].sem_flg = 0; 14075184Sek110237 timeout.tv_sec = 600; 14085184Sek110237 timeout.tv_nsec = 0; 14095184Sek110237 14106212Saw148015 if (avd_get_bool(flowop->fo_blocking)) 14115184Sek110237 blocking = 1; 14125184Sek110237 else 14135184Sek110237 blocking = 0; 14145184Sek110237 14155184Sek110237 #ifdef HAVE_SEMTIMEDOP 14166391Saw148015 if ((semtimedop(sys_semid, &sbuf[0], blocking + 1, 14175184Sek110237 &timeout) == -1) && (errno && (errno != EAGAIN))) { 14185184Sek110237 #else 14196391Saw148015 if ((semop(sys_semid, &sbuf[0], blocking + 1) == -1) && 14205184Sek110237 (errno && (errno != EAGAIN))) { 14215184Sek110237 #endif /* HAVE_SEMTIMEDOP */ 14225184Sek110237 filebench_log(LOG_ERROR, "semop post failed: %s", 14235184Sek110237 strerror(errno)); 14246084Saw148015 return (FILEBENCH_ERROR); 14255184Sek110237 } 14265184Sek110237 14275184Sek110237 filebench_log(LOG_DEBUG_IMPL, 14285184Sek110237 "flow %s-%d finished posting", 14295184Sek110237 target->fo_name, target->fo_instance); 14305184Sek110237 #else 14315184Sek110237 filebench_log(LOG_DEBUG_IMPL, 14325184Sek110237 "sempost flow %s-%d to posix semaphore", 14335184Sek110237 target->fo_name, 14345184Sek110237 target->fo_instance); 14355184Sek110237 14365184Sek110237 /* Increment sem by value */ 14375184Sek110237 for (i = 0; i < value; i++) { 14385184Sek110237 if (sem_post(&target->fo_sem) == -1) { 14395184Sek110237 filebench_log(LOG_ERROR, "semop post failed"); 14406084Saw148015 return (FILEBENCH_ERROR); 14415184Sek110237 } 14425184Sek110237 } 14435184Sek110237 14445184Sek110237 filebench_log(LOG_DEBUG_IMPL, "flow %s-%d unblocking", 14455184Sek110237 target->fo_name, target->fo_instance); 14465184Sek110237 #endif /* HAVE_SYSV_SEM */ 14475184Sek110237 14485184Sek110237 target = target->fo_targetnext; 14495184Sek110237 } 14505673Saw148015 flowop_endop(threadflow, flowop, 0); 14515184Sek110237 14526084Saw148015 return (FILEBENCH_OK); 14535184Sek110237 } 14545184Sek110237 14555184Sek110237 14565184Sek110237 /* 14575184Sek110237 * Section for exercising create / open / close / delete operations 14585184Sek110237 * on files within a fileset. For proper operation, the flowop attribute 14595184Sek110237 * "fd", which sets the fo_fdnumber field in the flowop, must be used 14605184Sek110237 * so that the same file is opened and later closed. "fd" is an index 14615184Sek110237 * into a pair of arrays maintained by threadflows, one of which 14625184Sek110237 * contains the operating system assigned file descriptors and the other 14635184Sek110237 * a pointer to the filesetentry whose file the file descriptor 14645184Sek110237 * references. An openfile flowop defined without fd being set will use 14655184Sek110237 * the default (0) fd or, if specified, rotate through fd indices, but 14665184Sek110237 * createfile and closefile must use the default or a specified fd. 14675184Sek110237 * Meanwhile deletefile picks and arbitrary file to delete, regardless 14685184Sek110237 * of fd attribute. 14695184Sek110237 */ 14705184Sek110237 14715184Sek110237 /* 14725184Sek110237 * Emulates (and actually does) file open. Obtains a file descriptor 14736084Saw148015 * index, then calls flowoplib_openfile_common() to open. Returns 14746084Saw148015 * FILEBENCH_ERROR if no file descriptor is found, and returns the 14756084Saw148015 * status from flowoplib_openfile_common otherwise (FILEBENCH_ERROR, 14766084Saw148015 * FILEBENCH_NORSC, FILEBENCH_OK). 14775184Sek110237 */ 14785184Sek110237 static int 14795184Sek110237 flowoplib_openfile(threadflow_t *threadflow, flowop_t *flowop) 14805184Sek110237 { 14815184Sek110237 int fd = flowoplib_fdnum(threadflow, flowop); 14825184Sek110237 14835184Sek110237 if (fd == -1) 14846084Saw148015 return (FILEBENCH_ERROR); 14855184Sek110237 14865184Sek110237 return (flowoplib_openfile_common(threadflow, flowop, fd)); 14875184Sek110237 } 14885184Sek110237 14895184Sek110237 /* 14905184Sek110237 * Common file opening code for filesets. Uses the supplied 14915184Sek110237 * file descriptor index to determine the tf_fd entry to use. 14925184Sek110237 * If the entry is empty (0) and the fileset exists, fileset 14935184Sek110237 * pick is called to select a fileset entry to use. The file 14945184Sek110237 * specified in the filesetentry is opened, and the returned 14955184Sek110237 * operating system file descriptor and a pointer to the 14965184Sek110237 * filesetentry are stored in tf_fd[fd] and tf_fse[fd], 14976084Saw148015 * respectively. Returns FILEBENCH_ERROR on error, 14986084Saw148015 * FILEBENCH_NORSC if no suitable filesetentry can be found, 14996084Saw148015 * and FILEBENCH_OK on success. 15005184Sek110237 */ 15015184Sek110237 static int 15025184Sek110237 flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd) 15035184Sek110237 { 15045184Sek110237 filesetentry_t *file; 15056212Saw148015 char *fileset_name; 15065184Sek110237 int tid = 0; 1507*9326SAndrew.W.Wilson@sun.com int openflag = 0; 15088404SAndrew.W.Wilson@sun.com int err; 15095184Sek110237 15106391Saw148015 if (flowop->fo_fileset == NULL) { 15116391Saw148015 filebench_log(LOG_ERROR, "flowop NULL file"); 15126391Saw148015 return (FILEBENCH_ERROR); 15136391Saw148015 } 15146391Saw148015 15156212Saw148015 if ((fileset_name = 15166212Saw148015 avd_get_str(flowop->fo_fileset->fs_name)) == NULL) { 15176212Saw148015 filebench_log(LOG_ERROR, 15186212Saw148015 "flowop %s: fileset has no name", flowop->fo_name); 15196212Saw148015 return (FILEBENCH_ERROR); 15206212Saw148015 } 15216212Saw148015 15225184Sek110237 /* 1523*9326SAndrew.W.Wilson@sun.com * set the open flag for read only or read/write, as appropriate. 1524*9326SAndrew.W.Wilson@sun.com */ 1525*9326SAndrew.W.Wilson@sun.com if (avd_get_bool(flowop->fo_fileset->fs_readonly) == TRUE) 1526*9326SAndrew.W.Wilson@sun.com openflag = O_RDONLY; 1527*9326SAndrew.W.Wilson@sun.com else 1528*9326SAndrew.W.Wilson@sun.com openflag = O_RDWR; 1529*9326SAndrew.W.Wilson@sun.com 1530*9326SAndrew.W.Wilson@sun.com /* 15315184Sek110237 * If the flowop doesn't default to persistent fd 15325184Sek110237 * then get unique thread ID for use by fileset_pick 15335184Sek110237 */ 15346212Saw148015 if (avd_get_bool(flowop->fo_rotatefd)) 15355184Sek110237 tid = threadflow->tf_utid; 15365184Sek110237 15378615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr != NULL) { 15385184Sek110237 filebench_log(LOG_ERROR, 15395184Sek110237 "flowop %s attempted to open without closing on fd %d", 15405184Sek110237 flowop->fo_name, fd); 15416084Saw148015 return (FILEBENCH_ERROR); 15425184Sek110237 } 15435184Sek110237 15445673Saw148015 #ifdef HAVE_RAW_SUPPORT 15455673Saw148015 if (flowop->fo_fileset->fs_attrs & FILESET_IS_RAW_DEV) { 15465673Saw148015 int open_attrs = 0; 15475673Saw148015 char name[MAXPATHLEN]; 15485673Saw148015 15497946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(name, 15507946SAndrew.W.Wilson@sun.com avd_get_str(flowop->fo_fileset->fs_path), MAXPATHLEN); 15517946SAndrew.W.Wilson@sun.com (void) fb_strlcat(name, "/", MAXPATHLEN); 15527946SAndrew.W.Wilson@sun.com (void) fb_strlcat(name, fileset_name, MAXPATHLEN); 15535673Saw148015 15546212Saw148015 if (avd_get_bool(flowop->fo_dsync)) { 15555673Saw148015 #ifdef sun 15565673Saw148015 open_attrs |= O_DSYNC; 15575673Saw148015 #else 15585673Saw148015 open_attrs |= O_FSYNC; 15595673Saw148015 #endif 15605673Saw148015 } 15615673Saw148015 15625673Saw148015 filebench_log(LOG_DEBUG_SCRIPT, 15635673Saw148015 "open raw device %s flags %d = %d", name, open_attrs, fd); 15645673Saw148015 15658615SAndrew.W.Wilson@sun.com if (FB_OPEN(&(threadflow->tf_fd[fd]), name, 1566*9326SAndrew.W.Wilson@sun.com openflag | open_attrs, 0666) == FILEBENCH_ERROR) { 15675673Saw148015 filebench_log(LOG_ERROR, 15685673Saw148015 "Failed to open raw device %s: %s", 15695673Saw148015 name, strerror(errno)); 15706084Saw148015 return (FILEBENCH_ERROR); 15715673Saw148015 } 15725673Saw148015 15735673Saw148015 /* if running on Solaris, use un-buffered io */ 15745673Saw148015 #ifdef sun 15758615SAndrew.W.Wilson@sun.com (void) directio(threadflow->tf_fd[fd].fd_num, DIRECTIO_ON); 15765673Saw148015 #endif 15775673Saw148015 15785673Saw148015 threadflow->tf_fse[fd] = NULL; 15795673Saw148015 15806084Saw148015 return (FILEBENCH_OK); 15815673Saw148015 } 15825673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 15835673Saw148015 15848404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop, 15858404SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS, tid)) != FILEBENCH_OK) { 15866084Saw148015 filebench_log(LOG_DEBUG_SCRIPT, 15875184Sek110237 "flowop %s failed to pick file from %s on fd %d", 15886212Saw148015 flowop->fo_name, fileset_name, fd); 15898404SAndrew.W.Wilson@sun.com return (err); 15905184Sek110237 } 15915184Sek110237 15925184Sek110237 threadflow->tf_fse[fd] = file; 15935184Sek110237 15945184Sek110237 flowop_beginop(threadflow, flowop); 15958615SAndrew.W.Wilson@sun.com err = fileset_openfile(&threadflow->tf_fd[fd], flowop->fo_fileset, 1596*9326SAndrew.W.Wilson@sun.com file, openflag, 0666, flowoplib_fileattrs(flowop)); 15975673Saw148015 flowop_endop(threadflow, flowop, 0); 15985184Sek110237 15998615SAndrew.W.Wilson@sun.com if (err == FILEBENCH_ERROR) { 16006212Saw148015 filebench_log(LOG_ERROR, "flowop %s failed to open file %s", 16016212Saw148015 flowop->fo_name, file->fse_path); 16026084Saw148015 return (FILEBENCH_ERROR); 16035184Sek110237 } 16045184Sek110237 16055184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 16065184Sek110237 "flowop %s: opened %s fd[%d] = %d", 16075184Sek110237 flowop->fo_name, file->fse_path, fd, threadflow->tf_fd[fd]); 16085184Sek110237 16096084Saw148015 return (FILEBENCH_OK); 16105184Sek110237 } 16115184Sek110237 16125184Sek110237 /* 16135184Sek110237 * Emulate create of a file. Uses the flowop's fdnumber to select 16145184Sek110237 * tf_fd and tf_fse array locations to put the created file's file 16158404SAndrew.W.Wilson@sun.com * descriptor and filesetentry respectively. Uses flowoplib_pickfile() 16165184Sek110237 * to select a specific filesetentry whose file does not currently 16175184Sek110237 * exist for the file create operation. Then calls 16185184Sek110237 * fileset_openfile() with the O_CREATE flag set to create the 16196084Saw148015 * file. Returns FILEBENCH_ERROR if the array index specified by fdnumber is 16205184Sek110237 * already in use, the flowop has no associated fileset, or 16215184Sek110237 * the create call fails. Returns 1 if a filesetentry with a 16226084Saw148015 * nonexistent file cannot be found. Returns FILEBENCH_OK on success. 16235184Sek110237 */ 16245184Sek110237 static int 16255184Sek110237 flowoplib_createfile(threadflow_t *threadflow, flowop_t *flowop) 16265184Sek110237 { 16275184Sek110237 filesetentry_t *file; 16285184Sek110237 int fd = flowop->fo_fdnumber; 16298404SAndrew.W.Wilson@sun.com int err; 16305184Sek110237 16318615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr != NULL) { 16325184Sek110237 filebench_log(LOG_ERROR, 16335184Sek110237 "flowop %s attempted to create without closing on fd %d", 16345184Sek110237 flowop->fo_name, fd); 16356084Saw148015 return (FILEBENCH_ERROR); 16365184Sek110237 } 16375184Sek110237 16385184Sek110237 if (flowop->fo_fileset == NULL) { 16395184Sek110237 filebench_log(LOG_ERROR, "flowop NULL file"); 16406084Saw148015 return (FILEBENCH_ERROR); 16415184Sek110237 } 16425184Sek110237 1643*9326SAndrew.W.Wilson@sun.com if (avd_get_bool(flowop->fo_fileset->fs_readonly) == TRUE) { 1644*9326SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Can not CREATE the READONLY file %s", 1645*9326SAndrew.W.Wilson@sun.com avd_get_str(flowop->fo_fileset->fs_name)); 1646*9326SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 1647*9326SAndrew.W.Wilson@sun.com } 1648*9326SAndrew.W.Wilson@sun.com 1649*9326SAndrew.W.Wilson@sun.com 16505673Saw148015 #ifdef HAVE_RAW_SUPPORT 16515673Saw148015 /* can't be used with raw devices */ 16525673Saw148015 if (flowop->fo_fileset->fs_attrs & FILESET_IS_RAW_DEV) { 16535673Saw148015 filebench_log(LOG_ERROR, 16545673Saw148015 "flowop %s attempted to a createfile on RAW device", 16555673Saw148015 flowop->fo_name); 16566084Saw148015 return (FILEBENCH_ERROR); 16575673Saw148015 } 16585673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 16595673Saw148015 16608404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop, 16618404SAndrew.W.Wilson@sun.com FILESET_PICKNOEXIST, 0)) != FILEBENCH_OK) { 16626084Saw148015 filebench_log(LOG_DEBUG_SCRIPT, 16636084Saw148015 "flowop %s failed to pick file from fileset %s", 16646212Saw148015 flowop->fo_name, 16656212Saw148015 avd_get_str(flowop->fo_fileset->fs_name)); 16668404SAndrew.W.Wilson@sun.com return (err); 16675184Sek110237 } 16685184Sek110237 16695184Sek110237 threadflow->tf_fse[fd] = file; 16705184Sek110237 16715184Sek110237 flowop_beginop(threadflow, flowop); 16728615SAndrew.W.Wilson@sun.com err = fileset_openfile(&threadflow->tf_fd[fd], flowop->fo_fileset, 16735184Sek110237 file, O_RDWR | O_CREAT, 0666, flowoplib_fileattrs(flowop)); 16745673Saw148015 flowop_endop(threadflow, flowop, 0); 16755184Sek110237 16768615SAndrew.W.Wilson@sun.com if (err == FILEBENCH_ERROR) { 16775184Sek110237 filebench_log(LOG_ERROR, "failed to create file %s", 16785184Sek110237 flowop->fo_name); 16796084Saw148015 return (FILEBENCH_ERROR); 16805184Sek110237 } 16815184Sek110237 16825184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 16835184Sek110237 "flowop %s: created %s fd[%d] = %d", 16845184Sek110237 flowop->fo_name, file->fse_path, fd, threadflow->tf_fd[fd]); 16855184Sek110237 16866084Saw148015 return (FILEBENCH_OK); 16875184Sek110237 } 16885184Sek110237 16895184Sek110237 /* 16906391Saw148015 * Emulates delete of a file. If a valid fd is provided, it uses the 16916391Saw148015 * filesetentry stored at that fd location to select the file to be 16926391Saw148015 * deleted, otherwise it picks an arbitrary filesetentry 16936391Saw148015 * whose file exists. It then uses unlink() to delete it and Clears 16946084Saw148015 * the FSE_EXISTS flag for the filesetentry. Returns FILEBENCH_ERROR if the 16956084Saw148015 * flowop has no associated fileset. Returns FILEBENCH_NORSC if an appropriate 16966084Saw148015 * filesetentry cannot be found, and FILEBENCH_OK on success. 16975184Sek110237 */ 16985184Sek110237 static int 16995184Sek110237 flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop) 17005184Sek110237 { 17015184Sek110237 filesetentry_t *file; 17025184Sek110237 fileset_t *fileset; 17035184Sek110237 char path[MAXPATHLEN]; 17045184Sek110237 char *pathtmp; 17056391Saw148015 int fd = flowop->fo_fdnumber; 17065184Sek110237 17076391Saw148015 /* if fd specified, use it to access file */ 17086391Saw148015 if ((fd > 0) && ((file = threadflow->tf_fse[fd]) != NULL)) { 17096391Saw148015 17106391Saw148015 /* indicate that the file will be deleted */ 17116391Saw148015 threadflow->tf_fse[fd] = NULL; 17126391Saw148015 17136391Saw148015 /* if here, we still have a valid file pointer */ 17146391Saw148015 fileset = file->fse_fileset; 17156391Saw148015 } else { 17168404SAndrew.W.Wilson@sun.com 17176391Saw148015 /* Otherwise, pick arbitrary file */ 17186391Saw148015 file = NULL; 17196391Saw148015 fileset = flowop->fo_fileset; 17206391Saw148015 } 17216391Saw148015 17226391Saw148015 17236391Saw148015 if (fileset == NULL) { 17245184Sek110237 filebench_log(LOG_ERROR, "flowop NULL file"); 17256084Saw148015 return (FILEBENCH_ERROR); 17265184Sek110237 } 17275184Sek110237 17285673Saw148015 #ifdef HAVE_RAW_SUPPORT 17295673Saw148015 /* can't be used with raw devices */ 17306391Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { 17315673Saw148015 filebench_log(LOG_ERROR, 17325673Saw148015 "flowop %s attempted a deletefile on RAW device", 17335673Saw148015 flowop->fo_name); 17346084Saw148015 return (FILEBENCH_ERROR); 17355673Saw148015 } 17365673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 17375673Saw148015 17386391Saw148015 if (file == NULL) { 17398404SAndrew.W.Wilson@sun.com int err; 17408404SAndrew.W.Wilson@sun.com 17417556SAndrew.W.Wilson@sun.com /* pick arbitrary, existing (allocated) file */ 17428404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop, 17438404SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS, 0)) != FILEBENCH_OK) { 17446391Saw148015 filebench_log(LOG_DEBUG_SCRIPT, 17456391Saw148015 "flowop %s failed to pick file", flowop->fo_name); 17468404SAndrew.W.Wilson@sun.com return (err); 17476391Saw148015 } 17486391Saw148015 } else { 17497556SAndrew.W.Wilson@sun.com /* delete specific file. wait for it to be non-busy */ 17507556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 17517556SAndrew.W.Wilson@sun.com while (file->fse_flags & FSE_BUSY) { 17527556SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_THRD_WAITNG; 17537556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_thrd_wait_cv, 17547556SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 17557556SAndrew.W.Wilson@sun.com } 17567556SAndrew.W.Wilson@sun.com 17577556SAndrew.W.Wilson@sun.com /* File now available, grab it for deletion */ 17587556SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_BUSY; 17597556SAndrew.W.Wilson@sun.com fileset->fs_idle_files--; 17607556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 17615184Sek110237 } 17625184Sek110237 17638404SAndrew.W.Wilson@sun.com /* don't delete if anyone (other than me) has file open */ 17648615SAndrew.W.Wilson@sun.com if ((fd > 0) && (threadflow->tf_fd[fd].fd_num > 0)) { 17658404SAndrew.W.Wilson@sun.com if (file->fse_open_cnt > 1) { 17668404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 17678404SAndrew.W.Wilson@sun.com "flowop %s can't delete file opened by other" 17688404SAndrew.W.Wilson@sun.com " threads at fd = %d", flowop->fo_name, fd); 17698404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, 0); 17708404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 17718404SAndrew.W.Wilson@sun.com } else { 17728404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 17738404SAndrew.W.Wilson@sun.com "flowop %s deleting still open file at fd = %d", 17748404SAndrew.W.Wilson@sun.com flowop->fo_name, fd); 17758404SAndrew.W.Wilson@sun.com } 17768404SAndrew.W.Wilson@sun.com } else if (file->fse_open_cnt > 0) { 17778404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 17788404SAndrew.W.Wilson@sun.com "flowop %s can't delete file opened by other" 17798404SAndrew.W.Wilson@sun.com " threads at fd = %d, open count = %d", 17808404SAndrew.W.Wilson@sun.com flowop->fo_name, fd, file->fse_open_cnt); 17818404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, 0); 17828404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 17838404SAndrew.W.Wilson@sun.com } 17848404SAndrew.W.Wilson@sun.com 17857946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 17867946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 17877946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 17885184Sek110237 pathtmp = fileset_resolvepath(file); 17897946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 17905184Sek110237 free(pathtmp); 17915184Sek110237 17927556SAndrew.W.Wilson@sun.com /* delete the selected file */ 17935184Sek110237 flowop_beginop(threadflow, flowop); 17948615SAndrew.W.Wilson@sun.com (void) FB_UNLINK(path); 17955673Saw148015 flowop_endop(threadflow, flowop, 0); 17967556SAndrew.W.Wilson@sun.com 17977556SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy and no longer exists */ 17988404SAndrew.W.Wilson@sun.com fileset_unbusy(file, TRUE, FALSE, -file->fse_open_cnt); 17995184Sek110237 18005184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "deleted file %s", file->fse_path); 18015184Sek110237 18026084Saw148015 return (FILEBENCH_OK); 18035184Sek110237 } 18045184Sek110237 18055184Sek110237 /* 18065184Sek110237 * Emulates fsync of a file. Obtains the file descriptor index 18075184Sek110237 * from the flowop, obtains the actual file descriptor from 18085184Sek110237 * the threadflow's table, checks to be sure it is still an 18096084Saw148015 * open file, then does an fsync operation on it. Returns FILEBENCH_ERROR 18106084Saw148015 * if the file no longer is open, FILEBENCH_OK otherwise. 18115184Sek110237 */ 18125184Sek110237 static int 18135184Sek110237 flowoplib_fsync(threadflow_t *threadflow, flowop_t *flowop) 18145184Sek110237 { 18155184Sek110237 filesetentry_t *file; 18165184Sek110237 int fd = flowop->fo_fdnumber; 18175184Sek110237 18188615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr == NULL) { 18195184Sek110237 filebench_log(LOG_ERROR, 18205184Sek110237 "flowop %s attempted to fsync a closed fd %d", 18215184Sek110237 flowop->fo_name, fd); 18226084Saw148015 return (FILEBENCH_ERROR); 18235184Sek110237 } 18245184Sek110237 18255673Saw148015 file = threadflow->tf_fse[fd]; 18265673Saw148015 18275673Saw148015 if ((file == NULL) || 18285673Saw148015 (file->fse_fileset->fs_attrs & FILESET_IS_RAW_DEV)) { 18295673Saw148015 filebench_log(LOG_ERROR, 18305673Saw148015 "flowop %s attempted to a fsync a RAW device", 18315673Saw148015 flowop->fo_name); 18326084Saw148015 return (FILEBENCH_ERROR); 18335673Saw148015 } 18345673Saw148015 18355184Sek110237 /* Measure time to fsync */ 18365184Sek110237 flowop_beginop(threadflow, flowop); 18378615SAndrew.W.Wilson@sun.com (void) FB_FSYNC(&threadflow->tf_fd[fd]); 18385673Saw148015 flowop_endop(threadflow, flowop, 0); 18395184Sek110237 18405184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "fsync file %s", file->fse_path); 18415184Sek110237 18426084Saw148015 return (FILEBENCH_OK); 18435184Sek110237 } 18445184Sek110237 18455184Sek110237 /* 18465184Sek110237 * Emulate fsync of an entire fileset. Search through the 18475184Sek110237 * threadflow's file descriptor array, doing fsync() on each 18485184Sek110237 * open file that belongs to the flowop's fileset. Always 18496084Saw148015 * returns FILEBENCH_OK. 18505184Sek110237 */ 18515184Sek110237 static int 18525184Sek110237 flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop) 18535184Sek110237 { 18545184Sek110237 int fd; 18555184Sek110237 18565184Sek110237 for (fd = 0; fd < THREADFLOW_MAXFD; fd++) { 18575184Sek110237 filesetentry_t *file; 18585184Sek110237 18595184Sek110237 /* Match the file set to fsync */ 18605184Sek110237 if ((threadflow->tf_fse[fd] == NULL) || 18615184Sek110237 (flowop->fo_fileset != threadflow->tf_fse[fd]->fse_fileset)) 18625184Sek110237 continue; 18635184Sek110237 18645184Sek110237 /* Measure time to fsync */ 18655184Sek110237 flowop_beginop(threadflow, flowop); 18668615SAndrew.W.Wilson@sun.com (void) FB_FSYNC(&threadflow->tf_fd[fd]); 18675673Saw148015 flowop_endop(threadflow, flowop, 0); 18685184Sek110237 18695184Sek110237 file = threadflow->tf_fse[fd]; 18705184Sek110237 18715184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "fsync file %s", 18725184Sek110237 file->fse_path); 18735184Sek110237 } 18745184Sek110237 18756084Saw148015 return (FILEBENCH_OK); 18765184Sek110237 } 18775184Sek110237 18785184Sek110237 /* 18795184Sek110237 * Emulate close of a file. Obtains the file descriptor index 18805184Sek110237 * from the flowop, obtains the actual file descriptor from the 18815184Sek110237 * threadflow's table, checks to be sure it is still an open 18825184Sek110237 * file, then does a close operation on it. Then sets the 18835184Sek110237 * threadflow file descriptor table entry to 0, and the file set 18846084Saw148015 * entry pointer to NULL. Returns FILEBENCH_ERROR if the file was not open, 18856084Saw148015 * FILEBENCH_OK otherwise. 18865184Sek110237 */ 18875184Sek110237 static int 18885184Sek110237 flowoplib_closefile(threadflow_t *threadflow, flowop_t *flowop) 18895184Sek110237 { 18905184Sek110237 filesetentry_t *file; 18918404SAndrew.W.Wilson@sun.com fileset_t *fileset; 18925184Sek110237 int fd = flowop->fo_fdnumber; 18935184Sek110237 18948615SAndrew.W.Wilson@sun.com if (threadflow->tf_fd[fd].fd_ptr == NULL) { 18955184Sek110237 filebench_log(LOG_ERROR, 18965184Sek110237 "flowop %s attempted to close an already closed fd %d", 18975184Sek110237 flowop->fo_name, fd); 18986084Saw148015 return (FILEBENCH_ERROR); 18995184Sek110237 } 19005184Sek110237 19018404SAndrew.W.Wilson@sun.com file = threadflow->tf_fse[fd]; 19028404SAndrew.W.Wilson@sun.com fileset = file->fse_fileset; 19038404SAndrew.W.Wilson@sun.com 19048404SAndrew.W.Wilson@sun.com /* Wait for it to be non-busy */ 19058404SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 19068404SAndrew.W.Wilson@sun.com while (file->fse_flags & FSE_BUSY) { 19078404SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_THRD_WAITNG; 19088404SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_thrd_wait_cv, 19098404SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 19108404SAndrew.W.Wilson@sun.com } 19118404SAndrew.W.Wilson@sun.com 19128404SAndrew.W.Wilson@sun.com /* File now available, grab it for closing */ 19138404SAndrew.W.Wilson@sun.com file->fse_flags |= FSE_BUSY; 19148404SAndrew.W.Wilson@sun.com 19158404SAndrew.W.Wilson@sun.com /* if last open, set declare idle */ 19168404SAndrew.W.Wilson@sun.com if (file->fse_open_cnt == 1) 19178404SAndrew.W.Wilson@sun.com fileset->fs_idle_files--; 19188404SAndrew.W.Wilson@sun.com 19198404SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 19208404SAndrew.W.Wilson@sun.com 19215184Sek110237 /* Measure time to close */ 19225184Sek110237 flowop_beginop(threadflow, flowop); 19238615SAndrew.W.Wilson@sun.com (void) FB_CLOSE(&threadflow->tf_fd[fd]); 19245673Saw148015 flowop_endop(threadflow, flowop, 0); 19255184Sek110237 19268404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, -1); 19275184Sek110237 19288615SAndrew.W.Wilson@sun.com threadflow->tf_fd[fd].fd_ptr = NULL; 19295184Sek110237 19305184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "closed file %s", file->fse_path); 19315184Sek110237 19326084Saw148015 return (FILEBENCH_OK); 19335184Sek110237 } 19345184Sek110237 19355184Sek110237 /* 19367946SAndrew.W.Wilson@sun.com * Obtain the full pathname of the directory described by the filesetentry 19377946SAndrew.W.Wilson@sun.com * indicated by "dir", and copy it into the character array pointed to by 19387946SAndrew.W.Wilson@sun.com * path. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise. 19397946SAndrew.W.Wilson@sun.com */ 19407946SAndrew.W.Wilson@sun.com static int 19417946SAndrew.W.Wilson@sun.com flowoplib_getdirpath(filesetentry_t *dir, char *path) 19427946SAndrew.W.Wilson@sun.com { 19437946SAndrew.W.Wilson@sun.com char *fileset_path; 19447946SAndrew.W.Wilson@sun.com char *fileset_name; 19457946SAndrew.W.Wilson@sun.com char *part_path; 19467946SAndrew.W.Wilson@sun.com 19477946SAndrew.W.Wilson@sun.com if ((fileset_path = avd_get_str(dir->fse_fileset->fs_path)) == NULL) { 19487946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Fileset path not set"); 19497946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 19507946SAndrew.W.Wilson@sun.com } 19517946SAndrew.W.Wilson@sun.com 19527946SAndrew.W.Wilson@sun.com if ((fileset_name = avd_get_str(dir->fse_fileset->fs_name)) == NULL) { 19537946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Fileset name not set"); 19547946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 19557946SAndrew.W.Wilson@sun.com } 19567946SAndrew.W.Wilson@sun.com 19577946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, fileset_path, MAXPATHLEN); 19587946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 19597946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, fileset_name, MAXPATHLEN); 19607946SAndrew.W.Wilson@sun.com 19617946SAndrew.W.Wilson@sun.com if ((part_path = fileset_resolvepath(dir)) == NULL) 19627946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 19637946SAndrew.W.Wilson@sun.com 19647946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, part_path, MAXPATHLEN); 19657946SAndrew.W.Wilson@sun.com free(part_path); 19667946SAndrew.W.Wilson@sun.com 19677946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 19687946SAndrew.W.Wilson@sun.com } 19697946SAndrew.W.Wilson@sun.com 19707946SAndrew.W.Wilson@sun.com /* 19717946SAndrew.W.Wilson@sun.com * Use mkdir to create a directory. Obtains the fileset name from the 19727946SAndrew.W.Wilson@sun.com * flowop, selects a non-existent leaf directory and obtains its full 19737946SAndrew.W.Wilson@sun.com * path, then uses mkdir to create it on the storage subsystem (make it 19747946SAndrew.W.Wilson@sun.com * existent). Returns FILEBENCH_NORSC is there are no more non-existent 19757946SAndrew.W.Wilson@sun.com * directories in the fileset, FILEBENCH_ERROR on other errors, and 19767946SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success. 19777946SAndrew.W.Wilson@sun.com */ 19787946SAndrew.W.Wilson@sun.com static int 19797946SAndrew.W.Wilson@sun.com flowoplib_makedir(threadflow_t *threadflow, flowop_t *flowop) 19807946SAndrew.W.Wilson@sun.com { 19817946SAndrew.W.Wilson@sun.com filesetentry_t *dir; 19827946SAndrew.W.Wilson@sun.com int ret; 19837946SAndrew.W.Wilson@sun.com char full_path[MAXPATHLEN]; 19847946SAndrew.W.Wilson@sun.com 19857946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_pickleafdir(&dir, flowop, 19867946SAndrew.W.Wilson@sun.com FILESET_PICKNOEXIST)) != FILEBENCH_OK) 19877946SAndrew.W.Wilson@sun.com return (ret); 19887946SAndrew.W.Wilson@sun.com 19897946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK) 19907946SAndrew.W.Wilson@sun.com return (ret); 19917946SAndrew.W.Wilson@sun.com 19927946SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop); 19938615SAndrew.W.Wilson@sun.com (void) FB_MKDIR(full_path, 0755); 19947946SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0); 19957946SAndrew.W.Wilson@sun.com 19967946SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy and now exists */ 19978404SAndrew.W.Wilson@sun.com fileset_unbusy(dir, TRUE, TRUE, 0); 19987946SAndrew.W.Wilson@sun.com 19997946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 20007946SAndrew.W.Wilson@sun.com } 20017946SAndrew.W.Wilson@sun.com 20027946SAndrew.W.Wilson@sun.com /* 20037946SAndrew.W.Wilson@sun.com * Use rmdir to delete a directory. Obtains the fileset name from the 20047946SAndrew.W.Wilson@sun.com * flowop, selects an existent leaf directory and obtains its full path, 20057946SAndrew.W.Wilson@sun.com * then uses rmdir to remove it from the storage subsystem (make it 20067946SAndrew.W.Wilson@sun.com * non-existent). Returns FILEBENCH_NORSC is there are no more existent 20077946SAndrew.W.Wilson@sun.com * directories in the fileset, FILEBENCH_ERROR on other errors, and 20087946SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success. 20097946SAndrew.W.Wilson@sun.com */ 20107946SAndrew.W.Wilson@sun.com static int 20117946SAndrew.W.Wilson@sun.com flowoplib_removedir(threadflow_t *threadflow, flowop_t *flowop) 20127946SAndrew.W.Wilson@sun.com { 20137946SAndrew.W.Wilson@sun.com filesetentry_t *dir; 20147946SAndrew.W.Wilson@sun.com int ret; 20157946SAndrew.W.Wilson@sun.com char full_path[MAXPATHLEN]; 20167946SAndrew.W.Wilson@sun.com 20177946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_pickleafdir(&dir, flowop, 20187946SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS)) != FILEBENCH_OK) 20197946SAndrew.W.Wilson@sun.com return (ret); 20207946SAndrew.W.Wilson@sun.com 20217946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK) 20227946SAndrew.W.Wilson@sun.com return (ret); 20237946SAndrew.W.Wilson@sun.com 20247946SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop); 20258615SAndrew.W.Wilson@sun.com (void) FB_RMDIR(full_path); 20267946SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0); 20277946SAndrew.W.Wilson@sun.com 20287946SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy and no longer exists */ 20298404SAndrew.W.Wilson@sun.com fileset_unbusy(dir, TRUE, FALSE, 0); 20307946SAndrew.W.Wilson@sun.com 20317946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 20327946SAndrew.W.Wilson@sun.com } 20337946SAndrew.W.Wilson@sun.com 20347946SAndrew.W.Wilson@sun.com /* 20357946SAndrew.W.Wilson@sun.com * Use opendir(), multiple readdir() calls, and closedir() to list the 20367946SAndrew.W.Wilson@sun.com * contents of a directory. Obtains the fileset name from the 20377946SAndrew.W.Wilson@sun.com * flowop, selects a normal subdirectory (which always exist) and obtains 20387946SAndrew.W.Wilson@sun.com * its full path, then uses opendir() to get a DIR handle to it from the 20397946SAndrew.W.Wilson@sun.com * file system, a readdir() loop to access each directory entry, and 20407946SAndrew.W.Wilson@sun.com * finally cleans up with a closedir(). The latency reported is the total 20417946SAndrew.W.Wilson@sun.com * for all this activity, and it also reports the total number of bytes 20427946SAndrew.W.Wilson@sun.com * in the entries as the amount "read". Returns FILEBENCH_ERROR on errors, 20437946SAndrew.W.Wilson@sun.com * and FILEBENCH_OK on success. 20447946SAndrew.W.Wilson@sun.com */ 20457946SAndrew.W.Wilson@sun.com static int 20467946SAndrew.W.Wilson@sun.com flowoplib_listdir(threadflow_t *threadflow, flowop_t *flowop) 20477946SAndrew.W.Wilson@sun.com { 20487946SAndrew.W.Wilson@sun.com fileset_t *fileset; 20497946SAndrew.W.Wilson@sun.com filesetentry_t *dir; 20508615SAndrew.W.Wilson@sun.com DIR *dir_handle; 20517946SAndrew.W.Wilson@sun.com struct dirent *direntp; 20527946SAndrew.W.Wilson@sun.com int dir_bytes = 0; 20537946SAndrew.W.Wilson@sun.com int ret; 20547946SAndrew.W.Wilson@sun.com char full_path[MAXPATHLEN]; 20557946SAndrew.W.Wilson@sun.com 20567946SAndrew.W.Wilson@sun.com if ((fileset = flowop->fo_fileset) == NULL) { 20577946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "flowop NO fileset"); 20587946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 20597946SAndrew.W.Wilson@sun.com } 20607946SAndrew.W.Wilson@sun.com 20618404SAndrew.W.Wilson@sun.com if ((dir = fileset_pick(fileset, FILESET_PICKDIR, 0, 0)) == NULL) { 20627946SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 20637946SAndrew.W.Wilson@sun.com "flowop %s failed to pick directory from fileset %s", 20647946SAndrew.W.Wilson@sun.com flowop->fo_name, 20657946SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name)); 20668404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 20677946SAndrew.W.Wilson@sun.com } 20687946SAndrew.W.Wilson@sun.com 20697946SAndrew.W.Wilson@sun.com if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK) 20707946SAndrew.W.Wilson@sun.com return (ret); 20717946SAndrew.W.Wilson@sun.com 20727946SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop); 20737946SAndrew.W.Wilson@sun.com 20747946SAndrew.W.Wilson@sun.com /* open the directory */ 20758615SAndrew.W.Wilson@sun.com if ((dir_handle = FB_OPENDIR(full_path)) == NULL) { 20767946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 20777946SAndrew.W.Wilson@sun.com "flowop %s failed to open directory in fileset %s\n", 20787946SAndrew.W.Wilson@sun.com flowop->fo_name, avd_get_str(fileset->fs_name)); 20797946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 20807946SAndrew.W.Wilson@sun.com } 20817946SAndrew.W.Wilson@sun.com 20827946SAndrew.W.Wilson@sun.com /* read through the directory entries */ 20838615SAndrew.W.Wilson@sun.com while ((direntp = FB_READDIR(dir_handle)) != NULL) { 20847946SAndrew.W.Wilson@sun.com dir_bytes += (strlen(direntp->d_name) + 20857946SAndrew.W.Wilson@sun.com sizeof (struct dirent) - 1); 20867946SAndrew.W.Wilson@sun.com } 20877946SAndrew.W.Wilson@sun.com 20887946SAndrew.W.Wilson@sun.com /* close the directory */ 20898615SAndrew.W.Wilson@sun.com (void) FB_CLOSEDIR(dir_handle); 20907946SAndrew.W.Wilson@sun.com 20917946SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, dir_bytes); 20927946SAndrew.W.Wilson@sun.com 20937946SAndrew.W.Wilson@sun.com /* indicate that it is no longer busy */ 20948404SAndrew.W.Wilson@sun.com fileset_unbusy(dir, FALSE, FALSE, 0); 20957946SAndrew.W.Wilson@sun.com 20967946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 20977946SAndrew.W.Wilson@sun.com } 20987946SAndrew.W.Wilson@sun.com 20997946SAndrew.W.Wilson@sun.com /* 21005184Sek110237 * Emulate stat of a file. Picks an arbitrary filesetentry with 21015184Sek110237 * an existing file from the flowop's fileset, then performs a 21026084Saw148015 * stat() operation on it. Returns FILEBENCH_ERROR if the flowop has no 21036084Saw148015 * associated fileset. Returns FILEBENCH_NORSC if an appropriate filesetentry 21046084Saw148015 * cannot be found, and FILEBENCH_OK on success. 21055184Sek110237 */ 21065184Sek110237 static int 21075184Sek110237 flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop) 21085184Sek110237 { 21095184Sek110237 filesetentry_t *file; 21105184Sek110237 fileset_t *fileset; 21118615SAndrew.W.Wilson@sun.com struct stat64 statbuf; 21127556SAndrew.W.Wilson@sun.com int fd = flowop->fo_fdnumber; 21137556SAndrew.W.Wilson@sun.com 21147556SAndrew.W.Wilson@sun.com /* if fd specified and the file is open, use it to access file */ 21158615SAndrew.W.Wilson@sun.com if ((fd > 0) && (threadflow->tf_fd[fd].fd_num > 0)) { 21167556SAndrew.W.Wilson@sun.com 21177556SAndrew.W.Wilson@sun.com /* check whether file handle still valid */ 21187556SAndrew.W.Wilson@sun.com if ((file = threadflow->tf_fse[fd]) == NULL) { 21197556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 21207556SAndrew.W.Wilson@sun.com "flowop %s trying to stat NULL file at fd = %d", 21217556SAndrew.W.Wilson@sun.com flowop->fo_name, fd); 21227556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 21237556SAndrew.W.Wilson@sun.com } 21247556SAndrew.W.Wilson@sun.com 21257556SAndrew.W.Wilson@sun.com /* if here, we still have a valid file pointer */ 21267556SAndrew.W.Wilson@sun.com fileset = file->fse_fileset; 21277556SAndrew.W.Wilson@sun.com } else { 21287556SAndrew.W.Wilson@sun.com /* Otherwise, pick arbitrary file */ 21297556SAndrew.W.Wilson@sun.com file = NULL; 21307556SAndrew.W.Wilson@sun.com fileset = flowop->fo_fileset; 21317556SAndrew.W.Wilson@sun.com } 21327556SAndrew.W.Wilson@sun.com 21337556SAndrew.W.Wilson@sun.com if (fileset == NULL) { 21347556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 21357556SAndrew.W.Wilson@sun.com "statfile with no fileset specified"); 21367556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 21377556SAndrew.W.Wilson@sun.com } 21387556SAndrew.W.Wilson@sun.com 21397556SAndrew.W.Wilson@sun.com #ifdef HAVE_RAW_SUPPORT 21407556SAndrew.W.Wilson@sun.com /* can't be used with raw devices */ 21417556SAndrew.W.Wilson@sun.com if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { 21427556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 21437556SAndrew.W.Wilson@sun.com "flowop %s attempted do a statfile on a RAW device", 21447556SAndrew.W.Wilson@sun.com flowop->fo_name); 21456084Saw148015 return (FILEBENCH_ERROR); 21465184Sek110237 } 21477556SAndrew.W.Wilson@sun.com #endif /* HAVE_RAW_SUPPORT */ 21487556SAndrew.W.Wilson@sun.com 21497556SAndrew.W.Wilson@sun.com if (file == NULL) { 21507556SAndrew.W.Wilson@sun.com char path[MAXPATHLEN]; 21517556SAndrew.W.Wilson@sun.com char *pathtmp; 21528404SAndrew.W.Wilson@sun.com int err; 21537556SAndrew.W.Wilson@sun.com 21547556SAndrew.W.Wilson@sun.com /* pick arbitrary, existing (allocated) file */ 21558404SAndrew.W.Wilson@sun.com if ((err = flowoplib_pickfile(&file, flowop, 21568404SAndrew.W.Wilson@sun.com FILESET_PICKEXISTS, 0)) != FILEBENCH_OK) { 21577556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, 21587556SAndrew.W.Wilson@sun.com "Statfile flowop %s failed to pick file", 21597556SAndrew.W.Wilson@sun.com flowop->fo_name); 21608404SAndrew.W.Wilson@sun.com return (err); 21617556SAndrew.W.Wilson@sun.com } 21627556SAndrew.W.Wilson@sun.com 21637556SAndrew.W.Wilson@sun.com /* resolve path and do a stat on file */ 21647946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), 21657946SAndrew.W.Wilson@sun.com MAXPATHLEN); 21667946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 21677946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), 21687946SAndrew.W.Wilson@sun.com MAXPATHLEN); 21697556SAndrew.W.Wilson@sun.com pathtmp = fileset_resolvepath(file); 21707946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 21717556SAndrew.W.Wilson@sun.com free(pathtmp); 21727556SAndrew.W.Wilson@sun.com 21737556SAndrew.W.Wilson@sun.com /* stat the file */ 21747556SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop); 21758615SAndrew.W.Wilson@sun.com if (FB_STAT(path, &statbuf) == -1) 21767556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 21777556SAndrew.W.Wilson@sun.com "statfile flowop %s failed", flowop->fo_name); 21787556SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0); 21797556SAndrew.W.Wilson@sun.com 21808404SAndrew.W.Wilson@sun.com fileset_unbusy(file, FALSE, FALSE, 0); 21817556SAndrew.W.Wilson@sun.com } else { 21827556SAndrew.W.Wilson@sun.com /* stat specific file */ 21837556SAndrew.W.Wilson@sun.com flowop_beginop(threadflow, flowop); 21848615SAndrew.W.Wilson@sun.com if (FB_FSTAT(&threadflow->tf_fd[fd], &statbuf) == -1) 21857556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 21867556SAndrew.W.Wilson@sun.com "statfile flowop %s failed", flowop->fo_name); 21877556SAndrew.W.Wilson@sun.com flowop_endop(threadflow, flowop, 0); 21887556SAndrew.W.Wilson@sun.com 21895184Sek110237 } 21905184Sek110237 21916084Saw148015 return (FILEBENCH_OK); 21925184Sek110237 } 21935184Sek110237 21945184Sek110237 21955184Sek110237 /* 21965184Sek110237 * Additional reads and writes. Read and write whole files, write 21975184Sek110237 * and append to files. Some of these work with both fileobjs and 21985184Sek110237 * filesets, others only with filesets. The flowoplib_write routine 21995184Sek110237 * writes from thread memory, while the others read or write using 22005184Sek110237 * fo_buf memory. Note that both flowoplib_read() and 22015184Sek110237 * flowoplib_aiowrite() use thread memory as well. 22025184Sek110237 */ 22035184Sek110237 22045184Sek110237 22055184Sek110237 /* 22065673Saw148015 * Emulate a read of a whole file. The file must be open with 22075673Saw148015 * file descriptor and filesetentry stored at the locations indexed 22085673Saw148015 * by the flowop's fdnumber. It then seeks to the beginning of the 22095673Saw148015 * associated file, and reads fs_iosize bytes at a time until the end 22106084Saw148015 * of the file. Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if 22116084Saw148015 * out of files, and FILEBENCH_OK on success. 22125184Sek110237 */ 22135184Sek110237 static int 22145184Sek110237 flowoplib_readwholefile(threadflow_t *threadflow, flowop_t *flowop) 22155184Sek110237 { 22165673Saw148015 caddr_t iobuf; 22175184Sek110237 off64_t bytes = 0; 22188615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc; 22196212Saw148015 uint64_t wss; 22206212Saw148015 fbint_t iosize; 22215184Sek110237 int ret; 22226212Saw148015 char zerordbuf; 22235184Sek110237 22245673Saw148015 /* get the file to use */ 22256084Saw148015 if ((ret = flowoplib_filesetup(threadflow, flowop, &wss, 22268615SAndrew.W.Wilson@sun.com &fdesc)) != FILEBENCH_OK) 22276084Saw148015 return (ret); 22285184Sek110237 22295673Saw148015 /* an I/O size of zero means read entire working set with one I/O */ 22306212Saw148015 if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) 22315673Saw148015 iosize = wss; 22325184Sek110237 22336212Saw148015 /* 22346212Saw148015 * The file may actually be 0 bytes long, in which case skip 22356212Saw148015 * the buffer set up call (which would fail) and substitute 22366212Saw148015 * a small buffer, which won't really be used. 22376212Saw148015 */ 22386212Saw148015 if (iosize == 0) { 22396212Saw148015 iobuf = (caddr_t)&zerordbuf; 22406212Saw148015 filebench_log(LOG_DEBUG_SCRIPT, 22416212Saw148015 "flowop %s read zero length file", flowop->fo_name); 22426212Saw148015 } else { 22436212Saw148015 if (flowoplib_iobufsetup(threadflow, flowop, &iobuf, 22446212Saw148015 iosize) != 0) 22456212Saw148015 return (FILEBENCH_ERROR); 22466212Saw148015 } 22475184Sek110237 22485184Sek110237 /* Measure time to read bytes */ 22495184Sek110237 flowop_beginop(threadflow, flowop); 22508615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_SET); 22518615SAndrew.W.Wilson@sun.com while ((ret = FB_READ(fdesc, iobuf, iosize)) > 0) 22525184Sek110237 bytes += ret; 22535184Sek110237 22545673Saw148015 flowop_endop(threadflow, flowop, bytes); 22555184Sek110237 22565184Sek110237 if (ret < 0) { 22575184Sek110237 filebench_log(LOG_ERROR, 22586391Saw148015 "readwhole fail Failed to read whole file: %s", 22596391Saw148015 strerror(errno)); 22606084Saw148015 return (FILEBENCH_ERROR); 22615184Sek110237 } 22625184Sek110237 22636084Saw148015 return (FILEBENCH_OK); 22645184Sek110237 } 22655184Sek110237 22665184Sek110237 /* 22675184Sek110237 * Emulate a write to a file of size fo_iosize. Will write 22685184Sek110237 * to a file from a fileset if the flowop's fo_fileset field 22695184Sek110237 * specifies one or its fdnumber is non zero. Otherwise it 22705184Sek110237 * will write to a fileobj file, if one exists. If the file 22715184Sek110237 * is not currently open, the routine will attempt to open 22725184Sek110237 * it. The flowop's fo_wss parameter will be used to set the 22735184Sek110237 * maximum file size if it is non-zero, otherwise the 22745184Sek110237 * filesetentry's fse_size will be used. A random memory 22755184Sek110237 * buffer offset is calculated, and, if fo_random is TRUE, 22765184Sek110237 * a random file offset is used for the write. Otherwise the 22776084Saw148015 * write is to the next sequential location. Returns 22786084Saw148015 * FILEBENCH_ERROR on errors, FILEBENCH_NORSC if iosetup can't 22796084Saw148015 * obtain a file, or FILEBENCH_OK on success. 22805184Sek110237 */ 22815184Sek110237 static int 22825184Sek110237 flowoplib_write(threadflow_t *threadflow, flowop_t *flowop) 22835184Sek110237 { 22845673Saw148015 caddr_t iobuf; 22856212Saw148015 fbint_t wss; 22866212Saw148015 fbint_t iosize; 22878615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc; 22886084Saw148015 int ret; 22895184Sek110237 22906212Saw148015 iosize = avd_get_int(flowop->fo_iosize); 22916084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, 22928615SAndrew.W.Wilson@sun.com &fdesc, iosize)) != FILEBENCH_OK) 22936084Saw148015 return (ret); 22945184Sek110237 22956212Saw148015 if (avd_get_bool(flowop->fo_random)) { 22965184Sek110237 uint64_t fileoffset; 22975184Sek110237 22985184Sek110237 if (filebench_randomno64(&fileoffset, 22996212Saw148015 wss, iosize, NULL) == -1) { 23005184Sek110237 filebench_log(LOG_ERROR, 23015184Sek110237 "file size smaller than IO size for thread %s", 23025184Sek110237 flowop->fo_name); 23036084Saw148015 return (FILEBENCH_ERROR); 23045184Sek110237 } 23055184Sek110237 flowop_beginop(threadflow, flowop); 23068615SAndrew.W.Wilson@sun.com if (FB_PWRITE(fdesc, iobuf, 23076212Saw148015 iosize, (off64_t)fileoffset) == -1) { 23085184Sek110237 filebench_log(LOG_ERROR, "write failed, " 23096286Saw148015 "offset %llu io buffer %zd: %s", 23106286Saw148015 (u_longlong_t)fileoffset, iobuf, strerror(errno)); 23115673Saw148015 flowop_endop(threadflow, flowop, 0); 23126084Saw148015 return (FILEBENCH_ERROR); 23135184Sek110237 } 23146212Saw148015 flowop_endop(threadflow, flowop, iosize); 23155184Sek110237 } else { 23165184Sek110237 flowop_beginop(threadflow, flowop); 23178615SAndrew.W.Wilson@sun.com if (FB_WRITE(fdesc, iobuf, iosize) == -1) { 23185184Sek110237 filebench_log(LOG_ERROR, 23195673Saw148015 "write failed, io buffer %zd: %s", 23205673Saw148015 iobuf, strerror(errno)); 23215673Saw148015 flowop_endop(threadflow, flowop, 0); 23226084Saw148015 return (FILEBENCH_ERROR); 23235184Sek110237 } 23246212Saw148015 flowop_endop(threadflow, flowop, iosize); 23255184Sek110237 } 23265184Sek110237 23276084Saw148015 return (FILEBENCH_OK); 23285184Sek110237 } 23295184Sek110237 23305184Sek110237 /* 23315184Sek110237 * Emulate a write of a whole file. The size of the file 23325673Saw148015 * is taken from a filesetentry identified by fo_srcfdnumber or 23335673Saw148015 * from the working set size, while the file descriptor used is 23345673Saw148015 * identified by fo_fdnumber. Does multiple writes of fo_iosize 23356084Saw148015 * length length until full file has been written. Returns FILEBENCH_ERROR on 23366084Saw148015 * error, FILEBENCH_NORSC if out of files, FILEBENCH_OK on success. 23375184Sek110237 */ 23385184Sek110237 static int 23395184Sek110237 flowoplib_writewholefile(threadflow_t *threadflow, flowop_t *flowop) 23405184Sek110237 { 23415673Saw148015 caddr_t iobuf; 23425184Sek110237 filesetentry_t *file; 23435184Sek110237 int wsize; 23445184Sek110237 off64_t seek; 23455184Sek110237 off64_t bytes = 0; 23465673Saw148015 uint64_t wss; 23476212Saw148015 fbint_t iosize; 23488615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc; 23495184Sek110237 int srcfd = flowop->fo_srcfdnumber; 23505184Sek110237 int ret; 23516212Saw148015 char zerowrtbuf; 23525184Sek110237 23535673Saw148015 /* get the file to use */ 23546084Saw148015 if ((ret = flowoplib_filesetup(threadflow, flowop, &wss, 23558615SAndrew.W.Wilson@sun.com &fdesc)) != FILEBENCH_OK) 23566084Saw148015 return (ret); 23575184Sek110237 23586212Saw148015 /* an I/O size of zero means write entire working set with one I/O */ 23596212Saw148015 if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) 23605673Saw148015 iosize = wss; 23615184Sek110237 23626212Saw148015 /* 23636212Saw148015 * The file may actually be 0 bytes long, in which case skip 23646212Saw148015 * the buffer set up call (which would fail) and substitute 23656212Saw148015 * a small buffer, which won't really be used. 23666212Saw148015 */ 23676212Saw148015 if (iosize == 0) { 23686212Saw148015 iobuf = (caddr_t)&zerowrtbuf; 23696212Saw148015 filebench_log(LOG_DEBUG_SCRIPT, 23706212Saw148015 "flowop %s wrote zero length file", flowop->fo_name); 23716212Saw148015 } else { 23726212Saw148015 if (flowoplib_iobufsetup(threadflow, flowop, &iobuf, 23736212Saw148015 iosize) != 0) 23746212Saw148015 return (FILEBENCH_ERROR); 23756212Saw148015 } 23765184Sek110237 23775184Sek110237 file = threadflow->tf_fse[srcfd]; 23785673Saw148015 if ((srcfd != 0) && (file == NULL)) { 23795673Saw148015 filebench_log(LOG_ERROR, "flowop %s: NULL src file", 23805184Sek110237 flowop->fo_name); 23816084Saw148015 return (FILEBENCH_ERROR); 23825184Sek110237 } 23835184Sek110237 23845673Saw148015 if (file) 23855673Saw148015 wss = file->fse_size; 23865673Saw148015 23875673Saw148015 wsize = (int)MIN(wss, iosize); 23885184Sek110237 23895184Sek110237 /* Measure time to write bytes */ 23905184Sek110237 flowop_beginop(threadflow, flowop); 23915673Saw148015 for (seek = 0; seek < wss; seek += wsize) { 23928615SAndrew.W.Wilson@sun.com ret = FB_WRITE(fdesc, iobuf, wsize); 23935184Sek110237 if (ret != wsize) { 23945184Sek110237 filebench_log(LOG_ERROR, 23955184Sek110237 "Failed to write %d bytes on fd %d: %s", 23968615SAndrew.W.Wilson@sun.com wsize, fdesc->fd_num, strerror(errno)); 23975673Saw148015 flowop_endop(threadflow, flowop, 0); 23986084Saw148015 return (FILEBENCH_ERROR); 23995184Sek110237 } 24005673Saw148015 wsize = (int)MIN(wss - seek, iosize); 24015184Sek110237 bytes += ret; 24025184Sek110237 } 24035673Saw148015 flowop_endop(threadflow, flowop, bytes); 24045184Sek110237 24056084Saw148015 return (FILEBENCH_OK); 24065184Sek110237 } 24075184Sek110237 24085184Sek110237 24095184Sek110237 /* 24105184Sek110237 * Emulate a fixed size append to a file. Will append data to 24115184Sek110237 * a file chosen from a fileset if the flowop's fo_fileset 24125184Sek110237 * field specifies one or if its fdnumber is non zero. 24135184Sek110237 * Otherwise it will write to a fileobj file, if one exists. 24145184Sek110237 * The flowop's fo_wss parameter will be used to set the 24155184Sek110237 * maximum file size if it is non-zero, otherwise the 24165184Sek110237 * filesetentry's fse_size will be used. A random memory 24175184Sek110237 * buffer offset is calculated, then a logical seek to the 24185184Sek110237 * end of file is done followed by a write of fo_iosize 24195184Sek110237 * bytes. Writes are actually done from fo_buf, rather than 24205184Sek110237 * tf_mem as is done with flowoplib_write(), and no check 24215184Sek110237 * is made to see if fo_iosize exceeds the size of fo_buf. 24226084Saw148015 * Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if out of 24236084Saw148015 * files in the fileset, FILEBENCH_OK on success. 24245184Sek110237 */ 24255184Sek110237 static int 24265184Sek110237 flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop) 24275184Sek110237 { 24285673Saw148015 caddr_t iobuf; 24298615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc; 24306212Saw148015 fbint_t wss; 24316212Saw148015 fbint_t iosize; 24325184Sek110237 int ret; 24335184Sek110237 24346212Saw148015 iosize = avd_get_int(flowop->fo_iosize); 24356084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, 24368615SAndrew.W.Wilson@sun.com &fdesc, iosize)) != FILEBENCH_OK) 24376084Saw148015 return (ret); 24385184Sek110237 24395184Sek110237 /* XXX wss is not being used */ 24405184Sek110237 24415184Sek110237 /* Measure time to write bytes */ 24425184Sek110237 flowop_beginop(threadflow, flowop); 24438615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_END); 24448615SAndrew.W.Wilson@sun.com ret = FB_WRITE(fdesc, iobuf, iosize); 24455673Saw148015 if (ret != iosize) { 24465184Sek110237 filebench_log(LOG_ERROR, 24476286Saw148015 "Failed to write %llu bytes on fd %d: %s", 24488615SAndrew.W.Wilson@sun.com (u_longlong_t)iosize, fdesc->fd_num, strerror(errno)); 24496212Saw148015 flowop_endop(threadflow, flowop, ret); 24506084Saw148015 return (FILEBENCH_ERROR); 24515184Sek110237 } 24526212Saw148015 flowop_endop(threadflow, flowop, ret); 24535184Sek110237 24546084Saw148015 return (FILEBENCH_OK); 24555184Sek110237 } 24565184Sek110237 24575184Sek110237 /* 24585184Sek110237 * Emulate a random size append to a file. Will append data 24595184Sek110237 * to a file chosen from a fileset if the flowop's fo_fileset 24605184Sek110237 * field specifies one or if its fdnumber is non zero. Otherwise 24615184Sek110237 * it will write to a fileobj file, if one exists. The flowop's 24625184Sek110237 * fo_wss parameter will be used to set the maximum file size 24635184Sek110237 * if it is non-zero, otherwise the filesetentry's fse_size 24645184Sek110237 * will be used. A random transfer size (but at most fo_iosize 24655184Sek110237 * bytes) and a random memory offset are calculated. A logical 24665184Sek110237 * seek to the end of file is done, then writes of up to 24675184Sek110237 * FILE_ALLOC_BLOCK in size are done until the full transfer 24685184Sek110237 * size has been written. Writes are actually done from fo_buf, 24695184Sek110237 * rather than tf_mem as is done with flowoplib_write(). 24706084Saw148015 * Returns FILEBENCH_ERROR on error, FILEBENCH_NORSC if out of 24716084Saw148015 * files in the fileset, FILEBENCH_OK on success. 24725184Sek110237 */ 24735184Sek110237 static int 24745184Sek110237 flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop) 24755184Sek110237 { 24765673Saw148015 caddr_t iobuf; 24775184Sek110237 uint64_t appendsize; 24788615SAndrew.W.Wilson@sun.com fb_fdesc_t *fdesc; 24796212Saw148015 fbint_t wss; 24806212Saw148015 fbint_t iosize; 24816212Saw148015 int ret = 0; 24825184Sek110237 24836212Saw148015 if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) { 24846212Saw148015 filebench_log(LOG_ERROR, "zero iosize for flowop %s", 24856212Saw148015 flowop->fo_name); 24866212Saw148015 return (FILEBENCH_ERROR); 24876212Saw148015 } 24886212Saw148015 24896212Saw148015 if (filebench_randomno64(&appendsize, iosize, 1LL, NULL) != 0) 24906084Saw148015 return (FILEBENCH_ERROR); 24915184Sek110237 24925673Saw148015 /* skip if attempting zero length append */ 24935673Saw148015 if (appendsize == 0) { 24945673Saw148015 flowop_beginop(threadflow, flowop); 24955673Saw148015 flowop_endop(threadflow, flowop, 0LL); 24966084Saw148015 return (FILEBENCH_OK); 24975673Saw148015 } 24985184Sek110237 24996084Saw148015 if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, 25008615SAndrew.W.Wilson@sun.com &fdesc, appendsize)) != FILEBENCH_OK) 25016084Saw148015 return (ret); 25025673Saw148015 25035184Sek110237 /* XXX wss is not being used */ 25045184Sek110237 25055673Saw148015 /* Measure time to write bytes */ 25065673Saw148015 flowop_beginop(threadflow, flowop); 25075673Saw148015 25088615SAndrew.W.Wilson@sun.com (void) FB_LSEEK(fdesc, 0, SEEK_END); 25098615SAndrew.W.Wilson@sun.com ret = FB_WRITE(fdesc, iobuf, appendsize); 25105673Saw148015 if (ret != appendsize) { 25115673Saw148015 filebench_log(LOG_ERROR, 25126286Saw148015 "Failed to write %llu bytes on fd %d: %s", 25138615SAndrew.W.Wilson@sun.com (u_longlong_t)appendsize, fdesc->fd_num, strerror(errno)); 25145673Saw148015 flowop_endop(threadflow, flowop, 0); 25156084Saw148015 return (FILEBENCH_ERROR); 25165184Sek110237 } 25175184Sek110237 25185673Saw148015 flowop_endop(threadflow, flowop, appendsize); 25195184Sek110237 25206084Saw148015 return (FILEBENCH_OK); 25215184Sek110237 } 25225184Sek110237 25236212Saw148015 typedef struct testrandvar_priv { 25246212Saw148015 uint64_t sample_count; 25256212Saw148015 double val_sum; 25266212Saw148015 double sqr_sum; 25276212Saw148015 } testrandvar_priv_t; 25286212Saw148015 25296212Saw148015 /* 25306212Saw148015 * flowop to calculate various statistics from the number stream 25316212Saw148015 * produced by a random variable. This allows verification that the 25326212Saw148015 * random distribution used to define the random variable is producing 25336212Saw148015 * the expected distribution of random numbers. 25346212Saw148015 */ 25356212Saw148015 /* ARGSUSED */ 25366212Saw148015 static int 25376212Saw148015 flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop) 25386212Saw148015 { 25396212Saw148015 testrandvar_priv_t *mystats; 25406212Saw148015 double value; 25416212Saw148015 25426212Saw148015 if ((mystats = (testrandvar_priv_t *)flowop->fo_private) == NULL) { 25436212Saw148015 filebench_log(LOG_ERROR, "testrandvar not initialized\n"); 25446212Saw148015 filebench_shutdown(1); 25456212Saw148015 return (-1); 25466212Saw148015 } 25476212Saw148015 25486212Saw148015 value = avd_get_dbl(flowop->fo_value); 25496212Saw148015 25506212Saw148015 mystats->sample_count++; 25516212Saw148015 mystats->val_sum += value; 25526212Saw148015 mystats->sqr_sum += (value * value); 25536212Saw148015 25546212Saw148015 return (0); 25556212Saw148015 } 25566212Saw148015 25576212Saw148015 /* 25586212Saw148015 * Initialize the private data area used to accumulate the statistics 25596212Saw148015 */ 25606212Saw148015 static int 25616212Saw148015 flowoplib_testrandvar_init(flowop_t *flowop) 25626212Saw148015 { 25636212Saw148015 testrandvar_priv_t *mystats; 25646212Saw148015 25656212Saw148015 if ((mystats = (testrandvar_priv_t *) 25666212Saw148015 malloc(sizeof (testrandvar_priv_t))) == NULL) { 25676212Saw148015 filebench_log(LOG_ERROR, "could not initialize testrandvar"); 25686212Saw148015 filebench_shutdown(1); 25696212Saw148015 return (-1); 25706212Saw148015 } 25716212Saw148015 25726212Saw148015 mystats->sample_count = 0; 25736212Saw148015 mystats->val_sum = 0; 25746212Saw148015 mystats->sqr_sum = 0; 25756212Saw148015 flowop->fo_private = (void *)mystats; 25766212Saw148015 25776212Saw148015 (void) ipc_mutex_unlock(&flowop->fo_lock); 25786212Saw148015 return (0); 25796212Saw148015 } 25806212Saw148015 25816212Saw148015 /* 25826212Saw148015 * Print out the accumulated statistics, and free the private storage 25836212Saw148015 */ 25846212Saw148015 static void 25856212Saw148015 flowoplib_testrandvar_destruct(flowop_t *flowop) 25866212Saw148015 { 25876212Saw148015 testrandvar_priv_t *mystats; 25886212Saw148015 double mean, std_dev, dbl_count; 25896212Saw148015 25906212Saw148015 (void) ipc_mutex_lock(&flowop->fo_lock); 25916212Saw148015 if ((mystats = (testrandvar_priv_t *) 25926212Saw148015 flowop->fo_private) == NULL) { 25936212Saw148015 (void) ipc_mutex_unlock(&flowop->fo_lock); 25946212Saw148015 return; 25956212Saw148015 } 25966212Saw148015 25976212Saw148015 flowop->fo_private = NULL; 25986212Saw148015 (void) ipc_mutex_unlock(&flowop->fo_lock); 25996212Saw148015 26006212Saw148015 dbl_count = (double)mystats->sample_count; 26016212Saw148015 mean = mystats->val_sum / dbl_count; 26026212Saw148015 std_dev = sqrt((mystats->sqr_sum / dbl_count) - (mean * mean)) / mean; 26036212Saw148015 26046212Saw148015 filebench_log(LOG_VERBOSE, 26056286Saw148015 "testrandvar: ops = %llu, mean = %8.2lf, stddev = %8.2lf", 26066286Saw148015 (u_longlong_t)mystats->sample_count, mean, std_dev); 26076212Saw148015 free(mystats); 26086212Saw148015 } 26095184Sek110237 26105184Sek110237 /* 26117556SAndrew.W.Wilson@sun.com * prints message to the console from within a thread 26127556SAndrew.W.Wilson@sun.com */ 26137556SAndrew.W.Wilson@sun.com static int 26147556SAndrew.W.Wilson@sun.com flowoplib_print(threadflow_t *threadflow, flowop_t *flowop) 26157556SAndrew.W.Wilson@sun.com { 26167556SAndrew.W.Wilson@sun.com procflow_t *procflow; 26177556SAndrew.W.Wilson@sun.com 26187556SAndrew.W.Wilson@sun.com procflow = threadflow->tf_process; 26197556SAndrew.W.Wilson@sun.com filebench_log(LOG_INFO, 26207556SAndrew.W.Wilson@sun.com "Message from process (%s,%d), thread (%s,%d): %s", 26217556SAndrew.W.Wilson@sun.com procflow->pf_name, procflow->pf_instance, 26227556SAndrew.W.Wilson@sun.com threadflow->tf_name, threadflow->tf_instance, 26237556SAndrew.W.Wilson@sun.com avd_get_str(flowop->fo_value)); 26247556SAndrew.W.Wilson@sun.com 26257556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 26267556SAndrew.W.Wilson@sun.com } 26277556SAndrew.W.Wilson@sun.com 26287556SAndrew.W.Wilson@sun.com /* 26295184Sek110237 * Prints usage information for flowop operations. 26305184Sek110237 */ 26315184Sek110237 void 26325184Sek110237 flowoplib_usage() 26335184Sek110237 { 26345184Sek110237 (void) fprintf(stderr, 26355184Sek110237 "flowop [openfile|createfile] name=<name>,fileset=<fname>\n"); 26365184Sek110237 (void) fprintf(stderr, 26375184Sek110237 " [,fd=<file desc num>]\n"); 26385184Sek110237 (void) fprintf(stderr, "\n"); 26395184Sek110237 (void) fprintf(stderr, 26405184Sek110237 "flowop closefile name=<name>,fd=<file desc num>]\n"); 26415184Sek110237 (void) fprintf(stderr, "\n"); 26425184Sek110237 (void) fprintf(stderr, "flowop deletefile name=<name>\n"); 26435184Sek110237 (void) fprintf(stderr, " [,fileset=<fname>]\n"); 26445184Sek110237 (void) fprintf(stderr, 26455184Sek110237 " [,fd=<file desc num>]\n"); 26465184Sek110237 (void) fprintf(stderr, "\n"); 26475184Sek110237 (void) fprintf(stderr, "flowop statfile name=<name>\n"); 26485184Sek110237 (void) fprintf(stderr, " [,fileset=<fname>]\n"); 26495184Sek110237 (void) fprintf(stderr, 26505184Sek110237 " [,fd=<file desc num>]\n"); 26515184Sek110237 (void) fprintf(stderr, "\n"); 26525184Sek110237 (void) fprintf(stderr, 26535184Sek110237 "flowop fsync name=<name>,fd=<file desc num>]\n"); 26545184Sek110237 (void) fprintf(stderr, "\n"); 26555184Sek110237 (void) fprintf(stderr, 26565184Sek110237 "flowop fsyncset name=<name>,fileset=<fname>]\n"); 26575184Sek110237 (void) fprintf(stderr, "\n"); 26585184Sek110237 (void) fprintf(stderr, "flowop [write|read|aiowrite] name=<name>, \n"); 26595184Sek110237 (void) fprintf(stderr, 26605184Sek110237 " filename|fileset=<fname>,\n"); 26615184Sek110237 (void) fprintf(stderr, " iosize=<size>\n"); 26625184Sek110237 (void) fprintf(stderr, " [,directio]\n"); 26635184Sek110237 (void) fprintf(stderr, " [,dsync]\n"); 26645184Sek110237 (void) fprintf(stderr, " [,iters=<count>]\n"); 26655184Sek110237 (void) fprintf(stderr, " [,random]\n"); 26665184Sek110237 (void) fprintf(stderr, " [,opennext]\n"); 26675184Sek110237 (void) fprintf(stderr, " [,workingset=<size>]\n"); 26685184Sek110237 (void) fprintf(stderr, 26695184Sek110237 "flowop [appendfile|appendfilerand] name=<name>, \n"); 26705184Sek110237 (void) fprintf(stderr, 26715184Sek110237 " filename|fileset=<fname>,\n"); 26725184Sek110237 (void) fprintf(stderr, " iosize=<size>\n"); 26735184Sek110237 (void) fprintf(stderr, " [,dsync]\n"); 26745184Sek110237 (void) fprintf(stderr, " [,iters=<count>]\n"); 26755184Sek110237 (void) fprintf(stderr, " [,workingset=<size>]\n"); 26765184Sek110237 (void) fprintf(stderr, 26775184Sek110237 "flowop [readwholefile|writewholefile] name=<name>, \n"); 26785184Sek110237 (void) fprintf(stderr, 26795184Sek110237 " filename|fileset=<fname>,\n"); 26805184Sek110237 (void) fprintf(stderr, " iosize=<size>\n"); 26815184Sek110237 (void) fprintf(stderr, " [,dsync]\n"); 26825184Sek110237 (void) fprintf(stderr, " [,iters=<count>]\n"); 26835184Sek110237 (void) fprintf(stderr, "\n"); 26845184Sek110237 (void) fprintf(stderr, "flowop aiowait name=<name>,target=" 26855184Sek110237 "<aiowrite-flowop>\n"); 26865184Sek110237 (void) fprintf(stderr, "\n"); 26875184Sek110237 (void) fprintf(stderr, "flowop sempost name=<name>," 26885184Sek110237 "target=<semblock-flowop>,\n"); 26895184Sek110237 (void) fprintf(stderr, 26905184Sek110237 " value=<increment-to-post>\n"); 26915184Sek110237 (void) fprintf(stderr, "\n"); 26925184Sek110237 (void) fprintf(stderr, "flowop semblock name=<name>,value=" 26935184Sek110237 "<decrement-to-receive>,\n"); 26945184Sek110237 (void) fprintf(stderr, " highwater=" 26955184Sek110237 "<inbound-queue-max>\n"); 26965184Sek110237 (void) fprintf(stderr, "\n"); 26975184Sek110237 (void) fprintf(stderr, "flowop block name=<name>\n"); 26985184Sek110237 (void) fprintf(stderr, "\n"); 26995184Sek110237 (void) fprintf(stderr, 27005184Sek110237 "flowop wakeup name=<name>,target=<block-flowop>,\n"); 27015184Sek110237 (void) fprintf(stderr, "\n"); 27025184Sek110237 (void) fprintf(stderr, 27035184Sek110237 "flowop hog name=<name>,value=<number-of-mem-ops>\n"); 27045184Sek110237 (void) fprintf(stderr, 27055184Sek110237 "flowop delay name=<name>,value=<number-of-seconds>\n"); 27065184Sek110237 (void) fprintf(stderr, "\n"); 27075184Sek110237 (void) fprintf(stderr, "flowop eventlimit name=<name>\n"); 27085184Sek110237 (void) fprintf(stderr, "flowop bwlimit name=<name>,value=<mb/s>\n"); 27095184Sek110237 (void) fprintf(stderr, "flowop iopslimit name=<name>,value=<iop/s>\n"); 27105184Sek110237 (void) fprintf(stderr, 27115184Sek110237 "flowop finishoncount name=<name>,value=<ops/s>\n"); 27125184Sek110237 (void) fprintf(stderr, 27135184Sek110237 "flowop finishonbytes name=<name>,value=<bytes>\n"); 27145184Sek110237 (void) fprintf(stderr, "\n"); 27155184Sek110237 (void) fprintf(stderr, "\n"); 27165184Sek110237 } 2717