15184Sek110237 /* 25184Sek110237 * CDDL HEADER START 35184Sek110237 * 45184Sek110237 * The contents of this file are subject to the terms of the 55184Sek110237 * Common Development and Distribution License (the "License"). 65184Sek110237 * You may not use this file except in compliance with the License. 75184Sek110237 * 85184Sek110237 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95184Sek110237 * or http://www.opensolaris.org/os/licensing. 105184Sek110237 * See the License for the specific language governing permissions 115184Sek110237 * and limitations under the License. 125184Sek110237 * 135184Sek110237 * When distributing Covered Code, include this CDDL HEADER in each 145184Sek110237 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155184Sek110237 * If applicable, add the following below this CDDL HEADER, with the 165184Sek110237 * fields enclosed by brackets "[]" replaced with your own identifying 175184Sek110237 * information: Portions Copyright [yyyy] [name of copyright owner] 185184Sek110237 * 195184Sek110237 * CDDL HEADER END 205184Sek110237 */ 215184Sek110237 /* 226212Saw148015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235184Sek110237 * Use is subject to license terms. 246613Sek110237 * 256613Sek110237 * Portions Copyright 2008 Denis Cheng 265184Sek110237 */ 275184Sek110237 285184Sek110237 #include <fcntl.h> 295184Sek110237 #include <pthread.h> 305184Sek110237 #include <errno.h> 315184Sek110237 #include <math.h> 325184Sek110237 #include <libgen.h> 335184Sek110237 #include <sys/mman.h> 346613Sek110237 356613Sek110237 #include "filebench.h" 365184Sek110237 #include "fileset.h" 375184Sek110237 #include "gamma_dist.h" 38*7946SAndrew.W.Wilson@sun.com #include "utils.h" 395184Sek110237 405184Sek110237 /* 415184Sek110237 * File sets, of type fileset_t, are entities which contain 425184Sek110237 * information about collections of files and subdirectories in Filebench. 435184Sek110237 * The fileset, once populated, consists of a tree of fileset entries of 445184Sek110237 * type filesetentry_t which specify files and directories. The fileset 456212Saw148015 * is rooted in a directory specified by fileset_path, and once the populated 465184Sek110237 * fileset has been created, has a tree of directories and files 475184Sek110237 * corresponding to the fileset's filesetentry tree. 486701Saw148015 * 497556SAndrew.W.Wilson@sun.com * Fileset entities are allocated by fileset_define() which is called from 507556SAndrew.W.Wilson@sun.com * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding 517556SAndrew.W.Wilson@sun.com * to the eventual directory and file tree to be instantiated on the storage 52*7946SAndrew.W.Wilson@sun.com * medium is built by fileset_populate(), which is This routine is called 53*7946SAndrew.W.Wilson@sun.com * from fileset_createset(), which is in turn called by fileset_createset(). 54*7946SAndrew.W.Wilson@sun.com * After calling fileset_populate(), fileset_createset() will call 55*7946SAndrew.W.Wilson@sun.com * fileset_create() to pre-allocate designated files and directories. 567556SAndrew.W.Wilson@sun.com * 577556SAndrew.W.Wilson@sun.com * Fileset_createset() is called from parser_gram.y: parser_create_fileset() 587556SAndrew.W.Wilson@sun.com * when a "create fileset" or "run" command is encountered. When the 597556SAndrew.W.Wilson@sun.com * "create fileset" command is used, it is generally paired with 606701Saw148015 * a "create processes" command, and must appear first, in order to 616701Saw148015 * instantiate all the files in the fileset before trying to use them. 625184Sek110237 */ 635184Sek110237 646305Saw148015 static int fileset_checkraw(fileset_t *fileset); 656305Saw148015 667556SAndrew.W.Wilson@sun.com /* maximum parallel allocation control */ 675673Saw148015 #define MAX_PARALLOC_THREADS 32 685673Saw148015 695673Saw148015 /* 705673Saw148015 * returns pointer to file or fileset 715673Saw148015 * string, as appropriate 725673Saw148015 */ 735673Saw148015 static char * 745673Saw148015 fileset_entity_name(fileset_t *fileset) 755673Saw148015 { 765673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) 775673Saw148015 return ("file"); 785673Saw148015 else 795673Saw148015 return ("fileset"); 805673Saw148015 } 815673Saw148015 825184Sek110237 /* 835184Sek110237 * Removes the last file or directory name from a pathname. 845184Sek110237 * Basically removes characters from the end of the path by 855184Sek110237 * setting them to \0 until a forward slash '/' is 865184Sek110237 * encountered. It also removes the forward slash. 875184Sek110237 */ 885184Sek110237 static char * 895184Sek110237 trunc_dirname(char *dir) 905184Sek110237 { 915184Sek110237 char *s = dir + strlen(dir); 925184Sek110237 935184Sek110237 while (s != dir) { 945184Sek110237 int c = *s; 955184Sek110237 965184Sek110237 *s = 0; 975184Sek110237 if (c == '/') 985184Sek110237 break; 995184Sek110237 s--; 1005184Sek110237 } 1015184Sek110237 return (dir); 1025184Sek110237 } 1035184Sek110237 1045184Sek110237 /* 1055184Sek110237 * Prints a list of allowed options and how to specify them. 1065184Sek110237 */ 1075184Sek110237 void 1085184Sek110237 fileset_usage(void) 1095184Sek110237 { 1105673Saw148015 (void) fprintf(stderr, 1115673Saw148015 "define [file name=<name> | fileset name=<name>],path=<pathname>," 1125673Saw148015 ",entries=<number>\n"); 1135673Saw148015 (void) fprintf(stderr, 1146212Saw148015 " [,filesize=[size]]\n"); 1156212Saw148015 (void) fprintf(stderr, 1165673Saw148015 " [,dirwidth=[width]]\n"); 1175673Saw148015 (void) fprintf(stderr, 1186212Saw148015 " [,dirdepthrv=$random_variable_name]\n"); 1196212Saw148015 (void) fprintf(stderr, 1205673Saw148015 " [,dirgamma=[100-10000]] " 1215184Sek110237 "(Gamma * 1000)\n"); 1225184Sek110237 (void) fprintf(stderr, 1235673Saw148015 " [,sizegamma=[100-10000]] (Gamma * 1000)\n"); 1245184Sek110237 (void) fprintf(stderr, 1255184Sek110237 " [,prealloc=[percent]]\n"); 1265673Saw148015 (void) fprintf(stderr, " [,paralloc]\n"); 1275184Sek110237 (void) fprintf(stderr, " [,reuse]\n"); 1285184Sek110237 (void) fprintf(stderr, "\n"); 1295184Sek110237 } 1305184Sek110237 1315184Sek110237 /* 1325184Sek110237 * Frees up memory mapped file region of supplied size. The 1335184Sek110237 * file descriptor "fd" indicates which memory mapped file. 134*7946SAndrew.W.Wilson@sun.com * If successful, returns 0. Otherwise returns -1 if "size" 135*7946SAndrew.W.Wilson@sun.com * is zero, or -1 times the number of times msync() failed. 1365184Sek110237 */ 1375184Sek110237 static int 1385184Sek110237 fileset_freemem(int fd, off64_t size) 1395184Sek110237 { 1405184Sek110237 off64_t left; 1415184Sek110237 int ret = 0; 1425184Sek110237 1435184Sek110237 for (left = size; left > 0; left -= MMAP_SIZE) { 1445184Sek110237 off64_t thismapsize; 1455184Sek110237 caddr_t addr; 1465184Sek110237 1475184Sek110237 thismapsize = MIN(MMAP_SIZE, left); 1485184Sek110237 addr = mmap64(0, thismapsize, PROT_READ|PROT_WRITE, 1495184Sek110237 MAP_SHARED, fd, size - left); 1505184Sek110237 ret += msync(addr, thismapsize, MS_INVALIDATE); 1515184Sek110237 (void) munmap(addr, thismapsize); 1525184Sek110237 } 1535184Sek110237 return (ret); 1545184Sek110237 } 1555184Sek110237 1565184Sek110237 /* 1575184Sek110237 * Creates a path string from the filesetentry_t "*entry" 1585184Sek110237 * and all of its parent's path names. The resulting path 1595184Sek110237 * is a concatination of all the individual parent paths. 1605184Sek110237 * Allocates memory for the path string and returns a 1615184Sek110237 * pointer to it. 1625184Sek110237 */ 1635184Sek110237 char * 1645184Sek110237 fileset_resolvepath(filesetentry_t *entry) 1655184Sek110237 { 1665184Sek110237 filesetentry_t *fsep = entry; 1675184Sek110237 char path[MAXPATHLEN]; 1685184Sek110237 char pathtmp[MAXPATHLEN]; 1695184Sek110237 char *s; 1705184Sek110237 171*7946SAndrew.W.Wilson@sun.com path[0] = '\0'; 1725184Sek110237 while (fsep->fse_parent) { 1735184Sek110237 (void) strcpy(pathtmp, "/"); 174*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(pathtmp, fsep->fse_path, MAXPATHLEN); 175*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(pathtmp, path, MAXPATHLEN); 176*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, pathtmp, MAXPATHLEN); 1775184Sek110237 fsep = fsep->fse_parent; 1785184Sek110237 } 1795184Sek110237 1805184Sek110237 s = malloc(strlen(path) + 1); 181*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(s, path, MAXPATHLEN); 1825184Sek110237 return (s); 1835184Sek110237 } 1845184Sek110237 1855184Sek110237 /* 1865184Sek110237 * Creates multiple nested directories as required by the 1875184Sek110237 * supplied path. Starts at the end of the path, creating 1885184Sek110237 * a list of directories to mkdir, up to the root of the 1895184Sek110237 * path, then mkdirs them one at a time from the root on down. 1905184Sek110237 */ 1915184Sek110237 static int 1925184Sek110237 fileset_mkdir(char *path, int mode) 1935184Sek110237 { 1945184Sek110237 char *p; 1955184Sek110237 char *dirs[65536]; 1965184Sek110237 int i = 0; 1975184Sek110237 1985184Sek110237 if ((p = strdup(path)) == NULL) 1995184Sek110237 goto null_str; 2005184Sek110237 2015184Sek110237 /* 2025184Sek110237 * Fill an array of subdirectory path names until either we 2035184Sek110237 * reach the root or encounter an already existing subdirectory 2045184Sek110237 */ 2055184Sek110237 /* CONSTCOND */ 2065184Sek110237 while (1) { 2075184Sek110237 struct stat64 sb; 2085184Sek110237 2095184Sek110237 if (stat64(p, &sb) == 0) 2105184Sek110237 break; 2115184Sek110237 if (strlen(p) < 3) 2125184Sek110237 break; 2135184Sek110237 if ((dirs[i] = strdup(p)) == NULL) { 2145184Sek110237 free(p); 2155184Sek110237 goto null_str; 2165184Sek110237 } 2175184Sek110237 2185184Sek110237 (void) trunc_dirname(p); 2195184Sek110237 i++; 2205184Sek110237 } 2215184Sek110237 2225184Sek110237 /* Make the directories, from closest to root downwards. */ 2235184Sek110237 for (--i; i >= 0; i--) { 2245184Sek110237 (void) mkdir(dirs[i], mode); 2255184Sek110237 free(dirs[i]); 2265184Sek110237 } 2275184Sek110237 2285184Sek110237 free(p); 2297556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 2305184Sek110237 2315184Sek110237 null_str: 2325184Sek110237 /* clean up */ 2335184Sek110237 for (--i; i >= 0; i--) 2345184Sek110237 free(dirs[i]); 2355184Sek110237 2365184Sek110237 filebench_log(LOG_ERROR, 2375184Sek110237 "Failed to create directory path %s: Out of memory", path); 2387556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2395184Sek110237 } 2405184Sek110237 2415673Saw148015 /* 2425673Saw148015 * creates the subdirectory tree for a fileset. 2435673Saw148015 */ 2445673Saw148015 static int 2455673Saw148015 fileset_create_subdirs(fileset_t *fileset, char *filesetpath) 2465673Saw148015 { 2475673Saw148015 filesetentry_t *direntry; 2485673Saw148015 char full_path[MAXPATHLEN]; 2495673Saw148015 char *part_path; 2505673Saw148015 2515673Saw148015 /* walk the subdirectory list, enstanciating subdirs */ 2525673Saw148015 direntry = fileset->fs_dirlist; 2535673Saw148015 while (direntry) { 254*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(full_path, filesetpath, MAXPATHLEN); 2555673Saw148015 part_path = fileset_resolvepath(direntry); 256*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(full_path, part_path, MAXPATHLEN); 2575673Saw148015 free(part_path); 2585673Saw148015 2595673Saw148015 /* now create this portion of the subdirectory tree */ 2607556SAndrew.W.Wilson@sun.com if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR) 2617556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2625673Saw148015 2635673Saw148015 direntry = direntry->fse_dirnext; 2645673Saw148015 } 2657556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 2665673Saw148015 } 2675673Saw148015 2685673Saw148015 /* 269*7946SAndrew.W.Wilson@sun.com * given a fileset entry, determines if the associated leaf directory 270*7946SAndrew.W.Wilson@sun.com * needs to be made or not, and if so does the mkdir. 271*7946SAndrew.W.Wilson@sun.com */ 272*7946SAndrew.W.Wilson@sun.com static int 273*7946SAndrew.W.Wilson@sun.com fileset_alloc_leafdir(filesetentry_t *entry) 274*7946SAndrew.W.Wilson@sun.com { 275*7946SAndrew.W.Wilson@sun.com fileset_t *fileset; 276*7946SAndrew.W.Wilson@sun.com char path[MAXPATHLEN]; 277*7946SAndrew.W.Wilson@sun.com struct stat64 sb; 278*7946SAndrew.W.Wilson@sun.com char *pathtmp; 279*7946SAndrew.W.Wilson@sun.com 280*7946SAndrew.W.Wilson@sun.com fileset = entry->fse_fileset; 281*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 282*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 283*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 284*7946SAndrew.W.Wilson@sun.com pathtmp = fileset_resolvepath(entry); 285*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 286*7946SAndrew.W.Wilson@sun.com free(pathtmp); 287*7946SAndrew.W.Wilson@sun.com 288*7946SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); 289*7946SAndrew.W.Wilson@sun.com 290*7946SAndrew.W.Wilson@sun.com /* see if not reusing and this directory does not exist */ 291*7946SAndrew.W.Wilson@sun.com if (!((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0))) { 292*7946SAndrew.W.Wilson@sun.com 293*7946SAndrew.W.Wilson@sun.com /* No file or not reusing, so create */ 294*7946SAndrew.W.Wilson@sun.com if (mkdir(path, 0755) < 0) { 295*7946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 296*7946SAndrew.W.Wilson@sun.com "Failed to pre-allocate leaf directory %s: %s", 297*7946SAndrew.W.Wilson@sun.com path, strerror(errno)); 298*7946SAndrew.W.Wilson@sun.com 299*7946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 300*7946SAndrew.W.Wilson@sun.com } 301*7946SAndrew.W.Wilson@sun.com } 302*7946SAndrew.W.Wilson@sun.com 303*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 304*7946SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS; 305*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_leafdirs++; 306*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 307*7946SAndrew.W.Wilson@sun.com 308*7946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 309*7946SAndrew.W.Wilson@sun.com } 310*7946SAndrew.W.Wilson@sun.com 311*7946SAndrew.W.Wilson@sun.com /* 3125673Saw148015 * given a fileset entry, determines if the associated file 3135673Saw148015 * needs to be allocated or not, and if so does the allocation. 3145673Saw148015 */ 3155673Saw148015 static int 3165673Saw148015 fileset_alloc_file(filesetentry_t *entry) 3175673Saw148015 { 318*7946SAndrew.W.Wilson@sun.com fileset_t *fileset; 3195673Saw148015 char path[MAXPATHLEN]; 3205673Saw148015 char *buf; 3215673Saw148015 struct stat64 sb; 3225673Saw148015 char *pathtmp; 3235673Saw148015 off64_t seek; 3245673Saw148015 int fd; 3255673Saw148015 326*7946SAndrew.W.Wilson@sun.com fileset = entry->fse_fileset; 327*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 328*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 329*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 3305673Saw148015 pathtmp = fileset_resolvepath(entry); 331*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 332*7946SAndrew.W.Wilson@sun.com free(pathtmp); 3335673Saw148015 3345673Saw148015 filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); 3355673Saw148015 3365673Saw148015 /* see if reusing and this file exists */ 3375673Saw148015 if ((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0)) { 3385673Saw148015 if ((fd = open64(path, O_RDWR)) < 0) { 3395673Saw148015 filebench_log(LOG_INFO, 3405673Saw148015 "Attempted but failed to Re-use file %s", 3415673Saw148015 path); 3427556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 3435673Saw148015 } 3445673Saw148015 3455673Saw148015 if (sb.st_size == (off64_t)entry->fse_size) { 3467556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL, 3475673Saw148015 "Re-using file %s", path); 3485673Saw148015 349*7946SAndrew.W.Wilson@sun.com if (!avd_get_bool(fileset->fs_cached)) 3505673Saw148015 (void) fileset_freemem(fd, 3515673Saw148015 entry->fse_size); 3525673Saw148015 353*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 3545673Saw148015 entry->fse_flags |= FSE_EXISTS; 355*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_files++; 356*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 3576701Saw148015 3585673Saw148015 (void) close(fd); 3597556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 3605673Saw148015 3615673Saw148015 } else if (sb.st_size > (off64_t)entry->fse_size) { 3625673Saw148015 /* reuse, but too large */ 3635673Saw148015 filebench_log(LOG_INFO, 3645673Saw148015 "Truncating & re-using file %s", path); 3655673Saw148015 3666613Sek110237 #ifdef HAVE_FTRUNCATE64 3676613Sek110237 (void) ftruncate64(fd, (off64_t)entry->fse_size); 3686613Sek110237 #else 3696613Sek110237 (void) ftruncate(fd, (off_t)entry->fse_size); 3706613Sek110237 #endif 3715673Saw148015 372*7946SAndrew.W.Wilson@sun.com if (!avd_get_bool(fileset->fs_cached)) 3735673Saw148015 (void) fileset_freemem(fd, 3745673Saw148015 entry->fse_size); 3755673Saw148015 376*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 3775673Saw148015 entry->fse_flags |= FSE_EXISTS; 378*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_files++; 379*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 3806701Saw148015 3815673Saw148015 (void) close(fd); 3827556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 3835673Saw148015 } 3845673Saw148015 } else { 3855673Saw148015 3865673Saw148015 /* No file or not reusing, so create */ 3875673Saw148015 if ((fd = open64(path, O_RDWR | O_CREAT, 0644)) < 0) { 3885673Saw148015 filebench_log(LOG_ERROR, 3895673Saw148015 "Failed to pre-allocate file %s: %s", 3905673Saw148015 path, strerror(errno)); 3915673Saw148015 3927556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 3935673Saw148015 } 3945673Saw148015 } 3955673Saw148015 3965673Saw148015 if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) 3977556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 3985673Saw148015 399*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 4007556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS; 401*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_files++; 402*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 4036701Saw148015 4045673Saw148015 for (seek = 0; seek < entry->fse_size; ) { 4055673Saw148015 off64_t wsize; 4065673Saw148015 int ret = 0; 4075673Saw148015 4085673Saw148015 /* 4095673Saw148015 * Write FILE_ALLOC_BLOCK's worth, 4105673Saw148015 * except on last write 4115673Saw148015 */ 4125673Saw148015 wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK); 4135673Saw148015 4145673Saw148015 ret = write(fd, buf, wsize); 4155673Saw148015 if (ret != wsize) { 4165673Saw148015 filebench_log(LOG_ERROR, 4175673Saw148015 "Failed to pre-allocate file %s: %s", 4185673Saw148015 path, strerror(errno)); 4195673Saw148015 (void) close(fd); 4205673Saw148015 free(buf); 4217556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 4225673Saw148015 } 4235673Saw148015 seek += wsize; 4245673Saw148015 } 4255673Saw148015 426*7946SAndrew.W.Wilson@sun.com if (!avd_get_bool(fileset->fs_cached)) 4275673Saw148015 (void) fileset_freemem(fd, entry->fse_size); 4285673Saw148015 4295673Saw148015 (void) close(fd); 4305673Saw148015 4315673Saw148015 free(buf); 4325673Saw148015 4335673Saw148015 filebench_log(LOG_DEBUG_IMPL, 4346286Saw148015 "Pre-allocated file %s size %llu", 4356286Saw148015 path, (u_longlong_t)entry->fse_size); 4365673Saw148015 4377556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 4385673Saw148015 } 4395673Saw148015 4405673Saw148015 /* 4415673Saw148015 * given a fileset entry, determines if the associated file 4425673Saw148015 * needs to be allocated or not, and if so does the allocation. 4437556SAndrew.W.Wilson@sun.com * Sets shm_fsparalloc_count to -1 on error. 4445673Saw148015 */ 4455673Saw148015 static void * 4465673Saw148015 fileset_alloc_thread(filesetentry_t *entry) 4475673Saw148015 { 4487556SAndrew.W.Wilson@sun.com if (fileset_alloc_file(entry) == FILEBENCH_ERROR) { 4497556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 4507556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count = -1; 4515673Saw148015 } else { 4527556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 4537556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count--; 4545673Saw148015 } 4555673Saw148015 4567556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv); 4577556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); 4585673Saw148015 4595673Saw148015 pthread_exit(NULL); 4605673Saw148015 return (NULL); 4615673Saw148015 } 4625673Saw148015 4635184Sek110237 4645184Sek110237 /* 4655184Sek110237 * First creates the parent directories of the file using 4665184Sek110237 * fileset_mkdir(). Then Optionally sets the O_DSYNC flag 4675184Sek110237 * and opens the file with open64(). It unlocks the fileset 4685184Sek110237 * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags 4695184Sek110237 * as requested, and returns the file descriptor integer 4705184Sek110237 * for the opened file. 4715184Sek110237 */ 4725184Sek110237 int 4735184Sek110237 fileset_openfile(fileset_t *fileset, 4747736SAndrew.W.Wilson@sun.com filesetentry_t *entry, int flag, int filemode, int attrs) 4755184Sek110237 { 4765184Sek110237 char path[MAXPATHLEN]; 4775184Sek110237 char dir[MAXPATHLEN]; 4785184Sek110237 char *pathtmp; 4795184Sek110237 struct stat64 sb; 4805184Sek110237 int fd; 4815184Sek110237 int open_attrs = 0; 4825184Sek110237 483*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); 484*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 485*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); 4865184Sek110237 pathtmp = fileset_resolvepath(entry); 487*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN); 488*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(dir, path, MAXPATHLEN); 4895184Sek110237 free(pathtmp); 4905184Sek110237 (void) trunc_dirname(dir); 4915184Sek110237 4925184Sek110237 /* If we are going to create a file, create the parent dirs */ 4935184Sek110237 if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) { 4947556SAndrew.W.Wilson@sun.com if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR) 4957556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 4966701Saw148015 } 4976701Saw148015 4985184Sek110237 if (attrs & FLOW_ATTR_DSYNC) { 4995184Sek110237 #ifdef sun 5005184Sek110237 open_attrs |= O_DSYNC; 5015184Sek110237 #else 5025184Sek110237 open_attrs |= O_FSYNC; 5035184Sek110237 #endif 5045184Sek110237 } 5055184Sek110237 5067736SAndrew.W.Wilson@sun.com if ((fd = open64(path, flag | open_attrs, filemode)) < 0) { 5075184Sek110237 filebench_log(LOG_ERROR, 5085184Sek110237 "Failed to open file %s: %s", 5095184Sek110237 path, strerror(errno)); 5107556SAndrew.W.Wilson@sun.com 5117556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 5127556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 5135184Sek110237 } 5147556SAndrew.W.Wilson@sun.com 5157556SAndrew.W.Wilson@sun.com if (flag & O_CREAT) 5167556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, TRUE); 5177556SAndrew.W.Wilson@sun.com else 5187556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 5195184Sek110237 5205184Sek110237 #ifdef sun 5215184Sek110237 if (attrs & FLOW_ATTR_DIRECTIO) 5225184Sek110237 (void) directio(fd, DIRECTIO_ON); 5235184Sek110237 else 5245184Sek110237 (void) directio(fd, DIRECTIO_OFF); 5255184Sek110237 #endif 5265184Sek110237 5275184Sek110237 return (fd); 5285184Sek110237 } 5295184Sek110237 5305184Sek110237 5315184Sek110237 /* 5325184Sek110237 * Selects a fileset entry from a fileset. If the 533*7946SAndrew.W.Wilson@sun.com * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry, 534*7946SAndrew.W.Wilson@sun.com * if the FILESET_PICKDIR flag is set it will pick a non leaf directory 5355184Sek110237 * entry, otherwise a file entry. The FILESET_PICKRESET 5365184Sek110237 * flag will cause it to reset the free list to the 5375184Sek110237 * overall list (file or directory). The FILESET_PICKUNIQUE 5385184Sek110237 * flag will take an entry off of one of the free (unused) 5395184Sek110237 * lists (file or directory), otherwise the entry will be 5405184Sek110237 * picked off of one of the rotor lists (file or directory). 5415184Sek110237 * The FILESET_PICKEXISTS will insure that only extant 5425184Sek110237 * (FSE_EXISTS) state files are selected, while 5435184Sek110237 * FILESET_PICKNOEXIST insures that only non extant 5445184Sek110237 * (not FSE_EXISTS) state files are selected. 5456391Saw148015 * Note that the selected fileset entry (file) is returned 5467556SAndrew.W.Wilson@sun.com * with its FSE_BUSY flag (in fse_flags) set. 5475184Sek110237 */ 5485184Sek110237 filesetentry_t * 5495184Sek110237 fileset_pick(fileset_t *fileset, int flags, int tid) 5505184Sek110237 { 5515184Sek110237 filesetentry_t *entry = NULL; 5525184Sek110237 filesetentry_t *first = NULL; 5535184Sek110237 5547556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 5557556SAndrew.W.Wilson@sun.com 5567556SAndrew.W.Wilson@sun.com /* see if we have to wait for available files or directories */ 557*7946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) { 558*7946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE: 559*7946SAndrew.W.Wilson@sun.com if (fileset->fs_filelist == NULL) 560*7946SAndrew.W.Wilson@sun.com goto empty; 5617556SAndrew.W.Wilson@sun.com while (fileset->fs_idle_files == 0) { 5627556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_files_cv, 5637556SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 5647556SAndrew.W.Wilson@sun.com } 565*7946SAndrew.W.Wilson@sun.com break; 566*7946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR: 567*7946SAndrew.W.Wilson@sun.com if (fileset->fs_dirlist == NULL) 568*7946SAndrew.W.Wilson@sun.com goto empty; 569*7946SAndrew.W.Wilson@sun.com while (fileset->fs_idle_dirs == 0) { 570*7946SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv, 571*7946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 572*7946SAndrew.W.Wilson@sun.com } 573*7946SAndrew.W.Wilson@sun.com break; 574*7946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR: 575*7946SAndrew.W.Wilson@sun.com if (fileset->fs_leafdirlist == NULL) 576*7946SAndrew.W.Wilson@sun.com goto empty; 577*7946SAndrew.W.Wilson@sun.com while (fileset->fs_idle_leafdirs == 0) { 578*7946SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv, 579*7946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 580*7946SAndrew.W.Wilson@sun.com } 581*7946SAndrew.W.Wilson@sun.com break; 5827556SAndrew.W.Wilson@sun.com } 5835184Sek110237 5846701Saw148015 /* see if asking for impossible */ 585*7946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) { 586*7946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE: 587*7946SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKEXISTS) { 588*7946SAndrew.W.Wilson@sun.com if (fileset->fs_num_act_files == 0) { 589*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock( 590*7946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 591*7946SAndrew.W.Wilson@sun.com return (NULL); 592*7946SAndrew.W.Wilson@sun.com } 593*7946SAndrew.W.Wilson@sun.com } else if (flags & FILESET_PICKNOEXIST) { 594*7946SAndrew.W.Wilson@sun.com if (fileset->fs_num_act_files == 595*7946SAndrew.W.Wilson@sun.com fileset->fs_realfiles) { 596*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock( 597*7946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 598*7946SAndrew.W.Wilson@sun.com return (NULL); 599*7946SAndrew.W.Wilson@sun.com } 6006701Saw148015 } 601*7946SAndrew.W.Wilson@sun.com break; 602*7946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR: 603*7946SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKEXISTS) { 604*7946SAndrew.W.Wilson@sun.com if (fileset->fs_num_act_leafdirs == 0) { 605*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock( 606*7946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 607*7946SAndrew.W.Wilson@sun.com return (NULL); 608*7946SAndrew.W.Wilson@sun.com } 609*7946SAndrew.W.Wilson@sun.com } else if (flags & FILESET_PICKNOEXIST) { 610*7946SAndrew.W.Wilson@sun.com if (fileset->fs_num_act_leafdirs == 611*7946SAndrew.W.Wilson@sun.com fileset->fs_realleafdirs) { 612*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock( 613*7946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 614*7946SAndrew.W.Wilson@sun.com return (NULL); 615*7946SAndrew.W.Wilson@sun.com } 6166701Saw148015 } 617*7946SAndrew.W.Wilson@sun.com break; 618*7946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR: 619*7946SAndrew.W.Wilson@sun.com default: 620*7946SAndrew.W.Wilson@sun.com break; 6216701Saw148015 } 6226701Saw148015 6235184Sek110237 while (entry == NULL) { 6245184Sek110237 625*7946SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKRESET) { 626*7946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) { 627*7946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE: 628*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_filelist; 629*7946SAndrew.W.Wilson@sun.com while (entry) { 630*7946SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE; 631*7946SAndrew.W.Wilson@sun.com entry = entry->fse_filenext; 632*7946SAndrew.W.Wilson@sun.com } 633*7946SAndrew.W.Wilson@sun.com fileset->fs_filefree = fileset->fs_filelist; 634*7946SAndrew.W.Wilson@sun.com break; 635*7946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR: 636*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_dirlist; 637*7946SAndrew.W.Wilson@sun.com while (entry) { 638*7946SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE; 639*7946SAndrew.W.Wilson@sun.com entry = entry->fse_dirnext; 640*7946SAndrew.W.Wilson@sun.com } 641*7946SAndrew.W.Wilson@sun.com fileset->fs_dirfree = fileset->fs_dirlist; 642*7946SAndrew.W.Wilson@sun.com break; 643*7946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR: 644*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_leafdirlist; 645*7946SAndrew.W.Wilson@sun.com while (entry) { 646*7946SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE; 647*7946SAndrew.W.Wilson@sun.com entry = entry->fse_leafdirnext; 648*7946SAndrew.W.Wilson@sun.com } 649*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirfree = 650*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirlist; 651*7946SAndrew.W.Wilson@sun.com break; 6525184Sek110237 } 6535184Sek110237 } 6545184Sek110237 6555184Sek110237 if (flags & FILESET_PICKUNIQUE) { 656*7946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) { 657*7946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE: 658*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_filefree; 659*7946SAndrew.W.Wilson@sun.com if (entry == NULL) 660*7946SAndrew.W.Wilson@sun.com goto empty; 661*7946SAndrew.W.Wilson@sun.com fileset->fs_filefree = entry->fse_filenext; 662*7946SAndrew.W.Wilson@sun.com break; 663*7946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR: 6645184Sek110237 entry = fileset->fs_dirfree; 6655184Sek110237 if (entry == NULL) 6665184Sek110237 goto empty; 6675184Sek110237 fileset->fs_dirfree = entry->fse_dirnext; 668*7946SAndrew.W.Wilson@sun.com break; 669*7946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR: 670*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_leafdirfree; 6715184Sek110237 if (entry == NULL) 6725184Sek110237 goto empty; 673*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirfree = 674*7946SAndrew.W.Wilson@sun.com entry->fse_leafdirnext; 675*7946SAndrew.W.Wilson@sun.com break; 6765184Sek110237 } 6775184Sek110237 entry->fse_flags &= ~FSE_FREE; 6785184Sek110237 } else { 679*7946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) { 680*7946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE: 6817556SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKNOEXIST) { 6827556SAndrew.W.Wilson@sun.com entry = fileset->fs_file_ne_rotor; 6837556SAndrew.W.Wilson@sun.com if (entry == NULL) 6847556SAndrew.W.Wilson@sun.com fileset->fs_file_ne_rotor = 6857556SAndrew.W.Wilson@sun.com entry = 6867556SAndrew.W.Wilson@sun.com fileset->fs_filelist; 6877556SAndrew.W.Wilson@sun.com fileset->fs_file_ne_rotor = 6887556SAndrew.W.Wilson@sun.com entry->fse_filenext; 6897556SAndrew.W.Wilson@sun.com } else { 6907556SAndrew.W.Wilson@sun.com entry = fileset->fs_filerotor[tid]; 6917556SAndrew.W.Wilson@sun.com if (entry == NULL) 6927556SAndrew.W.Wilson@sun.com fileset->fs_filerotor[tid] = 6937556SAndrew.W.Wilson@sun.com entry = 6947556SAndrew.W.Wilson@sun.com fileset->fs_filelist; 6955184Sek110237 fileset->fs_filerotor[tid] = 6967556SAndrew.W.Wilson@sun.com entry->fse_filenext; 6977556SAndrew.W.Wilson@sun.com } 698*7946SAndrew.W.Wilson@sun.com break; 699*7946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR: 700*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_dirrotor; 701*7946SAndrew.W.Wilson@sun.com if (entry == NULL) 702*7946SAndrew.W.Wilson@sun.com fileset->fs_dirrotor = 703*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_dirlist; 704*7946SAndrew.W.Wilson@sun.com fileset->fs_dirrotor = entry->fse_dirnext; 705*7946SAndrew.W.Wilson@sun.com break; 706*7946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR: 707*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_leafdirrotor; 708*7946SAndrew.W.Wilson@sun.com if (entry == NULL) 709*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirrotor = 710*7946SAndrew.W.Wilson@sun.com entry = fileset->fs_leafdirlist; 711*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirrotor = 712*7946SAndrew.W.Wilson@sun.com entry->fse_leafdirnext; 713*7946SAndrew.W.Wilson@sun.com break; 7145184Sek110237 } 7155184Sek110237 } 7165184Sek110237 7175184Sek110237 if (first == entry) 7185184Sek110237 goto empty; 7195184Sek110237 7205184Sek110237 if (first == NULL) 7215184Sek110237 first = entry; 7225184Sek110237 7237556SAndrew.W.Wilson@sun.com /* see if entry in use */ 7247556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_BUSY) { 7257556SAndrew.W.Wilson@sun.com 7267556SAndrew.W.Wilson@sun.com /* it is, so try next */ 7277556SAndrew.W.Wilson@sun.com entry = NULL; 7287556SAndrew.W.Wilson@sun.com continue; 7297556SAndrew.W.Wilson@sun.com } 7305184Sek110237 7315184Sek110237 /* If we ask for an existing file, go round again */ 7325184Sek110237 if ((flags & FILESET_PICKEXISTS) && 7337556SAndrew.W.Wilson@sun.com !(entry->fse_flags & FSE_EXISTS)) 7345184Sek110237 entry = NULL; 7355184Sek110237 7365184Sek110237 /* If we ask for not an existing file, go round again */ 7375184Sek110237 if ((flags & FILESET_PICKNOEXIST) && 7387556SAndrew.W.Wilson@sun.com (entry->fse_flags & FSE_EXISTS)) 7395184Sek110237 entry = NULL; 7405184Sek110237 } 7415184Sek110237 7427556SAndrew.W.Wilson@sun.com /* update file or directory idle counts */ 743*7946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) { 744*7946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE: 745*7946SAndrew.W.Wilson@sun.com fileset->fs_idle_files--; 746*7946SAndrew.W.Wilson@sun.com break; 747*7946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR: 7487556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs--; 749*7946SAndrew.W.Wilson@sun.com break; 750*7946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR: 751*7946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs--; 752*7946SAndrew.W.Wilson@sun.com break; 753*7946SAndrew.W.Wilson@sun.com } 7547556SAndrew.W.Wilson@sun.com 7557556SAndrew.W.Wilson@sun.com /* Indicate that file or directory is now busy */ 7567556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_BUSY; 7577556SAndrew.W.Wilson@sun.com 7587556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 7595184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path); 7605184Sek110237 return (entry); 7615184Sek110237 7625184Sek110237 empty: 7637556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 7645184Sek110237 return (NULL); 7655184Sek110237 } 7665184Sek110237 7675184Sek110237 /* 7687556SAndrew.W.Wilson@sun.com * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads 7697556SAndrew.W.Wilson@sun.com * that are waiting for a NOT BUSY filesetentry. Also sets whether it is 7707556SAndrew.W.Wilson@sun.com * existant or not, or leaves that designation alone. 7717556SAndrew.W.Wilson@sun.com */ 7727556SAndrew.W.Wilson@sun.com void 7737556SAndrew.W.Wilson@sun.com fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val) 7747556SAndrew.W.Wilson@sun.com { 7757556SAndrew.W.Wilson@sun.com fileset_t *fileset = NULL; 7767556SAndrew.W.Wilson@sun.com 7777556SAndrew.W.Wilson@sun.com if (entry) 7787556SAndrew.W.Wilson@sun.com fileset = entry->fse_fileset; 7797556SAndrew.W.Wilson@sun.com 7807556SAndrew.W.Wilson@sun.com if (fileset == NULL) { 7817556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!"); 7827556SAndrew.W.Wilson@sun.com return; 7837556SAndrew.W.Wilson@sun.com } 7847556SAndrew.W.Wilson@sun.com 7857556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 7867556SAndrew.W.Wilson@sun.com 7877556SAndrew.W.Wilson@sun.com /* increment idle count, clear FSE_BUSY and signal IF it was busy */ 7887556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_BUSY) { 7897556SAndrew.W.Wilson@sun.com 7907556SAndrew.W.Wilson@sun.com /* unbusy it */ 7917556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_BUSY); 7927556SAndrew.W.Wilson@sun.com 7937556SAndrew.W.Wilson@sun.com /* release any threads waiting for unbusy */ 7947556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_THRD_WAITNG) { 7957556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_THRD_WAITNG); 7967556SAndrew.W.Wilson@sun.com (void) pthread_cond_broadcast( 7977556SAndrew.W.Wilson@sun.com &fileset->fs_thrd_wait_cv); 7987556SAndrew.W.Wilson@sun.com } 7997556SAndrew.W.Wilson@sun.com 8007556SAndrew.W.Wilson@sun.com /* increment idle count and signal waiting threads */ 801*7946SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) { 802*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE: 803*7946SAndrew.W.Wilson@sun.com fileset->fs_idle_files++; 804*7946SAndrew.W.Wilson@sun.com if (fileset->fs_idle_files == 1) { 805*7946SAndrew.W.Wilson@sun.com (void) pthread_cond_signal( 806*7946SAndrew.W.Wilson@sun.com &fileset->fs_idle_files_cv); 807*7946SAndrew.W.Wilson@sun.com } 808*7946SAndrew.W.Wilson@sun.com break; 809*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR: 8107556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs++; 8117556SAndrew.W.Wilson@sun.com if (fileset->fs_idle_dirs == 1) { 8127556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal( 8137556SAndrew.W.Wilson@sun.com &fileset->fs_idle_dirs_cv); 8147556SAndrew.W.Wilson@sun.com } 815*7946SAndrew.W.Wilson@sun.com break; 816*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR: 817*7946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs++; 818*7946SAndrew.W.Wilson@sun.com if (fileset->fs_idle_leafdirs == 1) { 8197556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal( 820*7946SAndrew.W.Wilson@sun.com &fileset->fs_idle_leafdirs_cv); 8217556SAndrew.W.Wilson@sun.com } 822*7946SAndrew.W.Wilson@sun.com break; 8237556SAndrew.W.Wilson@sun.com } 8247556SAndrew.W.Wilson@sun.com } 8257556SAndrew.W.Wilson@sun.com 8267556SAndrew.W.Wilson@sun.com /* modify FSE_EXIST flag and actual dirs/files count, if requested */ 8277556SAndrew.W.Wilson@sun.com if (update_exist) { 8287556SAndrew.W.Wilson@sun.com if (new_exist_val == TRUE) { 8297556SAndrew.W.Wilson@sun.com if (!(entry->fse_flags & FSE_EXISTS)) { 8307556SAndrew.W.Wilson@sun.com 8317556SAndrew.W.Wilson@sun.com /* asked to set, and it was clear */ 8327556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS; 833*7946SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) { 834*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE: 8357556SAndrew.W.Wilson@sun.com fileset->fs_num_act_files++; 836*7946SAndrew.W.Wilson@sun.com break; 837*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR: 838*7946SAndrew.W.Wilson@sun.com break; 839*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR: 840*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_leafdirs++; 841*7946SAndrew.W.Wilson@sun.com break; 842*7946SAndrew.W.Wilson@sun.com } 8437556SAndrew.W.Wilson@sun.com } 8447556SAndrew.W.Wilson@sun.com } else { 8457556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_EXISTS) { 8467556SAndrew.W.Wilson@sun.com 8477556SAndrew.W.Wilson@sun.com /* asked to clear, and it was set */ 8487556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_EXISTS); 849*7946SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) { 850*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE: 8517556SAndrew.W.Wilson@sun.com fileset->fs_num_act_files--; 852*7946SAndrew.W.Wilson@sun.com break; 853*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR: 854*7946SAndrew.W.Wilson@sun.com break; 855*7946SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR: 856*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_leafdirs--; 857*7946SAndrew.W.Wilson@sun.com break; 858*7946SAndrew.W.Wilson@sun.com } 8597556SAndrew.W.Wilson@sun.com } 8607556SAndrew.W.Wilson@sun.com } 8617556SAndrew.W.Wilson@sun.com } 8627556SAndrew.W.Wilson@sun.com 8637556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 8647556SAndrew.W.Wilson@sun.com } 8657556SAndrew.W.Wilson@sun.com 8667556SAndrew.W.Wilson@sun.com /* 8675184Sek110237 * Given a fileset "fileset", create the associated files as 8685184Sek110237 * specified in the attributes of the fileset. The fileset is 8696212Saw148015 * rooted in a directory whose pathname is in fileset_path. If the 8705184Sek110237 * directory exists, meaning that there is already a fileset, 8716212Saw148015 * and the fileset_reuse attribute is false, then remove it and all 8725184Sek110237 * its contained files and subdirectories. Next, the routine 8735184Sek110237 * creates a root directory for the fileset. All the file type 8745184Sek110237 * filesetentries are cycled through creating as needed 8755184Sek110237 * their containing subdirectory trees in the filesystem and 8766212Saw148015 * creating actual files for fileset_preallocpercent of them. The 8775184Sek110237 * created files are filled with fse_size bytes of unitialized 8787556SAndrew.W.Wilson@sun.com * data. The routine returns FILEBENCH_ERROR on errors, 8797556SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success. 8805184Sek110237 */ 8815184Sek110237 static int 8825184Sek110237 fileset_create(fileset_t *fileset) 8835184Sek110237 { 8845184Sek110237 filesetentry_t *entry; 8855184Sek110237 char path[MAXPATHLEN]; 8865184Sek110237 struct stat64 sb; 887*7946SAndrew.W.Wilson@sun.com int pickflags; 8885184Sek110237 hrtime_t start = gethrtime(); 8896212Saw148015 char *fileset_path; 8906212Saw148015 char *fileset_name; 8916212Saw148015 int randno; 8925184Sek110237 int preallocated = 0; 8937736SAndrew.W.Wilson@sun.com int reusing; 8945184Sek110237 8956212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 8965673Saw148015 filebench_log(LOG_ERROR, "%s path not set", 8975673Saw148015 fileset_entity_name(fileset)); 8987556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 8995184Sek110237 } 9005184Sek110237 9016212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 9026212Saw148015 filebench_log(LOG_ERROR, "%s name not set", 9036212Saw148015 fileset_entity_name(fileset)); 9047556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 9056212Saw148015 } 9066212Saw148015 907*7946SAndrew.W.Wilson@sun.com /* declare all files currently non existant (single threaded code) */ 908*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_files = 0; 909*7946SAndrew.W.Wilson@sun.com 9105673Saw148015 #ifdef HAVE_RAW_SUPPORT 9115673Saw148015 /* treat raw device as special case */ 9125673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 9137556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 9145673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 9155673Saw148015 9165184Sek110237 /* XXX Add check to see if there is enough space */ 9175184Sek110237 9187736SAndrew.W.Wilson@sun.com /* set up path to fileset */ 919*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, fileset_path, MAXPATHLEN); 920*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 921*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, fileset_name, MAXPATHLEN); 9227736SAndrew.W.Wilson@sun.com 9237736SAndrew.W.Wilson@sun.com /* if exists and resusing, then don't create new */ 9247736SAndrew.W.Wilson@sun.com if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) && 9257736SAndrew.W.Wilson@sun.com (strlen(avd_get_str(fileset->fs_path)) > 2)) && 9267736SAndrew.W.Wilson@sun.com avd_get_bool(fileset->fs_reuse)) { 9277736SAndrew.W.Wilson@sun.com reusing = 1; 9287736SAndrew.W.Wilson@sun.com } else { 9297736SAndrew.W.Wilson@sun.com reusing = 0; 9307736SAndrew.W.Wilson@sun.com } 9317736SAndrew.W.Wilson@sun.com 9327736SAndrew.W.Wilson@sun.com if (!reusing) { 9337736SAndrew.W.Wilson@sun.com char cmd[MAXPATHLEN]; 9345184Sek110237 9357736SAndrew.W.Wilson@sun.com /* Remove existing */ 9367736SAndrew.W.Wilson@sun.com (void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path); 9377736SAndrew.W.Wilson@sun.com (void) system(cmd); 9387736SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, 9397736SAndrew.W.Wilson@sun.com "Removed any existing %s %s in %llu seconds", 9407736SAndrew.W.Wilson@sun.com fileset_entity_name(fileset), fileset_name, 9417736SAndrew.W.Wilson@sun.com (u_longlong_t)(((gethrtime() - start) / 9427736SAndrew.W.Wilson@sun.com 1000000000) + 1)); 9437736SAndrew.W.Wilson@sun.com } else { 9447736SAndrew.W.Wilson@sun.com /* we are re-using */ 9457736SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, "Re-using %s %s.", 9467736SAndrew.W.Wilson@sun.com fileset_entity_name(fileset), fileset_name); 9475184Sek110237 } 9487736SAndrew.W.Wilson@sun.com 9497736SAndrew.W.Wilson@sun.com /* make the filesets directory tree unless in reuse mode */ 9507736SAndrew.W.Wilson@sun.com if (!reusing && (avd_get_bool(fileset->fs_prealloc))) { 951*7946SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, 9527736SAndrew.W.Wilson@sun.com "making tree for filset %s", path); 9535184Sek110237 9547736SAndrew.W.Wilson@sun.com (void) mkdir(path, 0755); 9557736SAndrew.W.Wilson@sun.com 9567736SAndrew.W.Wilson@sun.com if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR) 9577736SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 9587736SAndrew.W.Wilson@sun.com } 9595673Saw148015 9605184Sek110237 start = gethrtime(); 9615184Sek110237 9625673Saw148015 filebench_log(LOG_VERBOSE, "Creating %s %s...", 9636212Saw148015 fileset_entity_name(fileset), fileset_name); 9645673Saw148015 9656212Saw148015 if (!avd_get_bool(fileset->fs_prealloc)) 9665673Saw148015 goto exit; 9675184Sek110237 9686212Saw148015 randno = ((RAND_MAX * (100 9696212Saw148015 - avd_get_int(fileset->fs_preallocpercent))) / 100); 9706212Saw148015 971*7946SAndrew.W.Wilson@sun.com /* alloc any files, as required */ 972*7946SAndrew.W.Wilson@sun.com pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET; 9735184Sek110237 while (entry = fileset_pick(fileset, pickflags, 0)) { 9745673Saw148015 pthread_t tid; 9757736SAndrew.W.Wilson@sun.com int newrand; 9765184Sek110237 9775184Sek110237 pickflags = FILESET_PICKUNIQUE; 9785184Sek110237 9795673Saw148015 /* entry doesn't need to be locked during initialization */ 9807556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 9815673Saw148015 9827736SAndrew.W.Wilson@sun.com newrand = rand(); 9837736SAndrew.W.Wilson@sun.com 9847736SAndrew.W.Wilson@sun.com if (newrand < randno) 9855184Sek110237 continue; 9865184Sek110237 9875184Sek110237 preallocated++; 9885184Sek110237 9895673Saw148015 if (reusing) 9905673Saw148015 entry->fse_flags |= FSE_REUSING; 9915673Saw148015 else 9925673Saw148015 entry->fse_flags &= (~FSE_REUSING); 9935673Saw148015 9947556SAndrew.W.Wilson@sun.com /* fire off allocation threads for each file if paralloc set */ 9956212Saw148015 if (avd_get_bool(fileset->fs_paralloc)) { 9965184Sek110237 9977556SAndrew.W.Wilson@sun.com /* limit total number of simultaneous allocations */ 9987556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock( 9997556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 10007556SAndrew.W.Wilson@sun.com while (filebench_shm->shm_fsparalloc_count 10017556SAndrew.W.Wilson@sun.com >= MAX_PARALLOC_THREADS) { 10025673Saw148015 (void) pthread_cond_wait( 10037556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv, 10047556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 10055673Saw148015 } 10065673Saw148015 10077556SAndrew.W.Wilson@sun.com /* quit if any allocation thread reports and error */ 10087556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_fsparalloc_count < 0) { 10097556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock( 10107556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 10117556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 10125184Sek110237 } 10135184Sek110237 10147556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count++; 10157556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock( 10167556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 10175184Sek110237 10187556SAndrew.W.Wilson@sun.com /* 10197556SAndrew.W.Wilson@sun.com * Fire off a detached allocation thread per file. 10207556SAndrew.W.Wilson@sun.com * The thread will self destruct when it finishes 10217556SAndrew.W.Wilson@sun.com * writing pre-allocation data to the file. 10227556SAndrew.W.Wilson@sun.com */ 10235673Saw148015 if (pthread_create(&tid, NULL, 10245673Saw148015 (void *(*)(void*))fileset_alloc_thread, 10257556SAndrew.W.Wilson@sun.com entry) == 0) { 10267556SAndrew.W.Wilson@sun.com /* 10277556SAndrew.W.Wilson@sun.com * A thread was created; detach it so it can 10287556SAndrew.W.Wilson@sun.com * fully quit when finished. 10297556SAndrew.W.Wilson@sun.com */ 10307556SAndrew.W.Wilson@sun.com (void) pthread_detach(tid); 10317556SAndrew.W.Wilson@sun.com } else { 10325184Sek110237 filebench_log(LOG_ERROR, 10335673Saw148015 "File prealloc thread create failed"); 10345673Saw148015 filebench_shutdown(1); 10355184Sek110237 } 10365184Sek110237 10375673Saw148015 } else { 10387556SAndrew.W.Wilson@sun.com if (fileset_alloc_file(entry) == FILEBENCH_ERROR) 10397556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 10405673Saw148015 } 10415673Saw148015 } 10425184Sek110237 1043*7946SAndrew.W.Wilson@sun.com /* alloc any leaf directories, as required */ 1044*7946SAndrew.W.Wilson@sun.com pickflags = 1045*7946SAndrew.W.Wilson@sun.com FILESET_PICKUNIQUE | FILESET_PICKRESET | FILESET_PICKLEAFDIR; 1046*7946SAndrew.W.Wilson@sun.com while (entry = fileset_pick(fileset, pickflags, 0)) { 1047*7946SAndrew.W.Wilson@sun.com 1048*7946SAndrew.W.Wilson@sun.com pickflags = FILESET_PICKUNIQUE | FILESET_PICKLEAFDIR; 1049*7946SAndrew.W.Wilson@sun.com 1050*7946SAndrew.W.Wilson@sun.com /* entry doesn't need to be locked during initialization */ 1051*7946SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 1052*7946SAndrew.W.Wilson@sun.com 1053*7946SAndrew.W.Wilson@sun.com if (rand() < randno) 1054*7946SAndrew.W.Wilson@sun.com continue; 1055*7946SAndrew.W.Wilson@sun.com 1056*7946SAndrew.W.Wilson@sun.com preallocated++; 1057*7946SAndrew.W.Wilson@sun.com 1058*7946SAndrew.W.Wilson@sun.com if (reusing) 1059*7946SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_REUSING; 1060*7946SAndrew.W.Wilson@sun.com else 1061*7946SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_REUSING); 1062*7946SAndrew.W.Wilson@sun.com 1063*7946SAndrew.W.Wilson@sun.com if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR) 1064*7946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 1065*7946SAndrew.W.Wilson@sun.com } 1066*7946SAndrew.W.Wilson@sun.com 10675673Saw148015 exit: 10685184Sek110237 filebench_log(LOG_VERBOSE, 10696286Saw148015 "Preallocated %d of %llu of %s %s in %llu seconds", 10705184Sek110237 preallocated, 10716286Saw148015 (u_longlong_t)fileset->fs_constentries, 10726212Saw148015 fileset_entity_name(fileset), fileset_name, 10736286Saw148015 (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1)); 10745184Sek110237 10757556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 10765184Sek110237 } 10775184Sek110237 10785184Sek110237 /* 10795184Sek110237 * Adds an entry to the fileset's file list. Single threaded so 10805184Sek110237 * no locking needed. 10815184Sek110237 */ 10825184Sek110237 static void 10835184Sek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry) 10845184Sek110237 { 10855184Sek110237 if (fileset->fs_filelist == NULL) { 10865184Sek110237 fileset->fs_filelist = entry; 10875184Sek110237 entry->fse_filenext = NULL; 10885184Sek110237 } else { 10895184Sek110237 entry->fse_filenext = fileset->fs_filelist; 10905184Sek110237 fileset->fs_filelist = entry; 10915184Sek110237 } 10925184Sek110237 } 10935184Sek110237 10945184Sek110237 /* 10955184Sek110237 * Adds an entry to the fileset's directory list. Single 10965184Sek110237 * threaded so no locking needed. 10975184Sek110237 */ 10985184Sek110237 static void 10995184Sek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) 11005184Sek110237 { 11015184Sek110237 if (fileset->fs_dirlist == NULL) { 11025184Sek110237 fileset->fs_dirlist = entry; 11035184Sek110237 entry->fse_dirnext = NULL; 11045184Sek110237 } else { 11055184Sek110237 entry->fse_dirnext = fileset->fs_dirlist; 11065184Sek110237 fileset->fs_dirlist = entry; 11075184Sek110237 } 11085184Sek110237 } 11095184Sek110237 11105184Sek110237 /* 1111*7946SAndrew.W.Wilson@sun.com * Adds an entry to the fileset's leaf directory list. Single 1112*7946SAndrew.W.Wilson@sun.com * threaded so no locking needed. 1113*7946SAndrew.W.Wilson@sun.com */ 1114*7946SAndrew.W.Wilson@sun.com static void 1115*7946SAndrew.W.Wilson@sun.com fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry) 1116*7946SAndrew.W.Wilson@sun.com { 1117*7946SAndrew.W.Wilson@sun.com if (fileset->fs_leafdirlist == NULL) { 1118*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirlist = entry; 1119*7946SAndrew.W.Wilson@sun.com entry->fse_leafdirnext = NULL; 1120*7946SAndrew.W.Wilson@sun.com } else { 1121*7946SAndrew.W.Wilson@sun.com entry->fse_leafdirnext = fileset->fs_leafdirlist; 1122*7946SAndrew.W.Wilson@sun.com fileset->fs_leafdirlist = entry; 1123*7946SAndrew.W.Wilson@sun.com } 1124*7946SAndrew.W.Wilson@sun.com } 1125*7946SAndrew.W.Wilson@sun.com 1126*7946SAndrew.W.Wilson@sun.com /* 1127*7946SAndrew.W.Wilson@sun.com * Obtains a filesetentry entity for a file to be placed in a 11285184Sek110237 * (sub)directory of a fileset. The size of the file may be 11296212Saw148015 * specified by fileset_meansize, or calculated from a gamma 11306212Saw148015 * distribution of parameter fileset_sizegamma and of mean size 11316212Saw148015 * fileset_meansize. The filesetentry entity is placed on the file 11325184Sek110237 * list in the specified parent filesetentry entity, which may 11335184Sek110237 * be a directory filesetentry, or the root filesetentry in the 11345184Sek110237 * fileset. It is also placed on the fileset's list of all 11357556SAndrew.W.Wilson@sun.com * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR 11367556SAndrew.W.Wilson@sun.com * if ipc memory for the path string cannot be allocated. 11375184Sek110237 */ 11385184Sek110237 static int 11395184Sek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) 11405184Sek110237 { 11415184Sek110237 char tmpname[16]; 11425184Sek110237 filesetentry_t *entry; 11435184Sek110237 double drand; 11445184Sek110237 11455184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 11465184Sek110237 == NULL) { 11475184Sek110237 filebench_log(LOG_ERROR, 11485184Sek110237 "fileset_populate_file: Can't malloc filesetentry"); 11497556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 11505184Sek110237 } 11515184Sek110237 11527556SAndrew.W.Wilson@sun.com /* Another currently idle file */ 11537556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 11547556SAndrew.W.Wilson@sun.com fileset->fs_idle_files++; 11557556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 11567556SAndrew.W.Wilson@sun.com 11575184Sek110237 entry->fse_parent = parent; 11585184Sek110237 entry->fse_fileset = fileset; 1159*7946SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_TYPE_FILE | FSE_FREE; 11605184Sek110237 fileset_insfilelist(fileset, entry); 11615184Sek110237 11625184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 11635184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 11645184Sek110237 filebench_log(LOG_ERROR, 11655184Sek110237 "fileset_populate_file: Can't alloc path string"); 11667556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 11675184Sek110237 } 11685184Sek110237 11696212Saw148015 /* see if random variable was supplied for file size */ 11706212Saw148015 if (fileset->fs_meansize == -1) { 11716212Saw148015 entry->fse_size = (off64_t)avd_get_int(fileset->fs_size); 11726212Saw148015 } else { 11736212Saw148015 double gamma; 11745184Sek110237 11756212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 11766212Saw148015 if (gamma > 0) { 11776212Saw148015 drand = gamma_dist_knuth(gamma, 11786212Saw148015 fileset->fs_meansize / gamma); 11796212Saw148015 entry->fse_size = (off64_t)drand; 11806212Saw148015 } else { 11816212Saw148015 entry->fse_size = (off64_t)fileset->fs_meansize; 11826212Saw148015 } 11835184Sek110237 } 11845184Sek110237 11855184Sek110237 fileset->fs_bytes += entry->fse_size; 11865184Sek110237 11875184Sek110237 fileset->fs_realfiles++; 11887556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 11895184Sek110237 } 11905184Sek110237 11915184Sek110237 /* 1192*7946SAndrew.W.Wilson@sun.com * Obtaines a filesetentry entity for a leaf directory to be placed in a 1193*7946SAndrew.W.Wilson@sun.com * (sub)directory of a fileset. The leaf directory will always be empty so 1194*7946SAndrew.W.Wilson@sun.com * it can be created and deleted (mkdir, rmdir) at will. The filesetentry 1195*7946SAndrew.W.Wilson@sun.com * entity is placed on the leaf directory list in the specified parent 1196*7946SAndrew.W.Wilson@sun.com * filesetentry entity, which may be a (sub) directory filesetentry, or 1197*7946SAndrew.W.Wilson@sun.com * the root filesetentry in the fileset. It is also placed on the fileset's 1198*7946SAndrew.W.Wilson@sun.com * list of all contained leaf directories. Returns FILEBENCH_OK if successful 1199*7946SAndrew.W.Wilson@sun.com * or FILEBENCH_ERROR if ipc memory cannot be allocated. 1200*7946SAndrew.W.Wilson@sun.com */ 1201*7946SAndrew.W.Wilson@sun.com static int 1202*7946SAndrew.W.Wilson@sun.com fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial) 1203*7946SAndrew.W.Wilson@sun.com { 1204*7946SAndrew.W.Wilson@sun.com char tmpname[16]; 1205*7946SAndrew.W.Wilson@sun.com filesetentry_t *entry; 1206*7946SAndrew.W.Wilson@sun.com 1207*7946SAndrew.W.Wilson@sun.com if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 1208*7946SAndrew.W.Wilson@sun.com == NULL) { 1209*7946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 1210*7946SAndrew.W.Wilson@sun.com "fileset_populate_file: Can't malloc filesetentry"); 1211*7946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 1212*7946SAndrew.W.Wilson@sun.com } 1213*7946SAndrew.W.Wilson@sun.com 1214*7946SAndrew.W.Wilson@sun.com /* Another currently idle leaf directory */ 1215*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 1216*7946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs++; 1217*7946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 1218*7946SAndrew.W.Wilson@sun.com 1219*7946SAndrew.W.Wilson@sun.com entry->fse_parent = parent; 1220*7946SAndrew.W.Wilson@sun.com entry->fse_fileset = fileset; 1221*7946SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE; 1222*7946SAndrew.W.Wilson@sun.com fileset_insleafdirlist(fileset, entry); 1223*7946SAndrew.W.Wilson@sun.com 1224*7946SAndrew.W.Wilson@sun.com (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 1225*7946SAndrew.W.Wilson@sun.com if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 1226*7946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, 1227*7946SAndrew.W.Wilson@sun.com "fileset_populate_file: Can't alloc path string"); 1228*7946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 1229*7946SAndrew.W.Wilson@sun.com } 1230*7946SAndrew.W.Wilson@sun.com 1231*7946SAndrew.W.Wilson@sun.com fileset->fs_realleafdirs++; 1232*7946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 1233*7946SAndrew.W.Wilson@sun.com } 1234*7946SAndrew.W.Wilson@sun.com 1235*7946SAndrew.W.Wilson@sun.com /* 12365184Sek110237 * Creates a directory node in a fileset, by obtaining a 12375184Sek110237 * filesetentry entity for the node and initializing it 12385184Sek110237 * according to parameters of the fileset. It determines a 12395184Sek110237 * directory tree depth and directory width, optionally using 12405184Sek110237 * a gamma distribution. If its calculated depth is less then 12415184Sek110237 * its actual depth in the directory tree, it becomes a leaf 12425184Sek110237 * node and files itself with "width" number of file type 12435184Sek110237 * filesetentries, otherwise it files itself with "width" 12445184Sek110237 * number of directory type filesetentries, using recursive 12455184Sek110237 * calls to fileset_populate_subdir. The end result of the 12465184Sek110237 * initial call to this routine is a tree of directories of 12475184Sek110237 * random width and varying depth with sufficient leaf 12485184Sek110237 * directories to contain all required files. 12497556SAndrew.W.Wilson@sun.com * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path 12507556SAndrew.W.Wilson@sun.com * string memory cannot be allocated and returns the error code (currently 12517556SAndrew.W.Wilson@sun.com * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive 12525184Sek110237 * calls to fileset_populate_subdir. 12535184Sek110237 */ 12545184Sek110237 static int 12555184Sek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, 12565184Sek110237 int serial, double depth) 12575184Sek110237 { 12586212Saw148015 double randepth, drand, ranwidth; 12595184Sek110237 int isleaf = 0; 12605184Sek110237 char tmpname[16]; 12615184Sek110237 filesetentry_t *entry; 12625184Sek110237 int i; 12635184Sek110237 12645184Sek110237 depth += 1; 12655184Sek110237 12665184Sek110237 /* Create dir node */ 12675184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 12685184Sek110237 == NULL) { 12695184Sek110237 filebench_log(LOG_ERROR, 12705184Sek110237 "fileset_populate_subdir: Can't malloc filesetentry"); 12717556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 12725184Sek110237 } 12735184Sek110237 12747556SAndrew.W.Wilson@sun.com /* another idle directory */ 12757556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 12767556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs++; 12777556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 12785184Sek110237 12795184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 12805184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 12815184Sek110237 filebench_log(LOG_ERROR, 12825184Sek110237 "fileset_populate_subdir: Can't alloc path string"); 12837556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 12845184Sek110237 } 12855184Sek110237 12865184Sek110237 entry->fse_parent = parent; 1287*7946SAndrew.W.Wilson@sun.com entry->fse_fileset = fileset; 1288*7946SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_TYPE_DIR | FSE_FREE; 12895184Sek110237 fileset_insdirlist(fileset, entry); 12905184Sek110237 12916212Saw148015 if (fileset->fs_dirdepthrv) { 12926212Saw148015 randepth = (int)avd_get_int(fileset->fs_dirdepthrv); 12935184Sek110237 } else { 12946212Saw148015 double gamma; 12956212Saw148015 12966212Saw148015 gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0; 12976212Saw148015 if (gamma > 0) { 12986212Saw148015 drand = gamma_dist_knuth(gamma, 12996212Saw148015 fileset->fs_meandepth / gamma); 13006212Saw148015 randepth = (int)drand; 13016212Saw148015 } else { 13026212Saw148015 randepth = (int)fileset->fs_meandepth; 13036212Saw148015 } 13045184Sek110237 } 13055184Sek110237 13066212Saw148015 if (fileset->fs_meanwidth == -1) { 13076212Saw148015 ranwidth = avd_get_dbl(fileset->fs_dirwidth); 13086212Saw148015 } else { 13096212Saw148015 double gamma; 13105184Sek110237 13116212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 13126212Saw148015 if (gamma > 0) { 13136212Saw148015 drand = gamma_dist_knuth(gamma, 13146212Saw148015 fileset->fs_meanwidth / gamma); 13156212Saw148015 ranwidth = drand; 13166212Saw148015 } else { 13176212Saw148015 ranwidth = fileset->fs_meanwidth; 13186212Saw148015 } 13195184Sek110237 } 13205184Sek110237 13215184Sek110237 if (randepth == 0) 13225184Sek110237 randepth = 1; 13235184Sek110237 if (ranwidth == 0) 13245184Sek110237 ranwidth = 1; 13255184Sek110237 if (depth >= randepth) 13265184Sek110237 isleaf = 1; 13275184Sek110237 13285184Sek110237 /* 1329*7946SAndrew.W.Wilson@sun.com * Create directory of random width filled with files according 1330*7946SAndrew.W.Wilson@sun.com * to distribution, or if root directory, continue until #files required 13315184Sek110237 */ 13326212Saw148015 for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && 13336212Saw148015 (fileset->fs_realfiles < fileset->fs_constentries); 13346212Saw148015 i++) { 13355184Sek110237 int ret = 0; 13365184Sek110237 13375184Sek110237 if (parent && isleaf) 13385184Sek110237 ret = fileset_populate_file(fileset, entry, i); 13395184Sek110237 else 13405184Sek110237 ret = fileset_populate_subdir(fileset, entry, i, depth); 13415184Sek110237 13425184Sek110237 if (ret != 0) 13435184Sek110237 return (ret); 13445184Sek110237 } 1345*7946SAndrew.W.Wilson@sun.com 1346*7946SAndrew.W.Wilson@sun.com /* 1347*7946SAndrew.W.Wilson@sun.com * Create directory of random width filled with leaf directories 1348*7946SAndrew.W.Wilson@sun.com * according to distribution, or if root directory, continue until 1349*7946SAndrew.W.Wilson@sun.com * the number of leaf directories required has been generated. 1350*7946SAndrew.W.Wilson@sun.com */ 1351*7946SAndrew.W.Wilson@sun.com for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && 1352*7946SAndrew.W.Wilson@sun.com (fileset->fs_realleafdirs < fileset->fs_constleafdirs); 1353*7946SAndrew.W.Wilson@sun.com i++) { 1354*7946SAndrew.W.Wilson@sun.com int ret = 0; 1355*7946SAndrew.W.Wilson@sun.com 1356*7946SAndrew.W.Wilson@sun.com if (parent && isleaf) 1357*7946SAndrew.W.Wilson@sun.com ret = fileset_populate_leafdir(fileset, entry, i); 1358*7946SAndrew.W.Wilson@sun.com else 1359*7946SAndrew.W.Wilson@sun.com ret = fileset_populate_subdir(fileset, entry, i, depth); 1360*7946SAndrew.W.Wilson@sun.com 1361*7946SAndrew.W.Wilson@sun.com if (ret != 0) 1362*7946SAndrew.W.Wilson@sun.com return (ret); 1363*7946SAndrew.W.Wilson@sun.com } 1364*7946SAndrew.W.Wilson@sun.com 13657556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 13665184Sek110237 } 13675184Sek110237 13685184Sek110237 /* 13695184Sek110237 * Populates a fileset with files and subdirectory entries. Uses 13706212Saw148015 * the supplied fileset_dirwidth and fileset_entries (number of files) to 13716212Saw148015 * calculate the required fileset_meandepth (of subdirectories) and 13726212Saw148015 * initialize the fileset_meanwidth and fileset_meansize variables. Then 13735184Sek110237 * calls fileset_populate_subdir() to do the recursive 13745184Sek110237 * subdirectory entry creation and leaf file entry creation. All 13755184Sek110237 * of the above is skipped if the fileset has already been 13765184Sek110237 * populated. Returns 0 on success, or an error code from the 13775184Sek110237 * call to fileset_populate_subdir if that call fails. 13785184Sek110237 */ 13795184Sek110237 static int 13805184Sek110237 fileset_populate(fileset_t *fileset) 13815184Sek110237 { 13826212Saw148015 int entries = (int)avd_get_int(fileset->fs_entries); 1383*7946SAndrew.W.Wilson@sun.com int leafdirs = (int)avd_get_int(fileset->fs_leafdirs); 13846212Saw148015 int meandirwidth; 13855184Sek110237 int ret; 13865184Sek110237 13875184Sek110237 /* Skip if already populated */ 13885184Sek110237 if (fileset->fs_bytes > 0) 13895184Sek110237 goto exists; 13905184Sek110237 13915673Saw148015 #ifdef HAVE_RAW_SUPPORT 13925673Saw148015 /* check for raw device */ 13935673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 13947556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 13955673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 13965673Saw148015 1397*7946SAndrew.W.Wilson@sun.com /* 1398*7946SAndrew.W.Wilson@sun.com * save value of entries and leaf dirs obtained for later 1399*7946SAndrew.W.Wilson@sun.com * in case it was random 1400*7946SAndrew.W.Wilson@sun.com */ 14016212Saw148015 fileset->fs_constentries = entries; 1402*7946SAndrew.W.Wilson@sun.com fileset->fs_constleafdirs = leafdirs; 14036212Saw148015 1404*7946SAndrew.W.Wilson@sun.com /* declare all files and leafdirs currently non existant */ 14057556SAndrew.W.Wilson@sun.com fileset->fs_num_act_files = 0; 1406*7946SAndrew.W.Wilson@sun.com fileset->fs_num_act_leafdirs = 0; 14077556SAndrew.W.Wilson@sun.com 14087556SAndrew.W.Wilson@sun.com /* initialize idle files and directories condition variables */ 1409*7946SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr()); 14107556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr()); 1411*7946SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr()); 14127556SAndrew.W.Wilson@sun.com 14137556SAndrew.W.Wilson@sun.com /* no files or dirs idle (or busy) yet */ 14147556SAndrew.W.Wilson@sun.com fileset->fs_idle_files = 0; 14157556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs = 0; 1416*7946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs = 0; 14177556SAndrew.W.Wilson@sun.com 14187556SAndrew.W.Wilson@sun.com /* initialize locks and other condition variables */ 14197556SAndrew.W.Wilson@sun.com (void) pthread_mutex_init(&fileset->fs_pick_lock, 14207556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL)); 14217556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr()); 14227556SAndrew.W.Wilson@sun.com 14236212Saw148015 /* is dirwidth a random variable? */ 14246212Saw148015 if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { 14256212Saw148015 meandirwidth = 14266212Saw148015 (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean; 14276212Saw148015 fileset->fs_meanwidth = -1; 14286212Saw148015 } else { 14296212Saw148015 meandirwidth = (int)avd_get_int(fileset->fs_dirwidth); 14306212Saw148015 fileset->fs_meanwidth = (double)meandirwidth; 14316212Saw148015 } 14326212Saw148015 14335184Sek110237 /* 14345184Sek110237 * Input params are: 14355184Sek110237 * # of files 14365184Sek110237 * ave # of files per dir 14375184Sek110237 * max size of dir 14385184Sek110237 * # ave size of file 14395184Sek110237 * max size of file 14405184Sek110237 */ 1441*7946SAndrew.W.Wilson@sun.com fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth); 14426212Saw148015 14436212Saw148015 /* Has a random variable been supplied for dirdepth? */ 14446212Saw148015 if (fileset->fs_dirdepthrv) { 14456212Saw148015 /* yes, so set the random variable's mean value to meandepth */ 14466212Saw148015 fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean = 14476212Saw148015 fileset->fs_meandepth; 14486212Saw148015 } 14496212Saw148015 14506212Saw148015 /* test for random size variable */ 14516212Saw148015 if (AVD_IS_RANDOM(fileset->fs_size)) 14526212Saw148015 fileset->fs_meansize = -1; 14536212Saw148015 else 14546212Saw148015 fileset->fs_meansize = avd_get_int(fileset->fs_size); 14555184Sek110237 14565184Sek110237 if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0) 14575184Sek110237 return (ret); 14585184Sek110237 14595184Sek110237 14605184Sek110237 exists: 14615673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 14626286Saw148015 filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu", 14636212Saw148015 avd_get_str(fileset->fs_name), 14646286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 14655673Saw148015 } else { 1466*7946SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs " 14676286Saw148015 "avg dir = %d, avg depth = %.1lf, mbytes=%llu", 1468*7946SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name), entries, leafdirs, 14696212Saw148015 meandirwidth, 14705673Saw148015 fileset->fs_meandepth, 14716286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 14725673Saw148015 } 14736701Saw148015 14747556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 14755184Sek110237 } 14765184Sek110237 14775184Sek110237 /* 14786212Saw148015 * Allocates a fileset instance, initializes fileset_dirgamma and 14796212Saw148015 * fileset_sizegamma default values, and sets the fileset name to the 14805184Sek110237 * supplied name string. Puts the allocated fileset on the 14815184Sek110237 * master fileset list and returns a pointer to it. 14826701Saw148015 * 14836701Saw148015 * This routine implements the 'define fileset' calls found in a .f 14846701Saw148015 * workload, such as in the following example: 14856701Saw148015 * define fileset name=drew4ever, entries=$nfiles 14865184Sek110237 */ 14875184Sek110237 fileset_t * 14886212Saw148015 fileset_define(avd_t name) 14895184Sek110237 { 14905184Sek110237 fileset_t *fileset; 14915184Sek110237 14925184Sek110237 if (name == NULL) 14935184Sek110237 return (NULL); 14945184Sek110237 14955184Sek110237 if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) { 14965184Sek110237 filebench_log(LOG_ERROR, 14975184Sek110237 "fileset_define: Can't malloc fileset"); 14985184Sek110237 return (NULL); 14995184Sek110237 } 15005184Sek110237 15016212Saw148015 filebench_log(LOG_DEBUG_IMPL, 15026212Saw148015 "Defining file %s", avd_get_str(name)); 15035184Sek110237 15046391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 15055184Sek110237 15066212Saw148015 fileset->fs_dirgamma = avd_int_alloc(1500); 15076212Saw148015 fileset->fs_sizegamma = avd_int_alloc(1500); 15085184Sek110237 15095184Sek110237 /* Add fileset to global list */ 15106391Saw148015 if (filebench_shm->shm_filesetlist == NULL) { 15116391Saw148015 filebench_shm->shm_filesetlist = fileset; 15125184Sek110237 fileset->fs_next = NULL; 15135184Sek110237 } else { 15146391Saw148015 fileset->fs_next = filebench_shm->shm_filesetlist; 15156391Saw148015 filebench_shm->shm_filesetlist = fileset; 15165184Sek110237 } 15175184Sek110237 15186391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 15195184Sek110237 15206212Saw148015 fileset->fs_name = name; 15215184Sek110237 15225184Sek110237 return (fileset); 15235184Sek110237 } 15245184Sek110237 15255184Sek110237 /* 15265184Sek110237 * If supplied with a pointer to a fileset and the fileset's 15276212Saw148015 * fileset_prealloc flag is set, calls fileset_populate() to populate 15285184Sek110237 * the fileset with filesetentries, then calls fileset_create() 15295184Sek110237 * to make actual directories and files for the filesetentries. 15305184Sek110237 * Otherwise, it applies fileset_populate() and fileset_create() 15315184Sek110237 * to all the filesets on the master fileset list. It always 15325184Sek110237 * returns zero (0) if one fileset is populated / created, 15335184Sek110237 * otherwise it returns the sum of returned values from 15345184Sek110237 * fileset_create() and fileset_populate(), which 15355184Sek110237 * will be a negative one (-1) times the number of 15365184Sek110237 * fileset_create() calls which failed. 15375184Sek110237 */ 15385184Sek110237 int 15395184Sek110237 fileset_createset(fileset_t *fileset) 15405184Sek110237 { 15415184Sek110237 fileset_t *list; 15425184Sek110237 int ret = 0; 15435184Sek110237 15445673Saw148015 /* set up for possible parallel allocate */ 15457556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count = 0; 15467556SAndrew.W.Wilson@sun.com (void) pthread_cond_init( 15477556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv, 15487556SAndrew.W.Wilson@sun.com ipc_condattr()); 15495673Saw148015 15506212Saw148015 if (fileset && avd_get_bool(fileset->fs_prealloc)) { 15515673Saw148015 15526305Saw148015 /* check for raw files */ 15536305Saw148015 if (fileset_checkraw(fileset)) { 15546305Saw148015 filebench_log(LOG_INFO, 15556305Saw148015 "file %s/%s is a RAW device", 15566305Saw148015 avd_get_str(fileset->fs_path), 15576305Saw148015 avd_get_str(fileset->fs_name)); 15587556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 15596305Saw148015 } 15606305Saw148015 15615673Saw148015 filebench_log(LOG_INFO, 15625673Saw148015 "creating/pre-allocating %s %s", 15636212Saw148015 fileset_entity_name(fileset), 15646212Saw148015 avd_get_str(fileset->fs_name)); 15655673Saw148015 15667556SAndrew.W.Wilson@sun.com if ((ret = fileset_populate(fileset)) != FILEBENCH_OK) 15675184Sek110237 return (ret); 15685673Saw148015 15697556SAndrew.W.Wilson@sun.com if ((ret = fileset_create(fileset)) != FILEBENCH_OK) 15705673Saw148015 return (ret); 15715673Saw148015 } else { 15725673Saw148015 15735673Saw148015 filebench_log(LOG_INFO, 15745673Saw148015 "Creating/pre-allocating files and filesets"); 15755673Saw148015 15766391Saw148015 list = filebench_shm->shm_filesetlist; 15775673Saw148015 while (list) { 15786305Saw148015 /* check for raw files */ 15796305Saw148015 if (fileset_checkraw(list)) { 15806305Saw148015 filebench_log(LOG_INFO, 15816305Saw148015 "file %s/%s is a RAW device", 15826305Saw148015 avd_get_str(list->fs_path), 15836305Saw148015 avd_get_str(list->fs_name)); 15846305Saw148015 list = list->fs_next; 15856305Saw148015 continue; 15866305Saw148015 } 15876305Saw148015 15887556SAndrew.W.Wilson@sun.com if ((ret = fileset_populate(list)) != FILEBENCH_OK) 15895673Saw148015 return (ret); 15907556SAndrew.W.Wilson@sun.com 15917556SAndrew.W.Wilson@sun.com if ((ret = fileset_create(list)) != FILEBENCH_OK) 15925673Saw148015 return (ret); 15937556SAndrew.W.Wilson@sun.com 15945673Saw148015 list = list->fs_next; 15955673Saw148015 } 15965184Sek110237 } 15975184Sek110237 15985673Saw148015 /* wait for allocation threads to finish */ 15995673Saw148015 filebench_log(LOG_INFO, 16005673Saw148015 "waiting for fileset pre-allocation to finish"); 16015184Sek110237 16027556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 16037556SAndrew.W.Wilson@sun.com while (filebench_shm->shm_fsparalloc_count > 0) 16047556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait( 16057556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv, 16067556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 16077556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); 16085673Saw148015 16097556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_fsparalloc_count < 0) 16107556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 16115673Saw148015 16127556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 16135184Sek110237 } 16145184Sek110237 16155184Sek110237 /* 16165184Sek110237 * Searches through the master fileset list for the named fileset. 16175184Sek110237 * If found, returns pointer to same, otherwise returns NULL. 16185184Sek110237 */ 16195184Sek110237 fileset_t * 16205184Sek110237 fileset_find(char *name) 16215184Sek110237 { 16226391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 16235184Sek110237 16246391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 16255184Sek110237 16265184Sek110237 while (fileset) { 16276212Saw148015 if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) { 16286391Saw148015 (void) ipc_mutex_unlock( 16296391Saw148015 &filebench_shm->shm_fileset_lock); 16305184Sek110237 return (fileset); 16315184Sek110237 } 16325184Sek110237 fileset = fileset->fs_next; 16335184Sek110237 } 16346391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 16355184Sek110237 16365184Sek110237 return (NULL); 16375184Sek110237 } 16385673Saw148015 16395673Saw148015 /* 16405673Saw148015 * Iterates over all the file sets in the filesetlist, 16415673Saw148015 * executing the supplied command "*cmd()" on them. Also 16425673Saw148015 * indicates to the executed command if it is the first 16435673Saw148015 * time the command has been executed since the current 16445673Saw148015 * call to fileset_iter. 16455673Saw148015 */ 16465673Saw148015 void 16475673Saw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first)) 16485673Saw148015 { 16496391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 16505673Saw148015 int count = 0; 16515673Saw148015 16526391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 16535673Saw148015 16545673Saw148015 while (fileset) { 16555673Saw148015 cmd(fileset, count == 0); 16565673Saw148015 fileset = fileset->fs_next; 16575673Saw148015 count++; 16585673Saw148015 } 16595673Saw148015 16606391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 16615673Saw148015 } 16625673Saw148015 16635673Saw148015 /* 16645673Saw148015 * Prints information to the filebench log about the file 16655673Saw148015 * object. Also prints a header on the first call. 16665673Saw148015 */ 16675673Saw148015 int 16685673Saw148015 fileset_print(fileset_t *fileset, int first) 16695673Saw148015 { 16706212Saw148015 int pathlength; 16716212Saw148015 char *fileset_path; 16726212Saw148015 char *fileset_name; 16736212Saw148015 static char pad[] = " "; /* 30 spaces */ 16746212Saw148015 16756212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 16766212Saw148015 filebench_log(LOG_ERROR, "%s path not set", 16776212Saw148015 fileset_entity_name(fileset)); 16787556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 16796212Saw148015 } 16806212Saw148015 16816212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 16826212Saw148015 filebench_log(LOG_ERROR, "%s name not set", 16836212Saw148015 fileset_entity_name(fileset)); 16847556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 16856212Saw148015 } 16866212Saw148015 16876212Saw148015 pathlength = strlen(fileset_path) + strlen(fileset_name); 16885673Saw148015 16895673Saw148015 if (pathlength > 29) 16905673Saw148015 pathlength = 29; 16915673Saw148015 16925673Saw148015 if (first) { 16935673Saw148015 filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s", 16945673Saw148015 "file size", 16955673Saw148015 "dir width", 16965673Saw148015 "entries"); 16975673Saw148015 } 16985673Saw148015 16995673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 17005673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { 17015673Saw148015 filebench_log(LOG_INFO, 17025673Saw148015 "%s/%s%s (Raw Device)", 17036212Saw148015 fileset_path, fileset_name, &pad[pathlength]); 17045673Saw148015 } else { 17055673Saw148015 filebench_log(LOG_INFO, 17066286Saw148015 "%s/%s%s%9llu (Single File)", 17076212Saw148015 fileset_path, fileset_name, &pad[pathlength], 17086286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size)); 17095673Saw148015 } 17105673Saw148015 } else { 17116286Saw148015 filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu", 17126212Saw148015 fileset_path, fileset_name, 17135673Saw148015 &pad[pathlength], 17146286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size), 17156286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_dirwidth), 17166286Saw148015 (u_longlong_t)fileset->fs_constentries); 17175673Saw148015 } 17187556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 17195673Saw148015 } 1720*7946SAndrew.W.Wilson@sun.com 17215673Saw148015 /* 17225673Saw148015 * checks to see if the path/name pair points to a raw device. If 17235673Saw148015 * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1. 17245673Saw148015 * If RAW is not defined, or it is not a raw device, it clears the 17255673Saw148015 * raw device flag and returns 0. 17265673Saw148015 */ 17275673Saw148015 int 17285673Saw148015 fileset_checkraw(fileset_t *fileset) 17295673Saw148015 { 17305673Saw148015 char path[MAXPATHLEN]; 17315673Saw148015 struct stat64 sb; 17326305Saw148015 char *pathname; 17336305Saw148015 char *setname; 17345673Saw148015 17355673Saw148015 fileset->fs_attrs &= (~FILESET_IS_RAW_DEV); 17365673Saw148015 17375673Saw148015 #ifdef HAVE_RAW_SUPPORT 17385673Saw148015 /* check for raw device */ 17396305Saw148015 if ((pathname = avd_get_str(fileset->fs_path)) == NULL) 17407556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 17416305Saw148015 17426305Saw148015 if ((setname = avd_get_str(fileset->fs_name)) == NULL) 17437556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 17446305Saw148015 1745*7946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, pathname, MAXPATHLEN); 1746*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN); 1747*7946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, setname, MAXPATHLEN); 17485673Saw148015 if ((stat64(path, &sb) == 0) && 17495673Saw148015 ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { 17505673Saw148015 fileset->fs_attrs |= FILESET_IS_RAW_DEV; 17516305Saw148015 if (!(fileset->fs_attrs & FILESET_IS_FILE)) { 17526305Saw148015 filebench_log(LOG_ERROR, 17536305Saw148015 "WARNING Fileset %s/%s Cannot be RAW device", 17546305Saw148015 avd_get_str(fileset->fs_path), 17556305Saw148015 avd_get_str(fileset->fs_name)); 17566305Saw148015 filebench_shutdown(1); 17576305Saw148015 } 17586305Saw148015 17595673Saw148015 return (1); 17605673Saw148015 } 17615673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 17625673Saw148015 17637556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 17645673Saw148015 } 1765