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