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 <fcntl.h> 29 5184 ek110237 #include <pthread.h> 30 5184 ek110237 #include <errno.h> 31 5184 ek110237 #include <math.h> 32 5184 ek110237 #include <libgen.h> 33 5184 ek110237 #include <sys/mman.h> 34 8404 Andrew #include <sys/shm.h> 35 6613 ek110237 36 6613 ek110237 #include "filebench.h" 37 5184 ek110237 #include "fileset.h" 38 5184 ek110237 #include "gamma_dist.h" 39 7946 Andrew #include "utils.h" 40 8615 Andrew #include "fsplug.h" 41 5184 ek110237 42 5184 ek110237 /* 43 5184 ek110237 * File sets, of type fileset_t, are entities which contain 44 5184 ek110237 * information about collections of files and subdirectories in Filebench. 45 5184 ek110237 * The fileset, once populated, consists of a tree of fileset entries of 46 5184 ek110237 * type filesetentry_t which specify files and directories. The fileset 47 6212 aw148015 * is rooted in a directory specified by fileset_path, and once the populated 48 5184 ek110237 * fileset has been created, has a tree of directories and files 49 5184 ek110237 * corresponding to the fileset's filesetentry tree. 50 6701 aw148015 * 51 7556 Andrew * Fileset entities are allocated by fileset_define() which is called from 52 7556 Andrew * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding 53 7556 Andrew * to the eventual directory and file tree to be instantiated on the storage 54 7946 Andrew * medium is built by fileset_populate(), which is This routine is called 55 7946 Andrew * from fileset_createset(), which is in turn called by fileset_createset(). 56 7946 Andrew * After calling fileset_populate(), fileset_createset() will call 57 7946 Andrew * fileset_create() to pre-allocate designated files and directories. 58 7556 Andrew * 59 7556 Andrew * Fileset_createset() is called from parser_gram.y: parser_create_fileset() 60 7556 Andrew * when a "create fileset" or "run" command is encountered. When the 61 7556 Andrew * "create fileset" command is used, it is generally paired with 62 6701 aw148015 * a "create processes" command, and must appear first, in order to 63 6701 aw148015 * instantiate all the files in the fileset before trying to use them. 64 5184 ek110237 */ 65 6305 aw148015 66 6305 aw148015 static int fileset_checkraw(fileset_t *fileset); 67 5673 aw148015 68 7556 Andrew /* maximum parallel allocation control */ 69 5673 aw148015 #define MAX_PARALLOC_THREADS 32 70 5673 aw148015 71 5673 aw148015 /* 72 5673 aw148015 * returns pointer to file or fileset 73 5673 aw148015 * string, as appropriate 74 5673 aw148015 */ 75 5673 aw148015 static char * 76 5673 aw148015 fileset_entity_name(fileset_t *fileset) 77 5673 aw148015 { 78 5673 aw148015 if (fileset->fs_attrs & FILESET_IS_FILE) 79 5673 aw148015 return ("file"); 80 5673 aw148015 else 81 5673 aw148015 return ("fileset"); 82 5673 aw148015 } 83 5184 ek110237 84 5184 ek110237 /* 85 5184 ek110237 * Removes the last file or directory name from a pathname. 86 5184 ek110237 * Basically removes characters from the end of the path by 87 5184 ek110237 * setting them to \0 until a forward slash '/' is 88 5184 ek110237 * encountered. It also removes the forward slash. 89 5184 ek110237 */ 90 5184 ek110237 static char * 91 5184 ek110237 trunc_dirname(char *dir) 92 5184 ek110237 { 93 5184 ek110237 char *s = dir + strlen(dir); 94 5184 ek110237 95 5184 ek110237 while (s != dir) { 96 5184 ek110237 int c = *s; 97 5184 ek110237 98 5184 ek110237 *s = 0; 99 5184 ek110237 if (c == '/') 100 5184 ek110237 break; 101 5184 ek110237 s--; 102 5184 ek110237 } 103 5184 ek110237 return (dir); 104 5184 ek110237 } 105 5184 ek110237 106 5184 ek110237 /* 107 5184 ek110237 * Prints a list of allowed options and how to specify them. 108 5184 ek110237 */ 109 5184 ek110237 void 110 5184 ek110237 fileset_usage(void) 111 5184 ek110237 { 112 5673 aw148015 (void) fprintf(stderr, 113 5673 aw148015 "define [file name=<name> | fileset name=<name>],path=<pathname>," 114 5673 aw148015 ",entries=<number>\n"); 115 5673 aw148015 (void) fprintf(stderr, 116 6212 aw148015 " [,filesize=[size]]\n"); 117 6212 aw148015 (void) fprintf(stderr, 118 5673 aw148015 " [,dirwidth=[width]]\n"); 119 6212 aw148015 (void) fprintf(stderr, 120 6212 aw148015 " [,dirdepthrv=$random_variable_name]\n"); 121 5673 aw148015 (void) fprintf(stderr, 122 5673 aw148015 " [,dirgamma=[100-10000]] " 123 5184 ek110237 "(Gamma * 1000)\n"); 124 5184 ek110237 (void) fprintf(stderr, 125 5673 aw148015 " [,sizegamma=[100-10000]] (Gamma * 1000)\n"); 126 5184 ek110237 (void) fprintf(stderr, 127 5184 ek110237 " [,prealloc=[percent]]\n"); 128 5673 aw148015 (void) fprintf(stderr, " [,paralloc]\n"); 129 5184 ek110237 (void) fprintf(stderr, " [,reuse]\n"); 130 5184 ek110237 (void) fprintf(stderr, "\n"); 131 5184 ek110237 } 132 5184 ek110237 133 5184 ek110237 /* 134 5184 ek110237 * Creates a path string from the filesetentry_t "*entry" 135 5184 ek110237 * and all of its parent's path names. The resulting path 136 5184 ek110237 * is a concatination of all the individual parent paths. 137 5184 ek110237 * Allocates memory for the path string and returns a 138 5184 ek110237 * pointer to it. 139 5184 ek110237 */ 140 5184 ek110237 char * 141 5184 ek110237 fileset_resolvepath(filesetentry_t *entry) 142 5184 ek110237 { 143 5184 ek110237 filesetentry_t *fsep = entry; 144 5184 ek110237 char path[MAXPATHLEN]; 145 5184 ek110237 char pathtmp[MAXPATHLEN]; 146 5184 ek110237 char *s; 147 5184 ek110237 148 7946 Andrew path[0] = '\0'; 149 5184 ek110237 while (fsep->fse_parent) { 150 5184 ek110237 (void) strcpy(pathtmp, "/"); 151 7946 Andrew (void) fb_strlcat(pathtmp, fsep->fse_path, MAXPATHLEN); 152 7946 Andrew (void) fb_strlcat(pathtmp, path, MAXPATHLEN); 153 7946 Andrew (void) fb_strlcpy(path, pathtmp, MAXPATHLEN); 154 5184 ek110237 fsep = fsep->fse_parent; 155 5184 ek110237 } 156 5184 ek110237 157 5184 ek110237 s = malloc(strlen(path) + 1); 158 7946 Andrew (void) fb_strlcpy(s, path, MAXPATHLEN); 159 5184 ek110237 return (s); 160 5184 ek110237 } 161 5184 ek110237 162 5184 ek110237 /* 163 5184 ek110237 * Creates multiple nested directories as required by the 164 5184 ek110237 * supplied path. Starts at the end of the path, creating 165 5184 ek110237 * a list of directories to mkdir, up to the root of the 166 5184 ek110237 * path, then mkdirs them one at a time from the root on down. 167 5184 ek110237 */ 168 5184 ek110237 static int 169 5184 ek110237 fileset_mkdir(char *path, int mode) 170 5184 ek110237 { 171 5184 ek110237 char *p; 172 5184 ek110237 char *dirs[65536]; 173 5184 ek110237 int i = 0; 174 5184 ek110237 175 5184 ek110237 if ((p = strdup(path)) == NULL) 176 5184 ek110237 goto null_str; 177 5184 ek110237 178 5184 ek110237 /* 179 5184 ek110237 * Fill an array of subdirectory path names until either we 180 5184 ek110237 * reach the root or encounter an already existing subdirectory 181 5184 ek110237 */ 182 5184 ek110237 /* CONSTCOND */ 183 5184 ek110237 while (1) { 184 5184 ek110237 struct stat64 sb; 185 5184 ek110237 186 5184 ek110237 if (stat64(p, &sb) == 0) 187 5184 ek110237 break; 188 5184 ek110237 if (strlen(p) < 3) 189 5184 ek110237 break; 190 5184 ek110237 if ((dirs[i] = strdup(p)) == NULL) { 191 5184 ek110237 free(p); 192 5184 ek110237 goto null_str; 193 5184 ek110237 } 194 5184 ek110237 195 5184 ek110237 (void) trunc_dirname(p); 196 5184 ek110237 i++; 197 5184 ek110237 } 198 5184 ek110237 199 5184 ek110237 /* Make the directories, from closest to root downwards. */ 200 5184 ek110237 for (--i; i >= 0; i--) { 201 8615 Andrew (void) FB_MKDIR(dirs[i], mode); 202 5184 ek110237 free(dirs[i]); 203 5184 ek110237 } 204 5184 ek110237 205 5184 ek110237 free(p); 206 7556 Andrew return (FILEBENCH_OK); 207 5184 ek110237 208 5184 ek110237 null_str: 209 5184 ek110237 /* clean up */ 210 5184 ek110237 for (--i; i >= 0; i--) 211 5184 ek110237 free(dirs[i]); 212 5184 ek110237 213 5184 ek110237 filebench_log(LOG_ERROR, 214 5184 ek110237 "Failed to create directory path %s: Out of memory", path); 215 7556 Andrew return (FILEBENCH_ERROR); 216 5673 aw148015 } 217 5673 aw148015 218 5673 aw148015 /* 219 5673 aw148015 * creates the subdirectory tree for a fileset. 220 5673 aw148015 */ 221 5673 aw148015 static int 222 5673 aw148015 fileset_create_subdirs(fileset_t *fileset, char *filesetpath) 223 5673 aw148015 { 224 5673 aw148015 filesetentry_t *direntry; 225 5673 aw148015 char full_path[MAXPATHLEN]; 226 5673 aw148015 char *part_path; 227 5673 aw148015 228 5673 aw148015 /* walk the subdirectory list, enstanciating subdirs */ 229 5673 aw148015 direntry = fileset->fs_dirlist; 230 5673 aw148015 while (direntry) { 231 7946 Andrew (void) fb_strlcpy(full_path, filesetpath, MAXPATHLEN); 232 5673 aw148015 part_path = fileset_resolvepath(direntry); 233 7946 Andrew (void) fb_strlcat(full_path, part_path, MAXPATHLEN); 234 5673 aw148015 free(part_path); 235 5673 aw148015 236 5673 aw148015 /* now create this portion of the subdirectory tree */ 237 7556 Andrew if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR) 238 7556 Andrew return (FILEBENCH_ERROR); 239 5673 aw148015 240 8404 Andrew direntry = direntry->fse_nextoftype; 241 5673 aw148015 } 242 7556 Andrew return (FILEBENCH_OK); 243 8404 Andrew } 244 8404 Andrew 245 8404 Andrew /* 246 8404 Andrew * move filesetentry between exist tree and non-exist tree, source_tree 247 8404 Andrew * to destination tree. 248 8404 Andrew */ 249 8404 Andrew static void 250 8404 Andrew fileset_move_entry(avl_tree_t *src_tree, avl_tree_t *dst_tree, 251 8404 Andrew filesetentry_t *entry) 252 8404 Andrew { 253 8404 Andrew avl_remove(src_tree, entry); 254 8404 Andrew avl_add(dst_tree, entry); 255 5673 aw148015 } 256 5673 aw148015 257 5673 aw148015 /* 258 7946 Andrew * given a fileset entry, determines if the associated leaf directory 259 7946 Andrew * needs to be made or not, and if so does the mkdir. 260 7946 Andrew */ 261 7946 Andrew static int 262 7946 Andrew fileset_alloc_leafdir(filesetentry_t *entry) 263 7946 Andrew { 264 7946 Andrew fileset_t *fileset; 265 7946 Andrew char path[MAXPATHLEN]; 266 7946 Andrew struct stat64 sb; 267 7946 Andrew char *pathtmp; 268 7946 Andrew 269 7946 Andrew fileset = entry->fse_fileset; 270 7946 Andrew (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 271 7946 Andrew (void) fb_strlcat(path, "/", MAXPATHLEN); 272 7946 Andrew (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 273 7946 Andrew pathtmp = fileset_resolvepath(entry); 274 7946 Andrew (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 275 7946 Andrew free(pathtmp); 276 7946 Andrew 277 7946 Andrew filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); 278 7946 Andrew 279 7946 Andrew /* see if not reusing and this directory does not exist */ 280 7946 Andrew if (!((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0))) { 281 7946 Andrew 282 7946 Andrew /* No file or not reusing, so create */ 283 8615 Andrew if (FB_MKDIR(path, 0755) < 0) { 284 7946 Andrew filebench_log(LOG_ERROR, 285 7946 Andrew "Failed to pre-allocate leaf directory %s: %s", 286 7946 Andrew path, strerror(errno)); 287 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 288 7946 Andrew return (FILEBENCH_ERROR); 289 7946 Andrew } 290 7946 Andrew } 291 7946 Andrew 292 8404 Andrew /* unbusy the allocated entry */ 293 8404 Andrew fileset_unbusy(entry, TRUE, TRUE, 0); 294 7946 Andrew return (FILEBENCH_OK); 295 7946 Andrew } 296 7946 Andrew 297 7946 Andrew /* 298 5673 aw148015 * given a fileset entry, determines if the associated file 299 5673 aw148015 * needs to be allocated or not, and if so does the allocation. 300 5673 aw148015 */ 301 5673 aw148015 static int 302 5673 aw148015 fileset_alloc_file(filesetentry_t *entry) 303 5673 aw148015 { 304 7946 Andrew fileset_t *fileset; 305 5673 aw148015 char path[MAXPATHLEN]; 306 5673 aw148015 char *buf; 307 5673 aw148015 struct stat64 sb; 308 5673 aw148015 char *pathtmp; 309 5673 aw148015 off64_t seek; 310 8615 Andrew fb_fdesc_t fdesc; 311 9326 Andrew int trust_tree; 312 5673 aw148015 313 7946 Andrew fileset = entry->fse_fileset; 314 7946 Andrew (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 315 7946 Andrew (void) fb_strlcat(path, "/", MAXPATHLEN); 316 7946 Andrew (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 317 5673 aw148015 pathtmp = fileset_resolvepath(entry); 318 7946 Andrew (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 319 7946 Andrew free(pathtmp); 320 5673 aw148015 321 5673 aw148015 filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); 322 5673 aw148015 323 5673 aw148015 /* see if reusing and this file exists */ 324 9326 Andrew trust_tree = avd_get_bool(fileset->fs_trust_tree); 325 9326 Andrew if ((entry->fse_flags & FSE_REUSING) && (trust_tree || 326 9326 Andrew (FB_STAT(path, &sb) == 0))) { 327 8615 Andrew if (FB_OPEN(&fdesc, path, O_RDWR, 0) == FILEBENCH_ERROR) { 328 5673 aw148015 filebench_log(LOG_INFO, 329 5673 aw148015 "Attempted but failed to Re-use file %s", 330 5673 aw148015 path); 331 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 332 7556 Andrew return (FILEBENCH_ERROR); 333 5673 aw148015 } 334 5673 aw148015 335 9326 Andrew if (trust_tree || (sb.st_size == (off64_t)entry->fse_size)) { 336 7556 Andrew filebench_log(LOG_DEBUG_IMPL, 337 5673 aw148015 "Re-using file %s", path); 338 5673 aw148015 339 7946 Andrew if (!avd_get_bool(fileset->fs_cached)) 340 8615 Andrew (void) FB_FREEMEM(&fdesc, entry->fse_size); 341 5673 aw148015 342 8615 Andrew (void) FB_CLOSE(&fdesc); 343 6701 aw148015 344 8404 Andrew /* unbusy the allocated entry */ 345 8404 Andrew fileset_unbusy(entry, TRUE, TRUE, 0); 346 7556 Andrew return (FILEBENCH_OK); 347 5673 aw148015 348 5673 aw148015 } else if (sb.st_size > (off64_t)entry->fse_size) { 349 5673 aw148015 /* reuse, but too large */ 350 8404 Andrew filebench_log(LOG_DEBUG_IMPL, 351 5673 aw148015 "Truncating & re-using file %s", path); 352 5673 aw148015 353 8615 Andrew (void) FB_FTRUNC(&fdesc, (off64_t)entry->fse_size); 354 5673 aw148015 355 7946 Andrew if (!avd_get_bool(fileset->fs_cached)) 356 8615 Andrew (void) FB_FREEMEM(&fdesc, entry->fse_size); 357 5673 aw148015 358 8615 Andrew (void) FB_CLOSE(&fdesc); 359 6701 aw148015 360 8404 Andrew /* unbusy the allocated entry */ 361 8404 Andrew fileset_unbusy(entry, TRUE, TRUE, 0); 362 7556 Andrew return (FILEBENCH_OK); 363 5673 aw148015 } 364 5673 aw148015 } else { 365 5673 aw148015 366 5673 aw148015 /* No file or not reusing, so create */ 367 8615 Andrew if (FB_OPEN(&fdesc, path, O_RDWR | O_CREAT, 0644) == 368 8615 Andrew FILEBENCH_ERROR) { 369 5673 aw148015 filebench_log(LOG_ERROR, 370 5673 aw148015 "Failed to pre-allocate file %s: %s", 371 5673 aw148015 path, strerror(errno)); 372 5673 aw148015 373 8404 Andrew /* unbusy the unallocated entry */ 374 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 375 7556 Andrew return (FILEBENCH_ERROR); 376 5673 aw148015 } 377 5673 aw148015 } 378 5673 aw148015 379 8404 Andrew if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) { 380 8404 Andrew /* unbusy the unallocated entry */ 381 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 382 7556 Andrew return (FILEBENCH_ERROR); 383 8404 Andrew } 384 5673 aw148015 385 5673 aw148015 for (seek = 0; seek < entry->fse_size; ) { 386 5673 aw148015 off64_t wsize; 387 5673 aw148015 int ret = 0; 388 5673 aw148015 389 5673 aw148015 /* 390 5673 aw148015 * Write FILE_ALLOC_BLOCK's worth, 391 5673 aw148015 * except on last write 392 5673 aw148015 */ 393 5673 aw148015 wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK); 394 5673 aw148015 395 8615 Andrew ret = FB_WRITE(&fdesc, buf, wsize); 396 5673 aw148015 if (ret != wsize) { 397 5673 aw148015 filebench_log(LOG_ERROR, 398 5673 aw148015 "Failed to pre-allocate file %s: %s", 399 5673 aw148015 path, strerror(errno)); 400 8615 Andrew (void) FB_CLOSE(&fdesc); 401 5673 aw148015 free(buf); 402 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 403 7556 Andrew return (FILEBENCH_ERROR); 404 5673 aw148015 } 405 5673 aw148015 seek += wsize; 406 5673 aw148015 } 407 5673 aw148015 408 7946 Andrew if (!avd_get_bool(fileset->fs_cached)) 409 8615 Andrew (void) FB_FREEMEM(&fdesc, entry->fse_size); 410 5673 aw148015 411 8615 Andrew (void) FB_CLOSE(&fdesc); 412 5673 aw148015 413 5673 aw148015 free(buf); 414 8404 Andrew 415 8404 Andrew /* unbusy the allocated entry */ 416 8404 Andrew fileset_unbusy(entry, TRUE, TRUE, 0); 417 5673 aw148015 418 5673 aw148015 filebench_log(LOG_DEBUG_IMPL, 419 6286 aw148015 "Pre-allocated file %s size %llu", 420 6286 aw148015 path, (u_longlong_t)entry->fse_size); 421 5673 aw148015 422 7556 Andrew return (FILEBENCH_OK); 423 5673 aw148015 } 424 5673 aw148015 425 5673 aw148015 /* 426 5673 aw148015 * given a fileset entry, determines if the associated file 427 5673 aw148015 * needs to be allocated or not, and if so does the allocation. 428 7556 Andrew * Sets shm_fsparalloc_count to -1 on error. 429 5673 aw148015 */ 430 5673 aw148015 static void * 431 5673 aw148015 fileset_alloc_thread(filesetentry_t *entry) 432 5673 aw148015 { 433 7556 Andrew if (fileset_alloc_file(entry) == FILEBENCH_ERROR) { 434 7556 Andrew (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 435 7556 Andrew filebench_shm->shm_fsparalloc_count = -1; 436 5673 aw148015 } else { 437 7556 Andrew (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 438 7556 Andrew filebench_shm->shm_fsparalloc_count--; 439 5673 aw148015 } 440 5673 aw148015 441 7556 Andrew (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv); 442 7556 Andrew (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); 443 5673 aw148015 444 5673 aw148015 pthread_exit(NULL); 445 5673 aw148015 return (NULL); 446 5184 ek110237 } 447 5184 ek110237 448 5184 ek110237 449 5184 ek110237 /* 450 5184 ek110237 * First creates the parent directories of the file using 451 5184 ek110237 * fileset_mkdir(). Then Optionally sets the O_DSYNC flag 452 5184 ek110237 * and opens the file with open64(). It unlocks the fileset 453 5184 ek110237 * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags 454 5184 ek110237 * as requested, and returns the file descriptor integer 455 8615 Andrew * for the opened file in the supplied filebench file descriptor. 456 8615 Andrew * Returns FILEBENCH_ERROR on error, and FILEBENCH_OK on success. 457 5184 ek110237 */ 458 5184 ek110237 int 459 8615 Andrew fileset_openfile(fb_fdesc_t *fdesc, fileset_t *fileset, 460 7736 Andrew filesetentry_t *entry, int flag, int filemode, int attrs) 461 5184 ek110237 { 462 5184 ek110237 char path[MAXPATHLEN]; 463 5184 ek110237 char dir[MAXPATHLEN]; 464 5184 ek110237 char *pathtmp; 465 5184 ek110237 struct stat64 sb; 466 5184 ek110237 int open_attrs = 0; 467 5184 ek110237 468 7946 Andrew (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 469 7946 Andrew (void) fb_strlcat(path, "/", MAXPATHLEN); 470 7946 Andrew (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 471 5184 ek110237 pathtmp = fileset_resolvepath(entry); 472 7946 Andrew (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 473 7946 Andrew (void) fb_strlcpy(dir, path, MAXPATHLEN); 474 5184 ek110237 free(pathtmp); 475 5184 ek110237 (void) trunc_dirname(dir); 476 5184 ek110237 477 5184 ek110237 /* If we are going to create a file, create the parent dirs */ 478 5184 ek110237 if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) { 479 7556 Andrew if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR) 480 7556 Andrew return (FILEBENCH_ERROR); 481 6701 aw148015 } 482 5184 ek110237 483 5184 ek110237 if (attrs & FLOW_ATTR_DSYNC) { 484 5184 ek110237 #ifdef sun 485 5184 ek110237 open_attrs |= O_DSYNC; 486 5184 ek110237 #else 487 5184 ek110237 open_attrs |= O_FSYNC; 488 5184 ek110237 #endif 489 5184 ek110237 } 490 5184 ek110237 491 8615 Andrew if (FB_OPEN(fdesc, path, flag | open_attrs, filemode) 492 8615 Andrew == FILEBENCH_ERROR) { 493 5184 ek110237 filebench_log(LOG_ERROR, 494 8404 Andrew "Failed to open file %d, %s, with status %x: %s", 495 8404 Andrew entry->fse_index, path, entry->fse_flags, strerror(errno)); 496 7556 Andrew 497 8404 Andrew fileset_unbusy(entry, FALSE, FALSE, 0); 498 7556 Andrew return (FILEBENCH_ERROR); 499 5184 ek110237 } 500 7556 Andrew 501 7556 Andrew if (flag & O_CREAT) 502 8404 Andrew fileset_unbusy(entry, TRUE, TRUE, 1); 503 7556 Andrew else 504 8404 Andrew fileset_unbusy(entry, FALSE, FALSE, 1); 505 5184 ek110237 506 5184 ek110237 #ifdef sun 507 5184 ek110237 if (attrs & FLOW_ATTR_DIRECTIO) 508 8615 Andrew (void) directio(fdesc->fd_num, DIRECTIO_ON); 509 5184 ek110237 else 510 8615 Andrew (void) directio(fdesc->fd_num, DIRECTIO_OFF); 511 5184 ek110237 #endif 512 5184 ek110237 513 8615 Andrew return (FILEBENCH_OK); 514 5184 ek110237 } 515 5184 ek110237 516 8404 Andrew /* 517 8404 Andrew * removes all filesetentries from their respective btrees, and puts them 518 8404 Andrew * on the free list. The supplied argument indicates which free list to 519 8404 Andrew * use. 520 8404 Andrew */ 521 8404 Andrew static void 522 8404 Andrew fileset_pickreset(fileset_t *fileset, int entry_type) 523 8404 Andrew { 524 8404 Andrew filesetentry_t *entry; 525 8404 Andrew 526 8404 Andrew switch (entry_type & FILESET_PICKMASK) { 527 8404 Andrew case FILESET_PICKFILE: 528 8404 Andrew entry = (filesetentry_t *)avl_first(&fileset->fs_noex_files); 529 8404 Andrew 530 8404 Andrew /* make sure non-existing files are marked free */ 531 8404 Andrew while (entry) { 532 8404 Andrew entry->fse_flags |= FSE_FREE; 533 8404 Andrew entry->fse_open_cnt = 0; 534 8404 Andrew fileset_move_entry(&fileset->fs_noex_files, 535 8404 Andrew &fileset->fs_free_files, entry); 536 8404 Andrew entry = AVL_NEXT(&fileset->fs_noex_files, entry); 537 8404 Andrew } 538 8404 Andrew 539 8404 Andrew /* free up any existing files */ 540 8404 Andrew entry = (filesetentry_t *)avl_first(&fileset->fs_exist_files); 541 8404 Andrew 542 8404 Andrew while (entry) { 543 8404 Andrew entry->fse_flags |= FSE_FREE; 544 8404 Andrew entry->fse_open_cnt = 0; 545 8404 Andrew fileset_move_entry(&fileset->fs_exist_files, 546 8404 Andrew &fileset->fs_free_files, entry); 547 8404 Andrew 548 8404 Andrew entry = AVL_NEXT(&fileset->fs_exist_files, entry); 549 8404 Andrew } 550 8404 Andrew 551 8404 Andrew break; 552 8404 Andrew 553 8404 Andrew case FILESET_PICKDIR: 554 8404 Andrew /* nothing to reset, as all (sub)dirs always exist */ 555 8404 Andrew break; 556 8404 Andrew 557 8404 Andrew case FILESET_PICKLEAFDIR: 558 8404 Andrew entry = (filesetentry_t *) 559 8404 Andrew avl_first(&fileset->fs_noex_leaf_dirs); 560 8404 Andrew 561 8404 Andrew /* make sure non-existing leaf dirs are marked free */ 562 8404 Andrew while (entry) { 563 8404 Andrew entry->fse_flags |= FSE_FREE; 564 8404 Andrew entry->fse_open_cnt = 0; 565 8404 Andrew fileset_move_entry(&fileset->fs_noex_leaf_dirs, 566 8404 Andrew &fileset->fs_free_leaf_dirs, entry); 567 8404 Andrew entry = AVL_NEXT(&fileset->fs_noex_leaf_dirs, entry); 568 8404 Andrew } 569 8404 Andrew 570 8404 Andrew /* free up any existing leaf dirs */ 571 8404 Andrew entry = (filesetentry_t *) 572 8404 Andrew avl_first(&fileset->fs_exist_leaf_dirs); 573 8404 Andrew 574 8404 Andrew while (entry) { 575 8404 Andrew entry->fse_flags |= FSE_FREE; 576 8404 Andrew entry->fse_open_cnt = 0; 577 8404 Andrew fileset_move_entry(&fileset->fs_exist_leaf_dirs, 578 8404 Andrew &fileset->fs_free_leaf_dirs, entry); 579 8404 Andrew 580 8404 Andrew entry = AVL_NEXT(&fileset->fs_exist_leaf_dirs, entry); 581 8404 Andrew } 582 8404 Andrew 583 8404 Andrew break; 584 8404 Andrew } 585 8404 Andrew } 586 8404 Andrew 587 8404 Andrew /* 588 8404 Andrew * find a filesetentry from the fileset using the supplied index 589 8404 Andrew */ 590 8404 Andrew static filesetentry_t * 591 8404 Andrew fileset_find_entry(avl_tree_t *atp, uint_t index) 592 8404 Andrew { 593 8404 Andrew avl_index_t found_loc; 594 8404 Andrew filesetentry_t desired_fse, *found_fse; 595 8404 Andrew 596 8404 Andrew /* find the file with the desired index, if it is in the tree */ 597 8404 Andrew desired_fse.fse_index = index; 598 8404 Andrew found_fse = avl_find(atp, (void *)(&desired_fse), &found_loc); 599 8404 Andrew if (found_fse != NULL) 600 8404 Andrew return (found_fse); 601 8404 Andrew 602 8404 Andrew /* if requested node not found, find next higher node */ 603 8404 Andrew found_fse = avl_nearest(atp, found_loc, AVL_AFTER); 604 8404 Andrew if (found_fse != NULL) 605 8404 Andrew return (found_fse); 606 8404 Andrew 607 8404 Andrew /* might have hit the end, return lowest available index node */ 608 8404 Andrew found_fse = avl_first(atp); 609 8404 Andrew return (found_fse); 610 8404 Andrew } 611 5184 ek110237 612 5184 ek110237 /* 613 5184 ek110237 * Selects a fileset entry from a fileset. If the 614 7946 Andrew * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry, 615 7946 Andrew * if the FILESET_PICKDIR flag is set it will pick a non leaf directory 616 8404 Andrew * entry, otherwise a file entry. The FILESET_PICKUNIQUE 617 5184 ek110237 * flag will take an entry off of one of the free (unused) 618 5184 ek110237 * lists (file or directory), otherwise the entry will be 619 5184 ek110237 * picked off of one of the rotor lists (file or directory). 620 5184 ek110237 * The FILESET_PICKEXISTS will insure that only extant 621 5184 ek110237 * (FSE_EXISTS) state files are selected, while 622 5184 ek110237 * FILESET_PICKNOEXIST insures that only non extant 623 5184 ek110237 * (not FSE_EXISTS) state files are selected. 624 6391 aw148015 * Note that the selected fileset entry (file) is returned 625 7556 Andrew * with its FSE_BUSY flag (in fse_flags) set. 626 5184 ek110237 */ 627 5184 ek110237 filesetentry_t * 628 8404 Andrew fileset_pick(fileset_t *fileset, int flags, int tid, int index) 629 5184 ek110237 { 630 5184 ek110237 filesetentry_t *entry = NULL; 631 8404 Andrew filesetentry_t *start_point; 632 8404 Andrew avl_tree_t *atp; 633 8404 Andrew fbint_t max_entries; 634 5184 ek110237 635 7556 Andrew (void) ipc_mutex_lock(&fileset->fs_pick_lock); 636 7556 Andrew 637 7556 Andrew /* see if we have to wait for available files or directories */ 638 7946 Andrew switch (flags & FILESET_PICKMASK) { 639 7946 Andrew case FILESET_PICKFILE: 640 7946 Andrew if (fileset->fs_filelist == NULL) 641 7946 Andrew goto empty; 642 8404 Andrew 643 7946 Andrew while (fileset->fs_idle_files == 0) { 644 7946 Andrew (void) pthread_cond_wait(&fileset->fs_idle_files_cv, 645 7946 Andrew &fileset->fs_pick_lock); 646 7946 Andrew } 647 8404 Andrew 648 8404 Andrew max_entries = fileset->fs_constentries; 649 8404 Andrew if (flags & FILESET_PICKUNIQUE) { 650 8404 Andrew atp = &fileset->fs_free_files; 651 8404 Andrew } else if (flags & FILESET_PICKNOEXIST) { 652 8404 Andrew atp = &fileset->fs_noex_files; 653 8404 Andrew } else { 654 8404 Andrew atp = &fileset->fs_exist_files; 655 8404 Andrew } 656 7946 Andrew break; 657 8404 Andrew 658 7946 Andrew case FILESET_PICKDIR: 659 7946 Andrew if (fileset->fs_dirlist == NULL) 660 7946 Andrew goto empty; 661 8404 Andrew 662 7556 Andrew while (fileset->fs_idle_dirs == 0) { 663 7556 Andrew (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv, 664 7556 Andrew &fileset->fs_pick_lock); 665 7556 Andrew } 666 8404 Andrew 667 8404 Andrew max_entries = 1; 668 8404 Andrew atp = &fileset->fs_dirs; 669 7946 Andrew break; 670 8404 Andrew 671 7946 Andrew case FILESET_PICKLEAFDIR: 672 7946 Andrew if (fileset->fs_leafdirlist == NULL) 673 7946 Andrew goto empty; 674 8404 Andrew 675 7946 Andrew while (fileset->fs_idle_leafdirs == 0) { 676 7946 Andrew (void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv, 677 7556 Andrew &fileset->fs_pick_lock); 678 8404 Andrew } 679 8404 Andrew 680 8404 Andrew max_entries = fileset->fs_constleafdirs; 681 8404 Andrew if (flags & FILESET_PICKUNIQUE) { 682 8404 Andrew atp = &fileset->fs_free_leaf_dirs; 683 8404 Andrew } else if (flags & FILESET_PICKNOEXIST) { 684 8404 Andrew atp = &fileset->fs_noex_leaf_dirs; 685 8404 Andrew } else { 686 8404 Andrew atp = &fileset->fs_exist_leaf_dirs; 687 7556 Andrew } 688 7946 Andrew break; 689 7556 Andrew } 690 6701 aw148015 691 6701 aw148015 /* see if asking for impossible */ 692 8404 Andrew if (avl_is_empty(atp)) 693 8404 Andrew goto empty; 694 8404 Andrew 695 8404 Andrew if (flags & FILESET_PICKUNIQUE) { 696 8404 Andrew uint64_t index64; 697 8404 Andrew 698 8404 Andrew /* 699 8404 Andrew * pick at random from free list in order to 700 8404 Andrew * distribute initially allocated files more 701 8404 Andrew * randomly on storage media. Use uniform 702 8404 Andrew * random number generator to select index 703 8404 Andrew * if it is not supplied with pick call. 704 8404 Andrew */ 705 8404 Andrew if (index) { 706 8404 Andrew index64 = index; 707 8404 Andrew } else { 708 8404 Andrew if (filebench_randomno64(&index64, max_entries, 1, 709 8404 Andrew NULL) == FILEBENCH_ERROR) 710 7946 Andrew return (NULL); 711 8404 Andrew } 712 8404 Andrew 713 8404 Andrew entry = fileset_find_entry(atp, (int)index64); 714 8404 Andrew 715 8404 Andrew if (entry == NULL) 716 8404 Andrew goto empty; 717 8404 Andrew 718 8404 Andrew } else if (flags & FILESET_PICKBYINDEX) { 719 8404 Andrew /* pick by supplied index */ 720 8404 Andrew entry = fileset_find_entry(atp, index); 721 8404 Andrew 722 8404 Andrew } else { 723 8404 Andrew /* pick in rotation */ 724 8404 Andrew switch (flags & FILESET_PICKMASK) { 725 8404 Andrew case FILESET_PICKFILE: 726 8404 Andrew if (flags & FILESET_PICKNOEXIST) { 727 8404 Andrew entry = fileset_find_entry(atp, 728 8404 Andrew fileset->fs_file_nerotor); 729 8404 Andrew fileset->fs_file_nerotor = 730 8404 Andrew entry->fse_index + 1; 731 8404 Andrew } else { 732 8404 Andrew entry = fileset_find_entry(atp, 733 8404 Andrew fileset->fs_file_exrotor[tid]); 734 8404 Andrew fileset->fs_file_exrotor[tid] = 735 8404 Andrew entry->fse_index + 1; 736 7946 Andrew } 737 8404 Andrew break; 738 8404 Andrew 739 8404 Andrew case FILESET_PICKDIR: 740 8404 Andrew entry = fileset_find_entry(atp, fileset->fs_dirrotor); 741 8404 Andrew fileset->fs_dirrotor = entry->fse_index + 1; 742 8404 Andrew break; 743 8404 Andrew 744 8404 Andrew case FILESET_PICKLEAFDIR: 745 8404 Andrew if (flags & FILESET_PICKNOEXIST) { 746 8404 Andrew entry = fileset_find_entry(atp, 747 8404 Andrew fileset->fs_leafdir_nerotor); 748 8404 Andrew fileset->fs_leafdir_nerotor = 749 8404 Andrew entry->fse_index + 1; 750 8404 Andrew } else { 751 8404 Andrew entry = fileset_find_entry(atp, 752 8404 Andrew fileset->fs_leafdir_exrotor); 753 8404 Andrew fileset->fs_leafdir_exrotor = 754 8404 Andrew entry->fse_index + 1; 755 7946 Andrew } 756 8404 Andrew break; 757 6701 aw148015 } 758 6701 aw148015 } 759 5184 ek110237 760 8404 Andrew if (entry == NULL) 761 8404 Andrew goto empty; 762 5184 ek110237 763 8404 Andrew /* see if entry in use */ 764 8404 Andrew start_point = entry; 765 8404 Andrew while (entry->fse_flags & FSE_BUSY) { 766 8404 Andrew 767 8404 Andrew /* it is, so try next */ 768 8404 Andrew entry = AVL_NEXT(atp, entry); 769 8404 Andrew if (entry == NULL) 770 8404 Andrew entry = avl_first(atp); 771 8404 Andrew 772 8404 Andrew /* see if we have wrapped around */ 773 8404 Andrew if ((entry == NULL) || (entry == start_point)) { 774 8404 Andrew filebench_log(LOG_DEBUG_SCRIPT, 775 8404 Andrew "All %d files are busy", avl_numnodes(atp)); 776 8404 Andrew goto empty; 777 5184 ek110237 } 778 5184 ek110237 779 5184 ek110237 } 780 5184 ek110237 781 7556 Andrew /* update file or directory idle counts */ 782 7946 Andrew switch (flags & FILESET_PICKMASK) { 783 7946 Andrew case FILESET_PICKFILE: 784 7946 Andrew fileset->fs_idle_files--; 785 7946 Andrew break; 786 7946 Andrew case FILESET_PICKDIR: 787 7556 Andrew fileset->fs_idle_dirs--; 788 7946 Andrew break; 789 7946 Andrew case FILESET_PICKLEAFDIR: 790 7946 Andrew fileset->fs_idle_leafdirs--; 791 7946 Andrew break; 792 7946 Andrew } 793 7556 Andrew 794 7556 Andrew /* Indicate that file or directory is now busy */ 795 7556 Andrew entry->fse_flags |= FSE_BUSY; 796 7556 Andrew 797 7556 Andrew (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 798 5184 ek110237 filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path); 799 5184 ek110237 return (entry); 800 5184 ek110237 801 5184 ek110237 empty: 802 8404 Andrew filebench_log(LOG_DEBUG_SCRIPT, "No file found"); 803 7556 Andrew (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 804 5184 ek110237 return (NULL); 805 7556 Andrew } 806 7556 Andrew 807 7556 Andrew /* 808 7556 Andrew * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads 809 7556 Andrew * that are waiting for a NOT BUSY filesetentry. Also sets whether it is 810 7556 Andrew * existant or not, or leaves that designation alone. 811 7556 Andrew */ 812 7556 Andrew void 813 8404 Andrew fileset_unbusy(filesetentry_t *entry, int update_exist, 814 8404 Andrew int new_exist_val, int open_cnt_incr) 815 7556 Andrew { 816 7556 Andrew fileset_t *fileset = NULL; 817 7556 Andrew 818 7556 Andrew if (entry) 819 7556 Andrew fileset = entry->fse_fileset; 820 7556 Andrew 821 7556 Andrew if (fileset == NULL) { 822 7556 Andrew filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!"); 823 7556 Andrew return; 824 7556 Andrew } 825 7556 Andrew 826 7556 Andrew (void) ipc_mutex_lock(&fileset->fs_pick_lock); 827 8404 Andrew 828 8404 Andrew /* modify FSE_EXIST flag and actual dirs/files count, if requested */ 829 8404 Andrew if (update_exist) { 830 8404 Andrew if (new_exist_val == TRUE) { 831 8404 Andrew if (entry->fse_flags & FSE_FREE) { 832 8404 Andrew 833 8404 Andrew /* asked to set and it was free */ 834 8404 Andrew entry->fse_flags |= FSE_EXISTS; 835 8404 Andrew entry->fse_flags &= (~FSE_FREE); 836 8404 Andrew switch (entry->fse_flags & FSE_TYPE_MASK) { 837 8404 Andrew case FSE_TYPE_FILE: 838 8404 Andrew fileset_move_entry( 839 8404 Andrew &fileset->fs_free_files, 840 8404 Andrew &fileset->fs_exist_files, entry); 841 8404 Andrew break; 842 8404 Andrew 843 8404 Andrew case FSE_TYPE_DIR: 844 8404 Andrew break; 845 8404 Andrew 846 8404 Andrew case FSE_TYPE_LEAFDIR: 847 8404 Andrew fileset_move_entry( 848 8404 Andrew &fileset->fs_free_leaf_dirs, 849 8404 Andrew &fileset->fs_exist_leaf_dirs, 850 8404 Andrew entry); 851 8404 Andrew break; 852 8404 Andrew } 853 8404 Andrew 854 8404 Andrew } else if (!(entry->fse_flags & FSE_EXISTS)) { 855 8404 Andrew 856 8404 Andrew /* asked to set, and it was clear */ 857 8404 Andrew entry->fse_flags |= FSE_EXISTS; 858 8404 Andrew switch (entry->fse_flags & FSE_TYPE_MASK) { 859 8404 Andrew case FSE_TYPE_FILE: 860 8404 Andrew fileset_move_entry( 861 8404 Andrew &fileset->fs_noex_files, 862 8404 Andrew &fileset->fs_exist_files, entry); 863 8404 Andrew break; 864 8404 Andrew case FSE_TYPE_DIR: 865 8404 Andrew break; 866 8404 Andrew case FSE_TYPE_LEAFDIR: 867 8404 Andrew fileset_move_entry( 868 8404 Andrew &fileset->fs_noex_leaf_dirs, 869 8404 Andrew &fileset->fs_exist_leaf_dirs, 870 8404 Andrew entry); 871 8404 Andrew break; 872 8404 Andrew } 873 8404 Andrew } 874 8404 Andrew } else { 875 8404 Andrew if (entry->fse_flags & FSE_FREE) { 876 8404 Andrew /* asked to clear, and it was free */ 877 8404 Andrew entry->fse_flags &= (~(FSE_FREE | FSE_EXISTS)); 878 8404 Andrew switch (entry->fse_flags & FSE_TYPE_MASK) { 879 8404 Andrew case FSE_TYPE_FILE: 880 8404 Andrew fileset_move_entry( 881 8404 Andrew &fileset->fs_free_files, 882 8404 Andrew &fileset->fs_noex_files, entry); 883 8404 Andrew break; 884 8404 Andrew 885 8404 Andrew case FSE_TYPE_DIR: 886 8404 Andrew break; 887 8404 Andrew 888 8404 Andrew case FSE_TYPE_LEAFDIR: 889 8404 Andrew fileset_move_entry( 890 8404 Andrew &fileset->fs_free_leaf_dirs, 891 8404 Andrew &fileset->fs_noex_leaf_dirs, 892 8404 Andrew entry); 893 8404 Andrew break; 894 8404 Andrew } 895 8404 Andrew } else if (entry->fse_flags & FSE_EXISTS) { 896 8404 Andrew 897 8404 Andrew /* asked to clear, and it was set */ 898 8404 Andrew entry->fse_flags &= (~FSE_EXISTS); 899 8404 Andrew switch (entry->fse_flags & FSE_TYPE_MASK) { 900 8404 Andrew case FSE_TYPE_FILE: 901 8404 Andrew fileset_move_entry( 902 8404 Andrew &fileset->fs_exist_files, 903 8404 Andrew &fileset->fs_noex_files, entry); 904 8404 Andrew break; 905 8404 Andrew case FSE_TYPE_DIR: 906 8404 Andrew break; 907 8404 Andrew case FSE_TYPE_LEAFDIR: 908 8404 Andrew fileset_move_entry( 909 8404 Andrew &fileset->fs_exist_leaf_dirs, 910 8404 Andrew &fileset->fs_noex_leaf_dirs, 911 8404 Andrew entry); 912 8404 Andrew break; 913 8404 Andrew } 914 8404 Andrew } 915 8404 Andrew } 916 8404 Andrew } 917 8404 Andrew 918 8404 Andrew /* update open count */ 919 8404 Andrew entry->fse_open_cnt += open_cnt_incr; 920 7556 Andrew 921 7556 Andrew /* increment idle count, clear FSE_BUSY and signal IF it was busy */ 922 7556 Andrew if (entry->fse_flags & FSE_BUSY) { 923 7556 Andrew 924 7556 Andrew /* unbusy it */ 925 7556 Andrew entry->fse_flags &= (~FSE_BUSY); 926 7556 Andrew 927 7556 Andrew /* release any threads waiting for unbusy */ 928 7556 Andrew if (entry->fse_flags & FSE_THRD_WAITNG) { 929 7556 Andrew entry->fse_flags &= (~FSE_THRD_WAITNG); 930 7556 Andrew (void) pthread_cond_broadcast( 931 7556 Andrew &fileset->fs_thrd_wait_cv); 932 7556 Andrew } 933 7556 Andrew 934 7556 Andrew /* increment idle count and signal waiting threads */ 935 7946 Andrew switch (entry->fse_flags & FSE_TYPE_MASK) { 936 7946 Andrew case FSE_TYPE_FILE: 937 7946 Andrew fileset->fs_idle_files++; 938 7946 Andrew if (fileset->fs_idle_files == 1) { 939 7946 Andrew (void) pthread_cond_signal( 940 7946 Andrew &fileset->fs_idle_files_cv); 941 7946 Andrew } 942 7946 Andrew break; 943 8404 Andrew 944 7946 Andrew case FSE_TYPE_DIR: 945 7556 Andrew fileset->fs_idle_dirs++; 946 7556 Andrew if (fileset->fs_idle_dirs == 1) { 947 7556 Andrew (void) pthread_cond_signal( 948 7556 Andrew &fileset->fs_idle_dirs_cv); 949 7556 Andrew } 950 7946 Andrew break; 951 8404 Andrew 952 7946 Andrew case FSE_TYPE_LEAFDIR: 953 7946 Andrew fileset->fs_idle_leafdirs++; 954 7946 Andrew if (fileset->fs_idle_leafdirs == 1) { 955 7556 Andrew (void) pthread_cond_signal( 956 7946 Andrew &fileset->fs_idle_leafdirs_cv); 957 7556 Andrew } 958 7946 Andrew break; 959 7556 Andrew } 960 7556 Andrew } 961 7556 Andrew 962 7556 Andrew (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 963 5184 ek110237 } 964 5184 ek110237 965 5184 ek110237 /* 966 5184 ek110237 * Given a fileset "fileset", create the associated files as 967 5184 ek110237 * specified in the attributes of the fileset. The fileset is 968 6212 aw148015 * rooted in a directory whose pathname is in fileset_path. If the 969 5184 ek110237 * directory exists, meaning that there is already a fileset, 970 6212 aw148015 * and the fileset_reuse attribute is false, then remove it and all 971 5184 ek110237 * its contained files and subdirectories. Next, the routine 972 5184 ek110237 * creates a root directory for the fileset. All the file type 973 5184 ek110237 * filesetentries are cycled through creating as needed 974 5184 ek110237 * their containing subdirectory trees in the filesystem and 975 6212 aw148015 * creating actual files for fileset_preallocpercent of them. The 976 5184 ek110237 * created files are filled with fse_size bytes of unitialized 977 7556 Andrew * data. The routine returns FILEBENCH_ERROR on errors, 978 7556 Andrew * FILEBENCH_OK on success. 979 5184 ek110237 */ 980 5184 ek110237 static int 981 5184 ek110237 fileset_create(fileset_t *fileset) 982 5184 ek110237 { 983 5184 ek110237 filesetentry_t *entry; 984 5184 ek110237 char path[MAXPATHLEN]; 985 5184 ek110237 struct stat64 sb; 986 5184 ek110237 hrtime_t start = gethrtime(); 987 6212 aw148015 char *fileset_path; 988 6212 aw148015 char *fileset_name; 989 6212 aw148015 int randno; 990 5184 ek110237 int preallocated = 0; 991 7736 Andrew int reusing; 992 5184 ek110237 993 6212 aw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 994 5673 aw148015 filebench_log(LOG_ERROR, "%s path not set", 995 6212 aw148015 fileset_entity_name(fileset)); 996 7556 Andrew return (FILEBENCH_ERROR); 997 6212 aw148015 } 998 6212 aw148015 999 6212 aw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 1000 6212 aw148015 filebench_log(LOG_ERROR, "%s name not set", 1001 5673 aw148015 fileset_entity_name(fileset)); 1002 7556 Andrew return (FILEBENCH_ERROR); 1003 5184 ek110237 } 1004 7946 Andrew 1005 5673 aw148015 #ifdef HAVE_RAW_SUPPORT 1006 5673 aw148015 /* treat raw device as special case */ 1007 5673 aw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 1008 7556 Andrew return (FILEBENCH_OK); 1009 5673 aw148015 #endif /* HAVE_RAW_SUPPORT */ 1010 5184 ek110237 1011 5184 ek110237 /* XXX Add check to see if there is enough space */ 1012 5184 ek110237 1013 7736 Andrew /* set up path to fileset */ 1014 7946 Andrew (void) fb_strlcpy(path, fileset_path, MAXPATHLEN); 1015 7946 Andrew (void) fb_strlcat(path, "/", MAXPATHLEN); 1016 7946 Andrew (void) fb_strlcat(path, fileset_name, MAXPATHLEN); 1017 5184 ek110237 1018 9326 Andrew /* if reusing and trusting to exist, just blindly reuse */ 1019 9326 Andrew if (avd_get_bool(fileset->fs_trust_tree)) { 1020 9326 Andrew reusing = 1; 1021 9326 Andrew 1022 7736 Andrew /* if exists and resusing, then don't create new */ 1023 9326 Andrew } else if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) && 1024 7736 Andrew (strlen(avd_get_str(fileset->fs_path)) > 2)) && 1025 7736 Andrew avd_get_bool(fileset->fs_reuse)) { 1026 7736 Andrew reusing = 1; 1027 7736 Andrew } else { 1028 7736 Andrew reusing = 0; 1029 5184 ek110237 } 1030 5184 ek110237 1031 7736 Andrew if (!reusing) { 1032 7736 Andrew /* Remove existing */ 1033 9356 Andrew FB_RECUR_RM(path); 1034 7736 Andrew filebench_log(LOG_VERBOSE, 1035 7736 Andrew "Removed any existing %s %s in %llu seconds", 1036 7736 Andrew fileset_entity_name(fileset), fileset_name, 1037 7736 Andrew (u_longlong_t)(((gethrtime() - start) / 1038 7736 Andrew 1000000000) + 1)); 1039 7736 Andrew } else { 1040 7736 Andrew /* we are re-using */ 1041 7736 Andrew filebench_log(LOG_VERBOSE, "Re-using %s %s.", 1042 7736 Andrew fileset_entity_name(fileset), fileset_name); 1043 7736 Andrew } 1044 7736 Andrew 1045 7736 Andrew /* make the filesets directory tree unless in reuse mode */ 1046 7736 Andrew if (!reusing && (avd_get_bool(fileset->fs_prealloc))) { 1047 7946 Andrew filebench_log(LOG_VERBOSE, 1048 7736 Andrew "making tree for filset %s", path); 1049 7736 Andrew 1050 8615 Andrew (void) FB_MKDIR(path, 0755); 1051 7736 Andrew 1052 7736 Andrew if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR) 1053 7736 Andrew return (FILEBENCH_ERROR); 1054 7736 Andrew } 1055 5673 aw148015 1056 5184 ek110237 start = gethrtime(); 1057 5184 ek110237 1058 5673 aw148015 filebench_log(LOG_VERBOSE, "Creating %s %s...", 1059 6212 aw148015 fileset_entity_name(fileset), fileset_name); 1060 5673 aw148015 1061 6212 aw148015 randno = ((RAND_MAX * (100 1062 6212 aw148015 - avd_get_int(fileset->fs_preallocpercent))) / 100); 1063 6212 aw148015 1064 7946 Andrew /* alloc any files, as required */ 1065 8404 Andrew fileset_pickreset(fileset, FILESET_PICKFILE); 1066 8404 Andrew while (entry = fileset_pick(fileset, 1067 8404 Andrew FILESET_PICKFREE | FILESET_PICKFILE, 0, 0)) { 1068 5673 aw148015 pthread_t tid; 1069 7736 Andrew int newrand; 1070 5184 ek110237 1071 7736 Andrew newrand = rand(); 1072 7736 Andrew 1073 8404 Andrew if (newrand < randno) { 1074 8404 Andrew /* unbusy the unallocated entry */ 1075 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 1076 5184 ek110237 continue; 1077 8404 Andrew } 1078 5184 ek110237 1079 5184 ek110237 preallocated++; 1080 5184 ek110237 1081 5673 aw148015 if (reusing) 1082 5673 aw148015 entry->fse_flags |= FSE_REUSING; 1083 5673 aw148015 else 1084 5673 aw148015 entry->fse_flags &= (~FSE_REUSING); 1085 5184 ek110237 1086 7556 Andrew /* fire off allocation threads for each file if paralloc set */ 1087 6212 aw148015 if (avd_get_bool(fileset->fs_paralloc)) { 1088 5673 aw148015 1089 7556 Andrew /* limit total number of simultaneous allocations */ 1090 7556 Andrew (void) pthread_mutex_lock( 1091 7556 Andrew &filebench_shm->shm_fsparalloc_lock); 1092 7556 Andrew while (filebench_shm->shm_fsparalloc_count 1093 7556 Andrew >= MAX_PARALLOC_THREADS) { 1094 5673 aw148015 (void) pthread_cond_wait( 1095 7556 Andrew &filebench_shm->shm_fsparalloc_cv, 1096 7556 Andrew &filebench_shm->shm_fsparalloc_lock); 1097 5673 aw148015 } 1098 5673 aw148015 1099 8615 Andrew /* quit if any allocation thread reports an error */ 1100 7556 Andrew if (filebench_shm->shm_fsparalloc_count < 0) { 1101 7556 Andrew (void) pthread_mutex_unlock( 1102 7556 Andrew &filebench_shm->shm_fsparalloc_lock); 1103 7556 Andrew return (FILEBENCH_ERROR); 1104 5184 ek110237 } 1105 5184 ek110237 1106 7556 Andrew filebench_shm->shm_fsparalloc_count++; 1107 7556 Andrew (void) pthread_mutex_unlock( 1108 7556 Andrew &filebench_shm->shm_fsparalloc_lock); 1109 5184 ek110237 1110 7556 Andrew /* 1111 7556 Andrew * Fire off a detached allocation thread per file. 1112 7556 Andrew * The thread will self destruct when it finishes 1113 7556 Andrew * writing pre-allocation data to the file. 1114 7556 Andrew */ 1115 5673 aw148015 if (pthread_create(&tid, NULL, 1116 5673 aw148015 (void *(*)(void*))fileset_alloc_thread, 1117 7556 Andrew entry) == 0) { 1118 7556 Andrew /* 1119 7556 Andrew * A thread was created; detach it so it can 1120 7556 Andrew * fully quit when finished. 1121 7556 Andrew */ 1122 7556 Andrew (void) pthread_detach(tid); 1123 7556 Andrew } else { 1124 5673 aw148015 filebench_log(LOG_ERROR, 1125 5673 aw148015 "File prealloc thread create failed"); 1126 5673 aw148015 filebench_shutdown(1); 1127 5673 aw148015 } 1128 5184 ek110237 1129 5673 aw148015 } else { 1130 7556 Andrew if (fileset_alloc_file(entry) == FILEBENCH_ERROR) 1131 7556 Andrew return (FILEBENCH_ERROR); 1132 5673 aw148015 } 1133 5673 aw148015 } 1134 5184 ek110237 1135 7946 Andrew /* alloc any leaf directories, as required */ 1136 8404 Andrew fileset_pickreset(fileset, FILESET_PICKLEAFDIR); 1137 8404 Andrew while (entry = fileset_pick(fileset, 1138 8404 Andrew FILESET_PICKFREE | FILESET_PICKLEAFDIR, 0, 0)) { 1139 7946 Andrew 1140 8404 Andrew if (rand() < randno) { 1141 8404 Andrew /* unbusy the unallocated entry */ 1142 8404 Andrew fileset_unbusy(entry, TRUE, FALSE, 0); 1143 7946 Andrew continue; 1144 8404 Andrew } 1145 7946 Andrew 1146 7946 Andrew preallocated++; 1147 7946 Andrew 1148 7946 Andrew if (reusing) 1149 7946 Andrew entry->fse_flags |= FSE_REUSING; 1150 7946 Andrew else 1151 7946 Andrew entry->fse_flags &= (~FSE_REUSING); 1152 7946 Andrew 1153 7946 Andrew if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR) 1154 7946 Andrew return (FILEBENCH_ERROR); 1155 7946 Andrew } 1156 7946 Andrew 1157 5673 aw148015 exit: 1158 5184 ek110237 filebench_log(LOG_VERBOSE, 1159 6286 aw148015 "Preallocated %d of %llu of %s %s in %llu seconds", 1160 5184 ek110237 preallocated, 1161 6286 aw148015 (u_longlong_t)fileset->fs_constentries, 1162 6212 aw148015 fileset_entity_name(fileset), fileset_name, 1163 6286 aw148015 (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1)); 1164 5184 ek110237 1165 7556 Andrew return (FILEBENCH_OK); 1166 5184 ek110237 } 1167 5184 ek110237 1168 9356 Andrew /* 1169 9356 Andrew * Removes all files and directories associated with a fileset 1170 9356 Andrew * from the storage subsystem. 1171 9356 Andrew */ 1172 9356 Andrew static void 1173 9356 Andrew fileset_delete_storage(fileset_t *fileset) 1174 9356 Andrew { 1175 9356 Andrew char path[MAXPATHLEN]; 1176 9356 Andrew char *fileset_path; 1177 9356 Andrew char *fileset_name; 1178 9356 Andrew 1179 9356 Andrew if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) 1180 9356 Andrew return; 1181 9356 Andrew 1182 9356 Andrew if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) 1183 9356 Andrew return; 1184 9356 Andrew 1185 9356 Andrew #ifdef HAVE_RAW_SUPPORT 1186 9356 Andrew /* treat raw device as special case */ 1187 9356 Andrew if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 1188 9356 Andrew return; 1189 9356 Andrew #endif /* HAVE_RAW_SUPPORT */ 1190 9356 Andrew 1191 9356 Andrew /* set up path to file */ 1192 9356 Andrew (void) fb_strlcpy(path, fileset_path, MAXPATHLEN); 1193 9356 Andrew (void) fb_strlcat(path, "/", MAXPATHLEN); 1194 9356 Andrew (void) fb_strlcat(path, fileset_name, MAXPATHLEN); 1195 9356 Andrew 1196 9356 Andrew /* now delete any files and directories on the disk */ 1197 9356 Andrew FB_RECUR_RM(path); 1198 9356 Andrew } 1199 9356 Andrew 1200 9356 Andrew /* 1201 9356 Andrew * Removes the fileset entity and all of its filesetentry entities. 1202 9356 Andrew */ 1203 9356 Andrew static void 1204 9356 Andrew fileset_delete_fileset(fileset_t *fileset) 1205 9356 Andrew { 1206 9356 Andrew filesetentry_t *entry, *next_entry; 1207 9356 Andrew 1208 9356 Andrew /* run down the file list, removing and freeing each filesetentry */ 1209 9356 Andrew for (entry = fileset->fs_filelist; entry; entry = next_entry) { 1210 9356 Andrew 1211 9356 Andrew /* free the entry */ 1212 9356 Andrew next_entry = entry->fse_next; 1213 9356 Andrew 1214 9356 Andrew /* return it to the pool */ 1215 9356 Andrew switch (entry->fse_flags & FSE_TYPE_MASK) { 1216 9356 Andrew case FSE_TYPE_FILE: 1217 9356 Andrew case FSE_TYPE_LEAFDIR: 1218 9356 Andrew case FSE_TYPE_DIR: 1219 9356 Andrew ipc_free(FILEBENCH_FILESETENTRY, (void *)entry); 1220 9356 Andrew break; 1221 9356 Andrew default: 1222 9356 Andrew filebench_log(LOG_ERROR, 1223 9356 Andrew "Unallocated filesetentry found on list"); 1224 9356 Andrew break; 1225 9356 Andrew } 1226 9356 Andrew } 1227 9356 Andrew 1228 9356 Andrew ipc_free(FILEBENCH_FILESET, (void *)fileset); 1229 9356 Andrew } 1230 9356 Andrew 1231 9356 Andrew void 1232 9356 Andrew fileset_delete_all_filesets(void) 1233 9356 Andrew { 1234 9356 Andrew fileset_t *fileset, *next_fileset; 1235 9356 Andrew 1236 9356 Andrew for (fileset = filebench_shm->shm_filesetlist; 1237 9356 Andrew fileset; fileset = next_fileset) { 1238 9356 Andrew next_fileset = fileset->fs_next; 1239 9356 Andrew fileset_delete_storage(fileset); 1240 9356 Andrew fileset_delete_fileset(fileset); 1241 9356 Andrew } 1242 9356 Andrew 1243 9356 Andrew filebench_shm->shm_filesetlist = NULL; 1244 9356 Andrew } 1245 5184 ek110237 /* 1246 5184 ek110237 * Adds an entry to the fileset's file list. Single threaded so 1247 5184 ek110237 * no locking needed. 1248 5184 ek110237 */ 1249 5184 ek110237 static void 1250 5184 ek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry) 1251 5184 ek110237 { 1252 8404 Andrew entry->fse_flags = FSE_TYPE_FILE | FSE_FREE; 1253 8404 Andrew avl_add(&fileset->fs_free_files, entry); 1254 8404 Andrew 1255 5184 ek110237 if (fileset->fs_filelist == NULL) { 1256 5184 ek110237 fileset->fs_filelist = entry; 1257 8404 Andrew entry->fse_nextoftype = NULL; 1258 5184 ek110237 } else { 1259 8404 Andrew entry->fse_nextoftype = fileset->fs_filelist; 1260 5184 ek110237 fileset->fs_filelist = entry; 1261 5184 ek110237 } 1262 5184 ek110237 } 1263 5184 ek110237 1264 5184 ek110237 /* 1265 5184 ek110237 * Adds an entry to the fileset's directory list. Single 1266 5184 ek110237 * threaded so no locking needed. 1267 5184 ek110237 */ 1268 5184 ek110237 static void 1269 5184 ek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) 1270 5184 ek110237 { 1271 8404 Andrew entry->fse_flags = FSE_TYPE_DIR | FSE_EXISTS; 1272 8404 Andrew avl_add(&fileset->fs_dirs, entry); 1273 8404 Andrew 1274 5184 ek110237 if (fileset->fs_dirlist == NULL) { 1275 5184 ek110237 fileset->fs_dirlist = entry; 1276 8404 Andrew entry->fse_nextoftype = NULL; 1277 5184 ek110237 } else { 1278 8404 Andrew entry->fse_nextoftype = fileset->fs_dirlist; 1279 5184 ek110237 fileset->fs_dirlist = entry; 1280 5184 ek110237 } 1281 5184 ek110237 } 1282 5184 ek110237 1283 5184 ek110237 /* 1284 7946 Andrew * Adds an entry to the fileset's leaf directory list. Single 1285 7946 Andrew * threaded so no locking needed. 1286 7946 Andrew */ 1287 7946 Andrew static void 1288 7946 Andrew fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry) 1289 7946 Andrew { 1290 8404 Andrew entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE; 1291 8404 Andrew avl_add(&fileset->fs_free_leaf_dirs, entry); 1292 8404 Andrew 1293 7946 Andrew if (fileset->fs_leafdirlist == NULL) { 1294 7946 Andrew fileset->fs_leafdirlist = entry; 1295 8404 Andrew entry->fse_nextoftype = NULL; 1296 7946 Andrew } else { 1297 8404 Andrew entry->fse_nextoftype = fileset->fs_leafdirlist; 1298 7946 Andrew fileset->fs_leafdirlist = entry; 1299 7946 Andrew } 1300 8404 Andrew } 1301 8404 Andrew 1302 8404 Andrew /* 1303 8404 Andrew * Compares two fileset entries to determine their relative order 1304 8404 Andrew */ 1305 8404 Andrew static int 1306 8404 Andrew fileset_entry_compare(const void *node_1, const void *node_2) 1307 8404 Andrew { 1308 8404 Andrew if (((filesetentry_t *)node_1)->fse_index < 1309 8404 Andrew ((filesetentry_t *)node_2)->fse_index) 1310 8404 Andrew return (-1); 1311 8404 Andrew 1312 8404 Andrew if (((filesetentry_t *)node_1)->fse_index == 1313 8404 Andrew ((filesetentry_t *)node_2)->fse_index) 1314 8404 Andrew return (0); 1315 8404 Andrew 1316 8404 Andrew return (1); 1317 7946 Andrew } 1318 7946 Andrew 1319 7946 Andrew /* 1320 7946 Andrew * Obtains a filesetentry entity for a file to be placed in a 1321 5184 ek110237 * (sub)directory of a fileset. The size of the file may be 1322 6212 aw148015 * specified by fileset_meansize, or calculated from a gamma 1323 6212 aw148015 * distribution of parameter fileset_sizegamma and of mean size 1324 6212 aw148015 * fileset_meansize. The filesetentry entity is placed on the file 1325 5184 ek110237 * list in the specified parent filesetentry entity, which may 1326 5184 ek110237 * be a directory filesetentry, or the root filesetentry in the 1327 5184 ek110237 * fileset. It is also placed on the fileset's list of all 1328 7556 Andrew * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR 1329 7556 Andrew * if ipc memory for the path string cannot be allocated. 1330 5184 ek110237 */ 1331 5184 ek110237 static int 1332 5184 ek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) 1333 5184 ek110237 { 1334 5184 ek110237 char tmpname[16]; 1335 5184 ek110237 filesetentry_t *entry; 1336 5184 ek110237 double drand; 1337 8404 Andrew uint_t index; 1338 5184 ek110237 1339 5184 ek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 1340 5184 ek110237 == NULL) { 1341 5184 ek110237 filebench_log(LOG_ERROR, 1342 5184 ek110237 "fileset_populate_file: Can't malloc filesetentry"); 1343 7556 Andrew return (FILEBENCH_ERROR); 1344 5184 ek110237 } 1345 5184 ek110237 1346 7556 Andrew /* Another currently idle file */ 1347 7556 Andrew (void) ipc_mutex_lock(&fileset->fs_pick_lock); 1348 8404 Andrew index = fileset->fs_idle_files++; 1349 7556 Andrew (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 1350 7556 Andrew 1351 8404 Andrew entry->fse_index = index; 1352 5184 ek110237 entry->fse_parent = parent; 1353 5184 ek110237 entry->fse_fileset = fileset; 1354 5184 ek110237 fileset_insfilelist(fileset, entry); 1355 5184 ek110237 1356 5184 ek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 1357 5184 ek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 1358 5184 ek110237 filebench_log(LOG_ERROR, 1359 5184 ek110237 "fileset_populate_file: Can't alloc path string"); 1360 7556 Andrew return (FILEBENCH_ERROR); 1361 5184 ek110237 } 1362 5184 ek110237 1363 6212 aw148015 /* see if random variable was supplied for file size */ 1364 6212 aw148015 if (fileset->fs_meansize == -1) { 1365 6212 aw148015 entry->fse_size = (off64_t)avd_get_int(fileset->fs_size); 1366 6212 aw148015 } else { 1367 6212 aw148015 double gamma; 1368 5184 ek110237 1369 6212 aw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 1370 6212 aw148015 if (gamma > 0) { 1371 6212 aw148015 drand = gamma_dist_knuth(gamma, 1372 6212 aw148015 fileset->fs_meansize / gamma); 1373 6212 aw148015 entry->fse_size = (off64_t)drand; 1374 6212 aw148015 } else { 1375 6212 aw148015 entry->fse_size = (off64_t)fileset->fs_meansize; 1376 6212 aw148015 } 1377 5184 ek110237 } 1378 5184 ek110237 1379 5184 ek110237 fileset->fs_bytes += entry->fse_size; 1380 5184 ek110237 1381 5184 ek110237 fileset->fs_realfiles++; 1382 7946 Andrew return (FILEBENCH_OK); 1383 7946 Andrew } 1384 7946 Andrew 1385 7946 Andrew /* 1386 7946 Andrew * Obtaines a filesetentry entity for a leaf directory to be placed in a 1387 7946 Andrew * (sub)directory of a fileset. The leaf directory will always be empty so 1388 7946 Andrew * it can be created and deleted (mkdir, rmdir) at will. The filesetentry 1389 7946 Andrew * entity is placed on the leaf directory list in the specified parent 1390 7946 Andrew * filesetentry entity, which may be a (sub) directory filesetentry, or 1391 7946 Andrew * the root filesetentry in the fileset. It is also placed on the fileset's 1392 7946 Andrew * list of all contained leaf directories. Returns FILEBENCH_OK if successful 1393 7946 Andrew * or FILEBENCH_ERROR if ipc memory cannot be allocated. 1394 7946 Andrew */ 1395 7946 Andrew static int 1396 7946 Andrew fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial) 1397 7946 Andrew { 1398 7946 Andrew char tmpname[16]; 1399 7946 Andrew filesetentry_t *entry; 1400 8404 Andrew uint_t index; 1401 7946 Andrew 1402 7946 Andrew if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 1403 7946 Andrew == NULL) { 1404 7946 Andrew filebench_log(LOG_ERROR, 1405 7946 Andrew "fileset_populate_file: Can't malloc filesetentry"); 1406 7946 Andrew return (FILEBENCH_ERROR); 1407 7946 Andrew } 1408 7946 Andrew 1409 7946 Andrew /* Another currently idle leaf directory */ 1410 7946 Andrew (void) ipc_mutex_lock(&fileset->fs_pick_lock); 1411 8404 Andrew index = fileset->fs_idle_leafdirs++; 1412 7946 Andrew (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 1413 7946 Andrew 1414 8404 Andrew entry->fse_index = index; 1415 7946 Andrew entry->fse_parent = parent; 1416 7946 Andrew entry->fse_fileset = fileset; 1417 7946 Andrew fileset_insleafdirlist(fileset, entry); 1418 7946 Andrew 1419 7946 Andrew (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 1420 7946 Andrew if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 1421 7946 Andrew filebench_log(LOG_ERROR, 1422 7946 Andrew "fileset_populate_file: Can't alloc path string"); 1423 7946 Andrew return (FILEBENCH_ERROR); 1424 7946 Andrew } 1425 7946 Andrew 1426 7946 Andrew fileset->fs_realleafdirs++; 1427 7556 Andrew return (FILEBENCH_OK); 1428 5184 ek110237 } 1429 5184 ek110237 1430 5184 ek110237 /* 1431 5184 ek110237 * Creates a directory node in a fileset, by obtaining a 1432 5184 ek110237 * filesetentry entity for the node and initializing it 1433 5184 ek110237 * according to parameters of the fileset. It determines a 1434 5184 ek110237 * directory tree depth and directory width, optionally using 1435 5184 ek110237 * a gamma distribution. If its calculated depth is less then 1436 5184 ek110237 * its actual depth in the directory tree, it becomes a leaf 1437 5184 ek110237 * node and files itself with "width" number of file type 1438 5184 ek110237 * filesetentries, otherwise it files itself with "width" 1439 5184 ek110237 * number of directory type filesetentries, using recursive 1440 5184 ek110237 * calls to fileset_populate_subdir. The end result of the 1441 5184 ek110237 * initial call to this routine is a tree of directories of 1442 5184 ek110237 * random width and varying depth with sufficient leaf 1443 5184 ek110237 * directories to contain all required files. 1444 7556 Andrew * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path 1445 7556 Andrew * string memory cannot be allocated and returns the error code (currently 1446 7556 Andrew * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive 1447 5184 ek110237 * calls to fileset_populate_subdir. 1448 5184 ek110237 */ 1449 5184 ek110237 static int 1450 5184 ek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, 1451 5184 ek110237 int serial, double depth) 1452 5184 ek110237 { 1453 6212 aw148015 double randepth, drand, ranwidth; 1454 5184 ek110237 int isleaf = 0; 1455 5184 ek110237 char tmpname[16]; 1456 5184 ek110237 filesetentry_t *entry; 1457 5184 ek110237 int i; 1458 8404 Andrew uint_t index; 1459 5184 ek110237 1460 5184 ek110237 depth += 1; 1461 5184 ek110237 1462 5184 ek110237 /* Create dir node */ 1463 5184 ek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 1464 5184 ek110237 == NULL) { 1465 5184 ek110237 filebench_log(LOG_ERROR, 1466 5184 ek110237 "fileset_populate_subdir: Can't malloc filesetentry"); 1467 7556 Andrew return (FILEBENCH_ERROR); 1468 5184 ek110237 } 1469 5184 ek110237 1470 7556 Andrew /* another idle directory */ 1471 7556 Andrew (void) ipc_mutex_lock(&fileset->fs_pick_lock); 1472 8404 Andrew index = fileset->fs_idle_dirs++; 1473 7556 Andrew (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 1474 5184 ek110237 1475 5184 ek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 1476 5184 ek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 1477 5184 ek110237 filebench_log(LOG_ERROR, 1478 5184 ek110237 "fileset_populate_subdir: Can't alloc path string"); 1479 7556 Andrew return (FILEBENCH_ERROR); 1480 5184 ek110237 } 1481 5184 ek110237 1482 8404 Andrew entry->fse_index = index; 1483 5184 ek110237 entry->fse_parent = parent; 1484 7946 Andrew entry->fse_fileset = fileset; 1485 5184 ek110237 fileset_insdirlist(fileset, entry); 1486 5184 ek110237 1487 6212 aw148015 if (fileset->fs_dirdepthrv) { 1488 6212 aw148015 randepth = (int)avd_get_int(fileset->fs_dirdepthrv); 1489 5184 ek110237 } else { 1490 6212 aw148015 double gamma; 1491 6212 aw148015 1492 6212 aw148015 gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0; 1493 6212 aw148015 if (gamma > 0) { 1494 6212 aw148015 drand = gamma_dist_knuth(gamma, 1495 6212 aw148015 fileset->fs_meandepth / gamma); 1496 6212 aw148015 randepth = (int)drand; 1497 6212 aw148015 } else { 1498 6212 aw148015 randepth = (int)fileset->fs_meandepth; 1499 6212 aw148015 } 1500 5184 ek110237 } 1501 5184 ek110237 1502 6212 aw148015 if (fileset->fs_meanwidth == -1) { 1503 6212 aw148015 ranwidth = avd_get_dbl(fileset->fs_dirwidth); 1504 6212 aw148015 } else { 1505 6212 aw148015 double gamma; 1506 5184 ek110237 1507 6212 aw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 1508 6212 aw148015 if (gamma > 0) { 1509 6212 aw148015 drand = gamma_dist_knuth(gamma, 1510 6212 aw148015 fileset->fs_meanwidth / gamma); 1511 6212 aw148015 ranwidth = drand; 1512 6212 aw148015 } else { 1513 6212 aw148015 ranwidth = fileset->fs_meanwidth; 1514 6212 aw148015 } 1515 5184 ek110237 } 1516 5184 ek110237 1517 5184 ek110237 if (randepth == 0) 1518 5184 ek110237 randepth = 1; 1519 5184 ek110237 if (ranwidth == 0) 1520 5184 ek110237 ranwidth = 1; 1521 5184 ek110237 if (depth >= randepth) 1522 5184 ek110237 isleaf = 1; 1523 5184 ek110237 1524 5184 ek110237 /* 1525 7946 Andrew * Create directory of random width filled with files according 1526 7946 Andrew * to distribution, or if root directory, continue until #files required 1527 5184 ek110237 */ 1528 6212 aw148015 for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && 1529 6212 aw148015 (fileset->fs_realfiles < fileset->fs_constentries); 1530 6212 aw148015 i++) { 1531 5184 ek110237 int ret = 0; 1532 5184 ek110237 1533 5184 ek110237 if (parent && isleaf) 1534 5184 ek110237 ret = fileset_populate_file(fileset, entry, i); 1535 5184 ek110237 else 1536 5184 ek110237 ret = fileset_populate_subdir(fileset, entry, i, depth); 1537 5184 ek110237 1538 5184 ek110237 if (ret != 0) 1539 5184 ek110237 return (ret); 1540 5184 ek110237 } 1541 7946 Andrew 1542 7946 Andrew /* 1543 7946 Andrew * Create directory of random width filled with leaf directories 1544 7946 Andrew * according to distribution, or if root directory, continue until 1545 7946 Andrew * the number of leaf directories required has been generated. 1546 7946 Andrew */ 1547 7946 Andrew for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && 1548 7946 Andrew (fileset->fs_realleafdirs < fileset->fs_constleafdirs); 1549 7946 Andrew i++) { 1550 7946 Andrew int ret = 0; 1551 7946 Andrew 1552 7946 Andrew if (parent && isleaf) 1553 7946 Andrew ret = fileset_populate_leafdir(fileset, entry, i); 1554 7946 Andrew else 1555 7946 Andrew ret = fileset_populate_subdir(fileset, entry, i, depth); 1556 7946 Andrew 1557 7946 Andrew if (ret != 0) 1558 7946 Andrew return (ret); 1559 7946 Andrew } 1560 7946 Andrew 1561 7556 Andrew return (FILEBENCH_OK); 1562 5184 ek110237 } 1563 5184 ek110237 1564 5184 ek110237 /* 1565 5184 ek110237 * Populates a fileset with files and subdirectory entries. Uses 1566 6212 aw148015 * the supplied fileset_dirwidth and fileset_entries (number of files) to 1567 6212 aw148015 * calculate the required fileset_meandepth (of subdirectories) and 1568 6212 aw148015 * initialize the fileset_meanwidth and fileset_meansize variables. Then 1569 5184 ek110237 * calls fileset_populate_subdir() to do the recursive 1570 5184 ek110237 * subdirectory entry creation and leaf file entry creation. All 1571 5184 ek110237 * of the above is skipped if the fileset has already been 1572 5184 ek110237 * populated. Returns 0 on success, or an error code from the 1573 5184 ek110237 * call to fileset_populate_subdir if that call fails. 1574 5184 ek110237 */ 1575 5184 ek110237 static int 1576 5184 ek110237 fileset_populate(fileset_t *fileset) 1577 5184 ek110237 { 1578 8404 Andrew fbint_t entries = avd_get_int(fileset->fs_entries); 1579 8404 Andrew fbint_t leafdirs = avd_get_int(fileset->fs_leafdirs); 1580 6212 aw148015 int meandirwidth; 1581 5184 ek110237 int ret; 1582 5184 ek110237 1583 5184 ek110237 /* Skip if already populated */ 1584 5184 ek110237 if (fileset->fs_bytes > 0) 1585 5184 ek110237 goto exists; 1586 5184 ek110237 1587 5673 aw148015 #ifdef HAVE_RAW_SUPPORT 1588 5673 aw148015 /* check for raw device */ 1589 5673 aw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 1590 7556 Andrew return (FILEBENCH_OK); 1591 5673 aw148015 #endif /* HAVE_RAW_SUPPORT */ 1592 5673 aw148015 1593 7946 Andrew /* 1594 7946 Andrew * save value of entries and leaf dirs obtained for later 1595 7946 Andrew * in case it was random 1596 7946 Andrew */ 1597 6212 aw148015 fileset->fs_constentries = entries; 1598 7946 Andrew fileset->fs_constleafdirs = leafdirs; 1599 7556 Andrew 1600 7556 Andrew /* initialize idle files and directories condition variables */ 1601 7946 Andrew (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr()); 1602 7556 Andrew (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr()); 1603 7946 Andrew (void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr()); 1604 7556 Andrew 1605 7556 Andrew /* no files or dirs idle (or busy) yet */ 1606 7556 Andrew fileset->fs_idle_files = 0; 1607 7556 Andrew fileset->fs_idle_dirs = 0; 1608 7946 Andrew fileset->fs_idle_leafdirs = 0; 1609 7556 Andrew 1610 7556 Andrew /* initialize locks and other condition variables */ 1611 7556 Andrew (void) pthread_mutex_init(&fileset->fs_pick_lock, 1612 7556 Andrew ipc_mutexattr(IPC_MUTEX_NORMAL)); 1613 8404 Andrew (void) pthread_mutex_init(&fileset->fs_histo_lock, 1614 8404 Andrew ipc_mutexattr(IPC_MUTEX_NORMAL)); 1615 7556 Andrew (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr()); 1616 8404 Andrew 1617 8404 Andrew /* Initialize avl btrees */ 1618 8404 Andrew avl_create(&(fileset->fs_free_files), fileset_entry_compare, 1619 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1620 8404 Andrew avl_create(&(fileset->fs_noex_files), fileset_entry_compare, 1621 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1622 8404 Andrew avl_create(&(fileset->fs_exist_files), fileset_entry_compare, 1623 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1624 8404 Andrew avl_create(&(fileset->fs_free_leaf_dirs), fileset_entry_compare, 1625 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1626 8404 Andrew avl_create(&(fileset->fs_noex_leaf_dirs), fileset_entry_compare, 1627 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1628 8404 Andrew avl_create(&(fileset->fs_exist_leaf_dirs), fileset_entry_compare, 1629 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1630 8404 Andrew avl_create(&(fileset->fs_dirs), fileset_entry_compare, 1631 8404 Andrew sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); 1632 6212 aw148015 1633 6212 aw148015 /* is dirwidth a random variable? */ 1634 6212 aw148015 if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { 1635 6212 aw148015 meandirwidth = 1636 6212 aw148015 (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean; 1637 6212 aw148015 fileset->fs_meanwidth = -1; 1638 6212 aw148015 } else { 1639 6212 aw148015 meandirwidth = (int)avd_get_int(fileset->fs_dirwidth); 1640 6212 aw148015 fileset->fs_meanwidth = (double)meandirwidth; 1641 6212 aw148015 } 1642 6212 aw148015 1643 5184 ek110237 /* 1644 5184 ek110237 * Input params are: 1645 5184 ek110237 * # of files 1646 5184 ek110237 * ave # of files per dir 1647 5184 ek110237 * max size of dir 1648 5184 ek110237 * # ave size of file 1649 5184 ek110237 * max size of file 1650 5184 ek110237 */ 1651 7946 Andrew fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth); 1652 6212 aw148015 1653 6212 aw148015 /* Has a random variable been supplied for dirdepth? */ 1654 6212 aw148015 if (fileset->fs_dirdepthrv) { 1655 6212 aw148015 /* yes, so set the random variable's mean value to meandepth */ 1656 6212 aw148015 fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean = 1657 6212 aw148015 fileset->fs_meandepth; 1658 6212 aw148015 } 1659 6212 aw148015 1660 6212 aw148015 /* test for random size variable */ 1661 6212 aw148015 if (AVD_IS_RANDOM(fileset->fs_size)) 1662 6212 aw148015 fileset->fs_meansize = -1; 1663 6212 aw148015 else 1664 6212 aw148015 fileset->fs_meansize = avd_get_int(fileset->fs_size); 1665 5184 ek110237 1666 5184 ek110237 if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0) 1667 5184 ek110237 return (ret); 1668 5184 ek110237 1669 5184 ek110237 1670 5184 ek110237 exists: 1671 5673 aw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 1672 6286 aw148015 filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu", 1673 6212 aw148015 avd_get_str(fileset->fs_name), 1674 6286 aw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 1675 5673 aw148015 } else { 1676 7946 Andrew filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs " 1677 6286 aw148015 "avg dir = %d, avg depth = %.1lf, mbytes=%llu", 1678 7946 Andrew avd_get_str(fileset->fs_name), entries, leafdirs, 1679 6212 aw148015 meandirwidth, 1680 5673 aw148015 fileset->fs_meandepth, 1681 6286 aw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 1682 5673 aw148015 } 1683 6701 aw148015 1684 7556 Andrew return (FILEBENCH_OK); 1685 5184 ek110237 } 1686 5184 ek110237 1687 5184 ek110237 /* 1688 6212 aw148015 * Allocates a fileset instance, initializes fileset_dirgamma and 1689 6212 aw148015 * fileset_sizegamma default values, and sets the fileset name to the 1690 5184 ek110237 * supplied name string. Puts the allocated fileset on the 1691 5184 ek110237 * master fileset list and returns a pointer to it. 1692 6701 aw148015 * 1693 6701 aw148015 * This routine implements the 'define fileset' calls found in a .f 1694 6701 aw148015 * workload, such as in the following example: 1695 6701 aw148015 * define fileset name=drew4ever, entries=$nfiles 1696 5184 ek110237 */ 1697 5184 ek110237 fileset_t * 1698 6212 aw148015 fileset_define(avd_t name) 1699 5184 ek110237 { 1700 5184 ek110237 fileset_t *fileset; 1701 5184 ek110237 1702 5184 ek110237 if (name == NULL) 1703 5184 ek110237 return (NULL); 1704 5184 ek110237 1705 5184 ek110237 if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) { 1706 5184 ek110237 filebench_log(LOG_ERROR, 1707 5184 ek110237 "fileset_define: Can't malloc fileset"); 1708 5184 ek110237 return (NULL); 1709 5184 ek110237 } 1710 5184 ek110237 1711 6212 aw148015 filebench_log(LOG_DEBUG_IMPL, 1712 6212 aw148015 "Defining file %s", avd_get_str(name)); 1713 5184 ek110237 1714 6391 aw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 1715 5184 ek110237 1716 6212 aw148015 fileset->fs_dirgamma = avd_int_alloc(1500); 1717 6212 aw148015 fileset->fs_sizegamma = avd_int_alloc(1500); 1718 8404 Andrew fileset->fs_histo_id = -1; 1719 5184 ek110237 1720 5184 ek110237 /* Add fileset to global list */ 1721 6391 aw148015 if (filebench_shm->shm_filesetlist == NULL) { 1722 6391 aw148015 filebench_shm->shm_filesetlist = fileset; 1723 5184 ek110237 fileset->fs_next = NULL; 1724 5184 ek110237 } else { 1725 6391 aw148015 fileset->fs_next = filebench_shm->shm_filesetlist; 1726 6391 aw148015 filebench_shm->shm_filesetlist = fileset; 1727 5184 ek110237 } 1728 5184 ek110237 1729 6391 aw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 1730 5184 ek110237 1731 6212 aw148015 fileset->fs_name = name; 1732 5184 ek110237 1733 5184 ek110237 return (fileset); 1734 5184 ek110237 } 1735 5184 ek110237 1736 5184 ek110237 /* 1737 5184 ek110237 * If supplied with a pointer to a fileset and the fileset's 1738 6212 aw148015 * fileset_prealloc flag is set, calls fileset_populate() to populate 1739 5184 ek110237 * the fileset with filesetentries, then calls fileset_create() 1740 5184 ek110237 * to make actual directories and files for the filesetentries. 1741 5184 ek110237 * Otherwise, it applies fileset_populate() and fileset_create() 1742 5184 ek110237 * to all the filesets on the master fileset list. It always 1743 5184 ek110237 * returns zero (0) if one fileset is populated / created, 1744 5184 ek110237 * otherwise it returns the sum of returned values from 1745 5184 ek110237 * fileset_create() and fileset_populate(), which 1746 5184 ek110237 * will be a negative one (-1) times the number of 1747 5184 ek110237 * fileset_create() calls which failed. 1748 5184 ek110237 */ 1749 5184 ek110237 int 1750 5184 ek110237 fileset_createset(fileset_t *fileset) 1751 5184 ek110237 { 1752 5184 ek110237 fileset_t *list; 1753 5184 ek110237 int ret = 0; 1754 5184 ek110237 1755 5673 aw148015 /* set up for possible parallel allocate */ 1756 7556 Andrew filebench_shm->shm_fsparalloc_count = 0; 1757 7556 Andrew (void) pthread_cond_init( 1758 7556 Andrew &filebench_shm->shm_fsparalloc_cv, 1759 7556 Andrew ipc_condattr()); 1760 5673 aw148015 1761 6212 aw148015 if (fileset && avd_get_bool(fileset->fs_prealloc)) { 1762 5673 aw148015 1763 6305 aw148015 /* check for raw files */ 1764 6305 aw148015 if (fileset_checkraw(fileset)) { 1765 6305 aw148015 filebench_log(LOG_INFO, 1766 6305 aw148015 "file %s/%s is a RAW device", 1767 6305 aw148015 avd_get_str(fileset->fs_path), 1768 6305 aw148015 avd_get_str(fileset->fs_name)); 1769 7556 Andrew return (FILEBENCH_OK); 1770 6305 aw148015 } 1771 6305 aw148015 1772 5673 aw148015 filebench_log(LOG_INFO, 1773 5673 aw148015 "creating/pre-allocating %s %s", 1774 6212 aw148015 fileset_entity_name(fileset), 1775 6212 aw148015 avd_get_str(fileset->fs_name)); 1776 5673 aw148015 1777 7556 Andrew if ((ret = fileset_populate(fileset)) != FILEBENCH_OK) 1778 5184 ek110237 return (ret); 1779 5673 aw148015 1780 7556 Andrew if ((ret = fileset_create(fileset)) != FILEBENCH_OK) 1781 5673 aw148015 return (ret); 1782 5673 aw148015 } else { 1783 5673 aw148015 1784 5673 aw148015 filebench_log(LOG_INFO, 1785 5673 aw148015 "Creating/pre-allocating files and filesets"); 1786 5673 aw148015 1787 6391 aw148015 list = filebench_shm->shm_filesetlist; 1788 5673 aw148015 while (list) { 1789 6305 aw148015 /* check for raw files */ 1790 6305 aw148015 if (fileset_checkraw(list)) { 1791 6305 aw148015 filebench_log(LOG_INFO, 1792 6305 aw148015 "file %s/%s is a RAW device", 1793 6305 aw148015 avd_get_str(list->fs_path), 1794 6305 aw148015 avd_get_str(list->fs_name)); 1795 6305 aw148015 list = list->fs_next; 1796 6305 aw148015 continue; 1797 6305 aw148015 } 1798 6305 aw148015 1799 7556 Andrew if ((ret = fileset_populate(list)) != FILEBENCH_OK) 1800 5673 aw148015 return (ret); 1801 7556 Andrew 1802 7556 Andrew if ((ret = fileset_create(list)) != FILEBENCH_OK) 1803 5673 aw148015 return (ret); 1804 7556 Andrew 1805 5673 aw148015 list = list->fs_next; 1806 5673 aw148015 } 1807 5184 ek110237 } 1808 5184 ek110237 1809 5673 aw148015 /* wait for allocation threads to finish */ 1810 5673 aw148015 filebench_log(LOG_INFO, 1811 5673 aw148015 "waiting for fileset pre-allocation to finish"); 1812 5184 ek110237 1813 7556 Andrew (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 1814 7556 Andrew while (filebench_shm->shm_fsparalloc_count > 0) 1815 7556 Andrew (void) pthread_cond_wait( 1816 7556 Andrew &filebench_shm->shm_fsparalloc_cv, 1817 7556 Andrew &filebench_shm->shm_fsparalloc_lock); 1818 7556 Andrew (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); 1819 5673 aw148015 1820 7556 Andrew if (filebench_shm->shm_fsparalloc_count < 0) 1821 7556 Andrew return (FILEBENCH_ERROR); 1822 5673 aw148015 1823 7556 Andrew return (FILEBENCH_OK); 1824 5184 ek110237 } 1825 5184 ek110237 1826 5184 ek110237 /* 1827 5184 ek110237 * Searches through the master fileset list for the named fileset. 1828 5184 ek110237 * If found, returns pointer to same, otherwise returns NULL. 1829 5184 ek110237 */ 1830 5184 ek110237 fileset_t * 1831 5184 ek110237 fileset_find(char *name) 1832 5184 ek110237 { 1833 6391 aw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 1834 5184 ek110237 1835 6391 aw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 1836 5184 ek110237 1837 5184 ek110237 while (fileset) { 1838 6212 aw148015 if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) { 1839 6391 aw148015 (void) ipc_mutex_unlock( 1840 6391 aw148015 &filebench_shm->shm_fileset_lock); 1841 5184 ek110237 return (fileset); 1842 5184 ek110237 } 1843 5184 ek110237 fileset = fileset->fs_next; 1844 5184 ek110237 } 1845 6391 aw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 1846 5184 ek110237 1847 5184 ek110237 return (NULL); 1848 5184 ek110237 } 1849 5673 aw148015 1850 5673 aw148015 /* 1851 5673 aw148015 * Iterates over all the file sets in the filesetlist, 1852 5673 aw148015 * executing the supplied command "*cmd()" on them. Also 1853 5673 aw148015 * indicates to the executed command if it is the first 1854 5673 aw148015 * time the command has been executed since the current 1855 5673 aw148015 * call to fileset_iter. 1856 5673 aw148015 */ 1857 8404 Andrew int 1858 5673 aw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first)) 1859 5673 aw148015 { 1860 6391 aw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 1861 5673 aw148015 int count = 0; 1862 5673 aw148015 1863 6391 aw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 1864 5673 aw148015 1865 5673 aw148015 while (fileset) { 1866 8404 Andrew if (cmd(fileset, count == 0) == FILEBENCH_ERROR) { 1867 8404 Andrew (void) ipc_mutex_unlock( 1868 8404 Andrew &filebench_shm->shm_fileset_lock); 1869 8404 Andrew return (FILEBENCH_ERROR); 1870 8404 Andrew } 1871 5673 aw148015 fileset = fileset->fs_next; 1872 5673 aw148015 count++; 1873 5673 aw148015 } 1874 5673 aw148015 1875 6391 aw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 1876 8404 Andrew return (FILEBENCH_OK); 1877 5673 aw148015 } 1878 5673 aw148015 1879 5673 aw148015 /* 1880 5673 aw148015 * Prints information to the filebench log about the file 1881 5673 aw148015 * object. Also prints a header on the first call. 1882 5673 aw148015 */ 1883 5673 aw148015 int 1884 5673 aw148015 fileset_print(fileset_t *fileset, int first) 1885 5673 aw148015 { 1886 6212 aw148015 int pathlength; 1887 6212 aw148015 char *fileset_path; 1888 6212 aw148015 char *fileset_name; 1889 6212 aw148015 static char pad[] = " "; /* 30 spaces */ 1890 6212 aw148015 1891 6212 aw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 1892 6212 aw148015 filebench_log(LOG_ERROR, "%s path not set", 1893 6212 aw148015 fileset_entity_name(fileset)); 1894 7556 Andrew return (FILEBENCH_ERROR); 1895 6212 aw148015 } 1896 6212 aw148015 1897 6212 aw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 1898 6212 aw148015 filebench_log(LOG_ERROR, "%s name not set", 1899 6212 aw148015 fileset_entity_name(fileset)); 1900 7556 Andrew return (FILEBENCH_ERROR); 1901 6212 aw148015 } 1902 6212 aw148015 1903 6212 aw148015 pathlength = strlen(fileset_path) + strlen(fileset_name); 1904 5673 aw148015 1905 5673 aw148015 if (pathlength > 29) 1906 5673 aw148015 pathlength = 29; 1907 5673 aw148015 1908 5673 aw148015 if (first) { 1909 5673 aw148015 filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s", 1910 5673 aw148015 "file size", 1911 5673 aw148015 "dir width", 1912 5673 aw148015 "entries"); 1913 5673 aw148015 } 1914 5673 aw148015 1915 5673 aw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 1916 5673 aw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { 1917 5673 aw148015 filebench_log(LOG_INFO, 1918 5673 aw148015 "%s/%s%s (Raw Device)", 1919 6212 aw148015 fileset_path, fileset_name, &pad[pathlength]); 1920 5673 aw148015 } else { 1921 5673 aw148015 filebench_log(LOG_INFO, 1922 6286 aw148015 "%s/%s%s%9llu (Single File)", 1923 6212 aw148015 fileset_path, fileset_name, &pad[pathlength], 1924 6286 aw148015 (u_longlong_t)avd_get_int(fileset->fs_size)); 1925 5673 aw148015 } 1926 5673 aw148015 } else { 1927 6286 aw148015 filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu", 1928 6212 aw148015 fileset_path, fileset_name, 1929 5673 aw148015 &pad[pathlength], 1930 6286 aw148015 (u_longlong_t)avd_get_int(fileset->fs_size), 1931 6286 aw148015 (u_longlong_t)avd_get_int(fileset->fs_dirwidth), 1932 6286 aw148015 (u_longlong_t)fileset->fs_constentries); 1933 5673 aw148015 } 1934 7556 Andrew return (FILEBENCH_OK); 1935 5673 aw148015 } 1936 7946 Andrew 1937 5673 aw148015 /* 1938 5673 aw148015 * checks to see if the path/name pair points to a raw device. If 1939 5673 aw148015 * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1. 1940 5673 aw148015 * If RAW is not defined, or it is not a raw device, it clears the 1941 5673 aw148015 * raw device flag and returns 0. 1942 5673 aw148015 */ 1943 5673 aw148015 int 1944 5673 aw148015 fileset_checkraw(fileset_t *fileset) 1945 5673 aw148015 { 1946 5673 aw148015 char path[MAXPATHLEN]; 1947 5673 aw148015 struct stat64 sb; 1948 6305 aw148015 char *pathname; 1949 6305 aw148015 char *setname; 1950 5673 aw148015 1951 5673 aw148015 fileset->fs_attrs &= (~FILESET_IS_RAW_DEV); 1952 5673 aw148015 1953 5673 aw148015 #ifdef HAVE_RAW_SUPPORT 1954 5673 aw148015 /* check for raw device */ 1955 6305 aw148015 if ((pathname = avd_get_str(fileset->fs_path)) == NULL) 1956 7556 Andrew return (FILEBENCH_OK); 1957 6305 aw148015 1958 6305 aw148015 if ((setname = avd_get_str(fileset->fs_name)) == NULL) 1959 7556 Andrew return (FILEBENCH_OK); 1960 6305 aw148015 1961 7946 Andrew (void) fb_strlcpy(path, pathname, MAXPATHLEN); 1962 7946 Andrew (void) fb_strlcat(path, "/", MAXPATHLEN); 1963 7946 Andrew (void) fb_strlcat(path, setname, MAXPATHLEN); 1964 5673 aw148015 if ((stat64(path, &sb) == 0) && 1965 5673 aw148015 ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { 1966 5673 aw148015 fileset->fs_attrs |= FILESET_IS_RAW_DEV; 1967 6305 aw148015 if (!(fileset->fs_attrs & FILESET_IS_FILE)) { 1968 6305 aw148015 filebench_log(LOG_ERROR, 1969 6305 aw148015 "WARNING Fileset %s/%s Cannot be RAW device", 1970 6305 aw148015 avd_get_str(fileset->fs_path), 1971 6305 aw148015 avd_get_str(fileset->fs_name)); 1972 6305 aw148015 filebench_shutdown(1); 1973 6305 aw148015 } 1974 6305 aw148015 1975 5673 aw148015 return (1); 1976 5673 aw148015 } 1977 5673 aw148015 #endif /* HAVE_RAW_SUPPORT */ 1978 5673 aw148015 1979 7556 Andrew return (FILEBENCH_OK); 1980 5673 aw148015 } 1981