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" 385184Sek110237 395184Sek110237 /* 405184Sek110237 * File sets, of type fileset_t, are entities which contain 415184Sek110237 * information about collections of files and subdirectories in Filebench. 425184Sek110237 * The fileset, once populated, consists of a tree of fileset entries of 435184Sek110237 * type filesetentry_t which specify files and directories. The fileset 446212Saw148015 * is rooted in a directory specified by fileset_path, and once the populated 455184Sek110237 * fileset has been created, has a tree of directories and files 465184Sek110237 * corresponding to the fileset's filesetentry tree. 476701Saw148015 * 487556SAndrew.W.Wilson@sun.com * Fileset entities are allocated by fileset_define() which is called from 497556SAndrew.W.Wilson@sun.com * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding 507556SAndrew.W.Wilson@sun.com * to the eventual directory and file tree to be instantiated on the storage 517556SAndrew.W.Wilson@sun.com * medium is built by fileset_populate(), which is called from 527556SAndrew.W.Wilson@sun.com * fileset_createset(). After calling fileset_populate(), fileset_createset() 537556SAndrew.W.Wilson@sun.com * will call fileset_create() to pre-allocate designated files and directories. 547556SAndrew.W.Wilson@sun.com * 557556SAndrew.W.Wilson@sun.com * Fileset_createset() is called from parser_gram.y: parser_create_fileset() 567556SAndrew.W.Wilson@sun.com * when a "create fileset" or "run" command is encountered. When the 577556SAndrew.W.Wilson@sun.com * "create fileset" command is used, it is generally paired with 586701Saw148015 * a "create processes" command, and must appear first, in order to 596701Saw148015 * instantiate all the files in the fileset before trying to use them. 605184Sek110237 */ 615184Sek110237 626305Saw148015 static int fileset_checkraw(fileset_t *fileset); 636305Saw148015 647556SAndrew.W.Wilson@sun.com /* maximum parallel allocation control */ 655673Saw148015 #define MAX_PARALLOC_THREADS 32 665673Saw148015 675673Saw148015 /* 685673Saw148015 * returns pointer to file or fileset 695673Saw148015 * string, as appropriate 705673Saw148015 */ 715673Saw148015 static char * 725673Saw148015 fileset_entity_name(fileset_t *fileset) 735673Saw148015 { 745673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) 755673Saw148015 return ("file"); 765673Saw148015 else 775673Saw148015 return ("fileset"); 785673Saw148015 } 795673Saw148015 805184Sek110237 /* 815184Sek110237 * Removes the last file or directory name from a pathname. 825184Sek110237 * Basically removes characters from the end of the path by 835184Sek110237 * setting them to \0 until a forward slash '/' is 845184Sek110237 * encountered. It also removes the forward slash. 855184Sek110237 */ 865184Sek110237 static char * 875184Sek110237 trunc_dirname(char *dir) 885184Sek110237 { 895184Sek110237 char *s = dir + strlen(dir); 905184Sek110237 915184Sek110237 while (s != dir) { 925184Sek110237 int c = *s; 935184Sek110237 945184Sek110237 *s = 0; 955184Sek110237 if (c == '/') 965184Sek110237 break; 975184Sek110237 s--; 985184Sek110237 } 995184Sek110237 return (dir); 1005184Sek110237 } 1015184Sek110237 1025184Sek110237 /* 1035184Sek110237 * Prints a list of allowed options and how to specify them. 1045184Sek110237 */ 1055184Sek110237 void 1065184Sek110237 fileset_usage(void) 1075184Sek110237 { 1085673Saw148015 (void) fprintf(stderr, 1095673Saw148015 "define [file name=<name> | fileset name=<name>],path=<pathname>," 1105673Saw148015 ",entries=<number>\n"); 1115673Saw148015 (void) fprintf(stderr, 1126212Saw148015 " [,filesize=[size]]\n"); 1136212Saw148015 (void) fprintf(stderr, 1145673Saw148015 " [,dirwidth=[width]]\n"); 1155673Saw148015 (void) fprintf(stderr, 1166212Saw148015 " [,dirdepthrv=$random_variable_name]\n"); 1176212Saw148015 (void) fprintf(stderr, 1185673Saw148015 " [,dirgamma=[100-10000]] " 1195184Sek110237 "(Gamma * 1000)\n"); 1205184Sek110237 (void) fprintf(stderr, 1215673Saw148015 " [,sizegamma=[100-10000]] (Gamma * 1000)\n"); 1225184Sek110237 (void) fprintf(stderr, 1235184Sek110237 " [,prealloc=[percent]]\n"); 1245673Saw148015 (void) fprintf(stderr, " [,paralloc]\n"); 1255184Sek110237 (void) fprintf(stderr, " [,reuse]\n"); 1265184Sek110237 (void) fprintf(stderr, "\n"); 1275184Sek110237 } 1285184Sek110237 1295184Sek110237 /* 1305184Sek110237 * Frees up memory mapped file region of supplied size. The 1315184Sek110237 * file descriptor "fd" indicates which memory mapped file. 1327556SAndrew.W.Wilson@sun.com * If successful, returns 0. Otherwise returns -1 times the number of 1337556SAndrew.W.Wilson@sun.com * times msync() failed. 1345184Sek110237 */ 1355184Sek110237 static int 1365184Sek110237 fileset_freemem(int fd, off64_t size) 1375184Sek110237 { 1385184Sek110237 off64_t left; 1395184Sek110237 int ret = 0; 1405184Sek110237 1415184Sek110237 for (left = size; left > 0; left -= MMAP_SIZE) { 1425184Sek110237 off64_t thismapsize; 1435184Sek110237 caddr_t addr; 1445184Sek110237 1455184Sek110237 thismapsize = MIN(MMAP_SIZE, left); 1465184Sek110237 addr = mmap64(0, thismapsize, PROT_READ|PROT_WRITE, 1475184Sek110237 MAP_SHARED, fd, size - left); 1485184Sek110237 ret += msync(addr, thismapsize, MS_INVALIDATE); 1495184Sek110237 (void) munmap(addr, thismapsize); 1505184Sek110237 } 1515184Sek110237 return (ret); 1525184Sek110237 } 1535184Sek110237 1545184Sek110237 /* 1555184Sek110237 * Creates a path string from the filesetentry_t "*entry" 1565184Sek110237 * and all of its parent's path names. The resulting path 1575184Sek110237 * is a concatination of all the individual parent paths. 1585184Sek110237 * Allocates memory for the path string and returns a 1595184Sek110237 * pointer to it. 1605184Sek110237 */ 1615184Sek110237 char * 1625184Sek110237 fileset_resolvepath(filesetentry_t *entry) 1635184Sek110237 { 1645184Sek110237 filesetentry_t *fsep = entry; 1655184Sek110237 char path[MAXPATHLEN]; 1665184Sek110237 char pathtmp[MAXPATHLEN]; 1675184Sek110237 char *s; 1685184Sek110237 1695184Sek110237 *path = 0; 1705184Sek110237 while (fsep->fse_parent) { 1715184Sek110237 (void) strcpy(pathtmp, "/"); 1725184Sek110237 (void) strcat(pathtmp, fsep->fse_path); 1735184Sek110237 (void) strcat(pathtmp, path); 1745184Sek110237 (void) strcpy(path, pathtmp); 1755184Sek110237 fsep = fsep->fse_parent; 1765184Sek110237 } 1775184Sek110237 1785184Sek110237 s = malloc(strlen(path) + 1); 1795184Sek110237 (void) strcpy(s, path); 1805184Sek110237 return (s); 1815184Sek110237 } 1825184Sek110237 1835184Sek110237 /* 1845184Sek110237 * Creates multiple nested directories as required by the 1855184Sek110237 * supplied path. Starts at the end of the path, creating 1865184Sek110237 * a list of directories to mkdir, up to the root of the 1875184Sek110237 * path, then mkdirs them one at a time from the root on down. 1885184Sek110237 */ 1895184Sek110237 static int 1905184Sek110237 fileset_mkdir(char *path, int mode) 1915184Sek110237 { 1925184Sek110237 char *p; 1935184Sek110237 char *dirs[65536]; 1945184Sek110237 int i = 0; 1955184Sek110237 1965184Sek110237 if ((p = strdup(path)) == NULL) 1975184Sek110237 goto null_str; 1985184Sek110237 1995184Sek110237 /* 2005184Sek110237 * Fill an array of subdirectory path names until either we 2015184Sek110237 * reach the root or encounter an already existing subdirectory 2025184Sek110237 */ 2035184Sek110237 /* CONSTCOND */ 2045184Sek110237 while (1) { 2055184Sek110237 struct stat64 sb; 2065184Sek110237 2075184Sek110237 if (stat64(p, &sb) == 0) 2085184Sek110237 break; 2095184Sek110237 if (strlen(p) < 3) 2105184Sek110237 break; 2115184Sek110237 if ((dirs[i] = strdup(p)) == NULL) { 2125184Sek110237 free(p); 2135184Sek110237 goto null_str; 2145184Sek110237 } 2155184Sek110237 2165184Sek110237 (void) trunc_dirname(p); 2175184Sek110237 i++; 2185184Sek110237 } 2195184Sek110237 2205184Sek110237 /* Make the directories, from closest to root downwards. */ 2215184Sek110237 for (--i; i >= 0; i--) { 2225184Sek110237 (void) mkdir(dirs[i], mode); 2235184Sek110237 free(dirs[i]); 2245184Sek110237 } 2255184Sek110237 2265184Sek110237 free(p); 2277556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 2285184Sek110237 2295184Sek110237 null_str: 2305184Sek110237 /* clean up */ 2315184Sek110237 for (--i; i >= 0; i--) 2325184Sek110237 free(dirs[i]); 2335184Sek110237 2345184Sek110237 filebench_log(LOG_ERROR, 2355184Sek110237 "Failed to create directory path %s: Out of memory", path); 2365184Sek110237 2377556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2385184Sek110237 } 2395184Sek110237 2405673Saw148015 /* 2415673Saw148015 * creates the subdirectory tree for a fileset. 2425673Saw148015 */ 2435673Saw148015 static int 2445673Saw148015 fileset_create_subdirs(fileset_t *fileset, char *filesetpath) 2455673Saw148015 { 2465673Saw148015 filesetentry_t *direntry; 2475673Saw148015 char full_path[MAXPATHLEN]; 2485673Saw148015 char *part_path; 2495673Saw148015 2505673Saw148015 /* walk the subdirectory list, enstanciating subdirs */ 2515673Saw148015 direntry = fileset->fs_dirlist; 2525673Saw148015 while (direntry) { 2535673Saw148015 (void) strcpy(full_path, filesetpath); 2545673Saw148015 part_path = fileset_resolvepath(direntry); 2555673Saw148015 (void) strcat(full_path, part_path); 2565673Saw148015 free(part_path); 2575673Saw148015 2585673Saw148015 /* now create this portion of the subdirectory tree */ 2597556SAndrew.W.Wilson@sun.com if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR) 2607556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2615673Saw148015 2625673Saw148015 direntry = direntry->fse_dirnext; 2635673Saw148015 } 2647556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 2655673Saw148015 } 2665673Saw148015 2675673Saw148015 /* 2685673Saw148015 * given a fileset entry, determines if the associated file 2695673Saw148015 * needs to be allocated or not, and if so does the allocation. 2705673Saw148015 */ 2715673Saw148015 static int 2725673Saw148015 fileset_alloc_file(filesetentry_t *entry) 2735673Saw148015 { 2745673Saw148015 char path[MAXPATHLEN]; 2755673Saw148015 char *buf; 2765673Saw148015 struct stat64 sb; 2775673Saw148015 char *pathtmp; 2785673Saw148015 off64_t seek; 2795673Saw148015 int fd; 2805673Saw148015 2815673Saw148015 *path = 0; 2826212Saw148015 (void) strcpy(path, avd_get_str(entry->fse_fileset->fs_path)); 2835673Saw148015 (void) strcat(path, "/"); 2846212Saw148015 (void) strcat(path, avd_get_str(entry->fse_fileset->fs_name)); 2855673Saw148015 pathtmp = fileset_resolvepath(entry); 2865673Saw148015 (void) strcat(path, pathtmp); 2875673Saw148015 2885673Saw148015 filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); 2895673Saw148015 2905673Saw148015 /* see if reusing and this file exists */ 2915673Saw148015 if ((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0)) { 2925673Saw148015 if ((fd = open64(path, O_RDWR)) < 0) { 2935673Saw148015 filebench_log(LOG_INFO, 2945673Saw148015 "Attempted but failed to Re-use file %s", 2955673Saw148015 path); 2967556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 2975673Saw148015 } 2985673Saw148015 2995673Saw148015 if (sb.st_size == (off64_t)entry->fse_size) { 3007556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL, 3015673Saw148015 "Re-using file %s", path); 3025673Saw148015 3036212Saw148015 if (!avd_get_bool(entry->fse_fileset->fs_cached)) 3045673Saw148015 (void) fileset_freemem(fd, 3055673Saw148015 entry->fse_size); 3065673Saw148015 3077556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock( 3087556SAndrew.W.Wilson@sun.com &entry->fse_fileset->fs_pick_lock); 3095673Saw148015 entry->fse_flags |= FSE_EXISTS; 3106701Saw148015 entry->fse_fileset->fs_num_act_files++; 3116701Saw148015 (void) ipc_mutex_unlock( 3127556SAndrew.W.Wilson@sun.com &entry->fse_fileset->fs_pick_lock); 3136701Saw148015 3145673Saw148015 (void) close(fd); 3157556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 3165673Saw148015 3175673Saw148015 } else if (sb.st_size > (off64_t)entry->fse_size) { 3185673Saw148015 /* reuse, but too large */ 3195673Saw148015 filebench_log(LOG_INFO, 3205673Saw148015 "Truncating & re-using file %s", path); 3215673Saw148015 3226613Sek110237 #ifdef HAVE_FTRUNCATE64 3236613Sek110237 (void) ftruncate64(fd, (off64_t)entry->fse_size); 3246613Sek110237 #else 3256613Sek110237 (void) ftruncate(fd, (off_t)entry->fse_size); 3266613Sek110237 #endif 3275673Saw148015 3286212Saw148015 if (!avd_get_bool(entry->fse_fileset->fs_cached)) 3295673Saw148015 (void) fileset_freemem(fd, 3305673Saw148015 entry->fse_size); 3315673Saw148015 3327556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock( 3337556SAndrew.W.Wilson@sun.com &entry->fse_fileset->fs_pick_lock); 3345673Saw148015 entry->fse_flags |= FSE_EXISTS; 3356701Saw148015 entry->fse_fileset->fs_num_act_files++; 3366701Saw148015 (void) ipc_mutex_unlock( 3377556SAndrew.W.Wilson@sun.com &entry->fse_fileset->fs_pick_lock); 3386701Saw148015 3395673Saw148015 (void) close(fd); 3407556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 3415673Saw148015 } 3425673Saw148015 } else { 3435673Saw148015 3445673Saw148015 /* No file or not reusing, so create */ 3455673Saw148015 if ((fd = open64(path, O_RDWR | O_CREAT, 0644)) < 0) { 3465673Saw148015 filebench_log(LOG_ERROR, 3475673Saw148015 "Failed to pre-allocate file %s: %s", 3485673Saw148015 path, strerror(errno)); 3495673Saw148015 3507556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 3515673Saw148015 } 3525673Saw148015 } 3535673Saw148015 3545673Saw148015 if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) 3557556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 3565673Saw148015 3577556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&entry->fse_fileset->fs_pick_lock); 3587556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS; 3596701Saw148015 entry->fse_fileset->fs_num_act_files++; 3607556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&entry->fse_fileset->fs_pick_lock); 3616701Saw148015 3625673Saw148015 for (seek = 0; seek < entry->fse_size; ) { 3635673Saw148015 off64_t wsize; 3645673Saw148015 int ret = 0; 3655673Saw148015 3665673Saw148015 /* 3675673Saw148015 * Write FILE_ALLOC_BLOCK's worth, 3685673Saw148015 * except on last write 3695673Saw148015 */ 3705673Saw148015 wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK); 3715673Saw148015 3725673Saw148015 ret = write(fd, buf, wsize); 3735673Saw148015 if (ret != wsize) { 3745673Saw148015 filebench_log(LOG_ERROR, 3755673Saw148015 "Failed to pre-allocate file %s: %s", 3765673Saw148015 path, strerror(errno)); 3775673Saw148015 (void) close(fd); 3785673Saw148015 free(buf); 3797556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 3805673Saw148015 } 3815673Saw148015 seek += wsize; 3825673Saw148015 } 3835673Saw148015 3846212Saw148015 if (!avd_get_bool(entry->fse_fileset->fs_cached)) 3855673Saw148015 (void) fileset_freemem(fd, entry->fse_size); 3865673Saw148015 3875673Saw148015 (void) close(fd); 3885673Saw148015 3895673Saw148015 free(buf); 3905673Saw148015 3915673Saw148015 filebench_log(LOG_DEBUG_IMPL, 3926286Saw148015 "Pre-allocated file %s size %llu", 3936286Saw148015 path, (u_longlong_t)entry->fse_size); 3945673Saw148015 3957556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 3965673Saw148015 } 3975673Saw148015 3985673Saw148015 /* 3995673Saw148015 * given a fileset entry, determines if the associated file 4005673Saw148015 * needs to be allocated or not, and if so does the allocation. 4017556SAndrew.W.Wilson@sun.com * Sets shm_fsparalloc_count to -1 on error. 4025673Saw148015 */ 4035673Saw148015 static void * 4045673Saw148015 fileset_alloc_thread(filesetentry_t *entry) 4055673Saw148015 { 4067556SAndrew.W.Wilson@sun.com if (fileset_alloc_file(entry) == FILEBENCH_ERROR) { 4077556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 4087556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count = -1; 4095673Saw148015 } else { 4107556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 4117556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count--; 4125673Saw148015 } 4135673Saw148015 4147556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv); 4157556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); 4165673Saw148015 4175673Saw148015 pthread_exit(NULL); 4185673Saw148015 return (NULL); 4195673Saw148015 } 4205673Saw148015 4215184Sek110237 4225184Sek110237 /* 4235184Sek110237 * First creates the parent directories of the file using 4245184Sek110237 * fileset_mkdir(). Then Optionally sets the O_DSYNC flag 4255184Sek110237 * and opens the file with open64(). It unlocks the fileset 4265184Sek110237 * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags 4275184Sek110237 * as requested, and returns the file descriptor integer 4285184Sek110237 * for the opened file. 4295184Sek110237 */ 4305184Sek110237 int 4315184Sek110237 fileset_openfile(fileset_t *fileset, 432*7736SAndrew.W.Wilson@sun.com filesetentry_t *entry, int flag, int filemode, int attrs) 4335184Sek110237 { 4345184Sek110237 char path[MAXPATHLEN]; 4355184Sek110237 char dir[MAXPATHLEN]; 4365184Sek110237 char *pathtmp; 4375184Sek110237 struct stat64 sb; 4385184Sek110237 int fd; 4395184Sek110237 int open_attrs = 0; 4405184Sek110237 4415184Sek110237 *path = 0; 4426212Saw148015 (void) strcpy(path, avd_get_str(fileset->fs_path)); 4435184Sek110237 (void) strcat(path, "/"); 4446212Saw148015 (void) strcat(path, avd_get_str(fileset->fs_name)); 4455184Sek110237 pathtmp = fileset_resolvepath(entry); 4465184Sek110237 (void) strcat(path, pathtmp); 4475184Sek110237 (void) strcpy(dir, path); 4485184Sek110237 free(pathtmp); 4495184Sek110237 (void) trunc_dirname(dir); 4505184Sek110237 4515184Sek110237 /* If we are going to create a file, create the parent dirs */ 4525184Sek110237 if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) { 4537556SAndrew.W.Wilson@sun.com if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR) 4547556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 4556701Saw148015 } 4566701Saw148015 4575184Sek110237 if (attrs & FLOW_ATTR_DSYNC) { 4585184Sek110237 #ifdef sun 4595184Sek110237 open_attrs |= O_DSYNC; 4605184Sek110237 #else 4615184Sek110237 open_attrs |= O_FSYNC; 4625184Sek110237 #endif 4635184Sek110237 } 4645184Sek110237 465*7736SAndrew.W.Wilson@sun.com if ((fd = open64(path, flag | open_attrs, filemode)) < 0) { 4665184Sek110237 filebench_log(LOG_ERROR, 4675184Sek110237 "Failed to open file %s: %s", 4685184Sek110237 path, strerror(errno)); 4697556SAndrew.W.Wilson@sun.com 4707556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 4717556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 4725184Sek110237 } 4737556SAndrew.W.Wilson@sun.com 4747556SAndrew.W.Wilson@sun.com if (flag & O_CREAT) 4757556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, TRUE); 4767556SAndrew.W.Wilson@sun.com else 4777556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 4785184Sek110237 4795184Sek110237 #ifdef sun 4805184Sek110237 if (attrs & FLOW_ATTR_DIRECTIO) 4815184Sek110237 (void) directio(fd, DIRECTIO_ON); 4825184Sek110237 else 4835184Sek110237 (void) directio(fd, DIRECTIO_OFF); 4845184Sek110237 #endif 4855184Sek110237 4865184Sek110237 return (fd); 4875184Sek110237 } 4885184Sek110237 4895184Sek110237 4905184Sek110237 /* 4915184Sek110237 * Selects a fileset entry from a fileset. If the 4925184Sek110237 * FILESET_PICKDIR flag is set it will pick a directory 4935184Sek110237 * entry, otherwise a file entry. The FILESET_PICKRESET 4945184Sek110237 * flag will cause it to reset the free list to the 4955184Sek110237 * overall list (file or directory). The FILESET_PICKUNIQUE 4965184Sek110237 * flag will take an entry off of one of the free (unused) 4975184Sek110237 * lists (file or directory), otherwise the entry will be 4985184Sek110237 * picked off of one of the rotor lists (file or directory). 4995184Sek110237 * The FILESET_PICKEXISTS will insure that only extant 5005184Sek110237 * (FSE_EXISTS) state files are selected, while 5015184Sek110237 * FILESET_PICKNOEXIST insures that only non extant 5025184Sek110237 * (not FSE_EXISTS) state files are selected. 5036391Saw148015 * Note that the selected fileset entry (file) is returned 5047556SAndrew.W.Wilson@sun.com * with its FSE_BUSY flag (in fse_flags) set. 5055184Sek110237 */ 5065184Sek110237 filesetentry_t * 5075184Sek110237 fileset_pick(fileset_t *fileset, int flags, int tid) 5085184Sek110237 { 5095184Sek110237 filesetentry_t *entry = NULL; 5105184Sek110237 filesetentry_t *first = NULL; 5115184Sek110237 5127556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 5137556SAndrew.W.Wilson@sun.com 5147556SAndrew.W.Wilson@sun.com /* see if we have to wait for available files or directories */ 5157556SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKDIR) { 5167556SAndrew.W.Wilson@sun.com while (fileset->fs_idle_dirs == 0) { 5177556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv, 5187556SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 5197556SAndrew.W.Wilson@sun.com } 5207556SAndrew.W.Wilson@sun.com } else { 5217556SAndrew.W.Wilson@sun.com while (fileset->fs_idle_files == 0) { 5227556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_files_cv, 5237556SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock); 5247556SAndrew.W.Wilson@sun.com } 5257556SAndrew.W.Wilson@sun.com } 5265184Sek110237 5276701Saw148015 /* see if asking for impossible */ 5286701Saw148015 if (flags & FILESET_PICKEXISTS) { 5296701Saw148015 if (fileset->fs_num_act_files == 0) { 5307556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 5316701Saw148015 return (NULL); 5326701Saw148015 } 5336701Saw148015 } else if (flags & FILESET_PICKNOEXIST) { 5346701Saw148015 if (fileset->fs_num_act_files == fileset->fs_realfiles) { 5357556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 5366701Saw148015 return (NULL); 5376701Saw148015 } 5386701Saw148015 } 5396701Saw148015 5405184Sek110237 while (entry == NULL) { 5415184Sek110237 5425184Sek110237 if ((flags & FILESET_PICKDIR) && (flags & FILESET_PICKRESET)) { 5435184Sek110237 entry = fileset->fs_dirlist; 5445184Sek110237 while (entry) { 5455184Sek110237 entry->fse_flags |= FSE_FREE; 5465184Sek110237 entry = entry->fse_dirnext; 5475184Sek110237 } 5485184Sek110237 fileset->fs_dirfree = fileset->fs_dirlist; 5495184Sek110237 } 5505184Sek110237 5515184Sek110237 if (!(flags & FILESET_PICKDIR) && (flags & FILESET_PICKRESET)) { 5525184Sek110237 entry = fileset->fs_filelist; 5535184Sek110237 while (entry) { 5545184Sek110237 entry->fse_flags |= FSE_FREE; 5555184Sek110237 entry = entry->fse_filenext; 5565184Sek110237 } 5575184Sek110237 fileset->fs_filefree = fileset->fs_filelist; 5585184Sek110237 } 5595184Sek110237 5605184Sek110237 if (flags & FILESET_PICKUNIQUE) { 5615184Sek110237 if (flags & FILESET_PICKDIR) { 5625184Sek110237 entry = fileset->fs_dirfree; 5635184Sek110237 if (entry == NULL) 5645184Sek110237 goto empty; 5655184Sek110237 fileset->fs_dirfree = entry->fse_dirnext; 5665184Sek110237 } else { 5675184Sek110237 entry = fileset->fs_filefree; 5685184Sek110237 if (entry == NULL) 5695184Sek110237 goto empty; 5705184Sek110237 fileset->fs_filefree = entry->fse_filenext; 5715184Sek110237 } 5725184Sek110237 entry->fse_flags &= ~FSE_FREE; 5735184Sek110237 } else { 5745184Sek110237 if (flags & FILESET_PICKDIR) { 5755184Sek110237 entry = fileset->fs_dirrotor; 5765184Sek110237 if (entry == NULL) 5775184Sek110237 fileset->fs_dirrotor = 5785184Sek110237 entry = fileset->fs_dirlist; 5795184Sek110237 fileset->fs_dirrotor = entry->fse_dirnext; 5805184Sek110237 } else { 5817556SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKNOEXIST) { 5827556SAndrew.W.Wilson@sun.com entry = fileset->fs_file_ne_rotor; 5837556SAndrew.W.Wilson@sun.com if (entry == NULL) 5847556SAndrew.W.Wilson@sun.com fileset->fs_file_ne_rotor = 5857556SAndrew.W.Wilson@sun.com entry = 5867556SAndrew.W.Wilson@sun.com fileset->fs_filelist; 5877556SAndrew.W.Wilson@sun.com fileset->fs_file_ne_rotor = 5887556SAndrew.W.Wilson@sun.com entry->fse_filenext; 5897556SAndrew.W.Wilson@sun.com } else { 5907556SAndrew.W.Wilson@sun.com entry = fileset->fs_filerotor[tid]; 5917556SAndrew.W.Wilson@sun.com if (entry == NULL) 5927556SAndrew.W.Wilson@sun.com fileset->fs_filerotor[tid] = 5937556SAndrew.W.Wilson@sun.com entry = 5947556SAndrew.W.Wilson@sun.com fileset->fs_filelist; 5955184Sek110237 fileset->fs_filerotor[tid] = 5967556SAndrew.W.Wilson@sun.com entry->fse_filenext; 5977556SAndrew.W.Wilson@sun.com } 5985184Sek110237 } 5995184Sek110237 } 6005184Sek110237 6015184Sek110237 if (first == entry) 6025184Sek110237 goto empty; 6035184Sek110237 6045184Sek110237 if (first == NULL) 6055184Sek110237 first = entry; 6065184Sek110237 6077556SAndrew.W.Wilson@sun.com /* see if entry in use */ 6087556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_BUSY) { 6097556SAndrew.W.Wilson@sun.com 6107556SAndrew.W.Wilson@sun.com /* it is, so try next */ 6117556SAndrew.W.Wilson@sun.com entry = NULL; 6127556SAndrew.W.Wilson@sun.com continue; 6137556SAndrew.W.Wilson@sun.com } 6145184Sek110237 6155184Sek110237 /* If we ask for an existing file, go round again */ 6165184Sek110237 if ((flags & FILESET_PICKEXISTS) && 6177556SAndrew.W.Wilson@sun.com !(entry->fse_flags & FSE_EXISTS)) 6185184Sek110237 entry = NULL; 6195184Sek110237 6205184Sek110237 /* If we ask for not an existing file, go round again */ 6215184Sek110237 if ((flags & FILESET_PICKNOEXIST) && 6227556SAndrew.W.Wilson@sun.com (entry->fse_flags & FSE_EXISTS)) 6235184Sek110237 entry = NULL; 6245184Sek110237 } 6255184Sek110237 6267556SAndrew.W.Wilson@sun.com /* update file or directory idle counts */ 6277556SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKDIR) 6287556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs--; 6297556SAndrew.W.Wilson@sun.com else 6307556SAndrew.W.Wilson@sun.com fileset->fs_idle_files--; 6317556SAndrew.W.Wilson@sun.com 6327556SAndrew.W.Wilson@sun.com /* Indicate that file or directory is now busy */ 6337556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_BUSY; 6347556SAndrew.W.Wilson@sun.com 6357556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 6365184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path); 6375184Sek110237 return (entry); 6385184Sek110237 6395184Sek110237 empty: 6407556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 6415184Sek110237 return (NULL); 6425184Sek110237 } 6435184Sek110237 6445184Sek110237 /* 6457556SAndrew.W.Wilson@sun.com * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads 6467556SAndrew.W.Wilson@sun.com * that are waiting for a NOT BUSY filesetentry. Also sets whether it is 6477556SAndrew.W.Wilson@sun.com * existant or not, or leaves that designation alone. 6487556SAndrew.W.Wilson@sun.com */ 6497556SAndrew.W.Wilson@sun.com void 6507556SAndrew.W.Wilson@sun.com fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val) 6517556SAndrew.W.Wilson@sun.com { 6527556SAndrew.W.Wilson@sun.com fileset_t *fileset = NULL; 6537556SAndrew.W.Wilson@sun.com int fse_is_dir; 6547556SAndrew.W.Wilson@sun.com 6557556SAndrew.W.Wilson@sun.com if (entry) 6567556SAndrew.W.Wilson@sun.com fileset = entry->fse_fileset; 6577556SAndrew.W.Wilson@sun.com 6587556SAndrew.W.Wilson@sun.com if (fileset == NULL) { 6597556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!"); 6607556SAndrew.W.Wilson@sun.com return; 6617556SAndrew.W.Wilson@sun.com } 6627556SAndrew.W.Wilson@sun.com 6637556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 6647556SAndrew.W.Wilson@sun.com fse_is_dir = entry->fse_flags & FSE_DIR; 6657556SAndrew.W.Wilson@sun.com 6667556SAndrew.W.Wilson@sun.com /* increment idle count, clear FSE_BUSY and signal IF it was busy */ 6677556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_BUSY) { 6687556SAndrew.W.Wilson@sun.com 6697556SAndrew.W.Wilson@sun.com /* unbusy it */ 6707556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_BUSY); 6717556SAndrew.W.Wilson@sun.com 6727556SAndrew.W.Wilson@sun.com /* release any threads waiting for unbusy */ 6737556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_THRD_WAITNG) { 6747556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_THRD_WAITNG); 6757556SAndrew.W.Wilson@sun.com (void) pthread_cond_broadcast( 6767556SAndrew.W.Wilson@sun.com &fileset->fs_thrd_wait_cv); 6777556SAndrew.W.Wilson@sun.com } 6787556SAndrew.W.Wilson@sun.com 6797556SAndrew.W.Wilson@sun.com /* increment idle count and signal waiting threads */ 6807556SAndrew.W.Wilson@sun.com if (fse_is_dir) { 6817556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs++; 6827556SAndrew.W.Wilson@sun.com if (fileset->fs_idle_dirs == 1) { 6837556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal( 6847556SAndrew.W.Wilson@sun.com &fileset->fs_idle_dirs_cv); 6857556SAndrew.W.Wilson@sun.com } 6867556SAndrew.W.Wilson@sun.com } else { 6877556SAndrew.W.Wilson@sun.com fileset->fs_idle_files++; 6887556SAndrew.W.Wilson@sun.com if (fileset->fs_idle_files == 1) { 6897556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal( 6907556SAndrew.W.Wilson@sun.com &fileset->fs_idle_files_cv); 6917556SAndrew.W.Wilson@sun.com } 6927556SAndrew.W.Wilson@sun.com } 6937556SAndrew.W.Wilson@sun.com } 6947556SAndrew.W.Wilson@sun.com 6957556SAndrew.W.Wilson@sun.com /* modify FSE_EXIST flag and actual dirs/files count, if requested */ 6967556SAndrew.W.Wilson@sun.com if (update_exist) { 6977556SAndrew.W.Wilson@sun.com if (new_exist_val == TRUE) { 6987556SAndrew.W.Wilson@sun.com if (!(entry->fse_flags & FSE_EXISTS)) { 6997556SAndrew.W.Wilson@sun.com 7007556SAndrew.W.Wilson@sun.com /* asked to set, and it was clear */ 7017556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS; 7027556SAndrew.W.Wilson@sun.com if (fse_is_dir) 7037556SAndrew.W.Wilson@sun.com fileset->fs_num_act_dirs++; 7047556SAndrew.W.Wilson@sun.com else 7057556SAndrew.W.Wilson@sun.com fileset->fs_num_act_files++; 7067556SAndrew.W.Wilson@sun.com } 7077556SAndrew.W.Wilson@sun.com } else { 7087556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_EXISTS) { 7097556SAndrew.W.Wilson@sun.com 7107556SAndrew.W.Wilson@sun.com /* asked to clear, and it was set */ 7117556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_EXISTS); 7127556SAndrew.W.Wilson@sun.com if (fse_is_dir) 7137556SAndrew.W.Wilson@sun.com fileset->fs_num_act_dirs--; 7147556SAndrew.W.Wilson@sun.com else 7157556SAndrew.W.Wilson@sun.com fileset->fs_num_act_files--; 7167556SAndrew.W.Wilson@sun.com } 7177556SAndrew.W.Wilson@sun.com } 7187556SAndrew.W.Wilson@sun.com } 7197556SAndrew.W.Wilson@sun.com 7207556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 7217556SAndrew.W.Wilson@sun.com } 7227556SAndrew.W.Wilson@sun.com 7237556SAndrew.W.Wilson@sun.com /* 7245184Sek110237 * Given a fileset "fileset", create the associated files as 7255184Sek110237 * specified in the attributes of the fileset. The fileset is 7266212Saw148015 * rooted in a directory whose pathname is in fileset_path. If the 7275184Sek110237 * directory exists, meaning that there is already a fileset, 7286212Saw148015 * and the fileset_reuse attribute is false, then remove it and all 7295184Sek110237 * its contained files and subdirectories. Next, the routine 7305184Sek110237 * creates a root directory for the fileset. All the file type 7315184Sek110237 * filesetentries are cycled through creating as needed 7325184Sek110237 * their containing subdirectory trees in the filesystem and 7336212Saw148015 * creating actual files for fileset_preallocpercent of them. The 7345184Sek110237 * created files are filled with fse_size bytes of unitialized 7357556SAndrew.W.Wilson@sun.com * data. The routine returns FILEBENCH_ERROR on errors, 7367556SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success. 7375184Sek110237 */ 7385184Sek110237 static int 7395184Sek110237 fileset_create(fileset_t *fileset) 7405184Sek110237 { 7415184Sek110237 filesetentry_t *entry; 7425184Sek110237 char path[MAXPATHLEN]; 7435184Sek110237 struct stat64 sb; 7445184Sek110237 int pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET; 7455184Sek110237 hrtime_t start = gethrtime(); 7466212Saw148015 char *fileset_path; 7476212Saw148015 char *fileset_name; 7486212Saw148015 int randno; 7495184Sek110237 int preallocated = 0; 750*7736SAndrew.W.Wilson@sun.com int reusing; 7515184Sek110237 7526212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 7535673Saw148015 filebench_log(LOG_ERROR, "%s path not set", 7545673Saw148015 fileset_entity_name(fileset)); 7557556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 7565184Sek110237 } 7575184Sek110237 7586212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 7596212Saw148015 filebench_log(LOG_ERROR, "%s name not set", 7606212Saw148015 fileset_entity_name(fileset)); 7617556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 7626212Saw148015 } 7636212Saw148015 7645673Saw148015 #ifdef HAVE_RAW_SUPPORT 7655673Saw148015 /* treat raw device as special case */ 7665673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 7677556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 7685673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 7695673Saw148015 7705184Sek110237 /* XXX Add check to see if there is enough space */ 7715184Sek110237 772*7736SAndrew.W.Wilson@sun.com /* set up path to fileset */ 7736212Saw148015 (void) strcpy(path, fileset_path); 7745184Sek110237 (void) strcat(path, "/"); 7756212Saw148015 (void) strcat(path, fileset_name); 776*7736SAndrew.W.Wilson@sun.com 777*7736SAndrew.W.Wilson@sun.com /* if exists and resusing, then don't create new */ 778*7736SAndrew.W.Wilson@sun.com if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) && 779*7736SAndrew.W.Wilson@sun.com (strlen(avd_get_str(fileset->fs_path)) > 2)) && 780*7736SAndrew.W.Wilson@sun.com avd_get_bool(fileset->fs_reuse)) { 781*7736SAndrew.W.Wilson@sun.com reusing = 1; 782*7736SAndrew.W.Wilson@sun.com } else { 783*7736SAndrew.W.Wilson@sun.com reusing = 0; 784*7736SAndrew.W.Wilson@sun.com } 785*7736SAndrew.W.Wilson@sun.com 786*7736SAndrew.W.Wilson@sun.com if (!reusing) { 787*7736SAndrew.W.Wilson@sun.com char cmd[MAXPATHLEN]; 7885184Sek110237 789*7736SAndrew.W.Wilson@sun.com /* Remove existing */ 790*7736SAndrew.W.Wilson@sun.com (void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path); 791*7736SAndrew.W.Wilson@sun.com (void) system(cmd); 792*7736SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, 793*7736SAndrew.W.Wilson@sun.com "Removed any existing %s %s in %llu seconds", 794*7736SAndrew.W.Wilson@sun.com fileset_entity_name(fileset), fileset_name, 795*7736SAndrew.W.Wilson@sun.com (u_longlong_t)(((gethrtime() - start) / 796*7736SAndrew.W.Wilson@sun.com 1000000000) + 1)); 797*7736SAndrew.W.Wilson@sun.com } else { 798*7736SAndrew.W.Wilson@sun.com /* we are re-using */ 799*7736SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, "Re-using %s %s.", 800*7736SAndrew.W.Wilson@sun.com fileset_entity_name(fileset), fileset_name); 8015184Sek110237 } 802*7736SAndrew.W.Wilson@sun.com 803*7736SAndrew.W.Wilson@sun.com /* make the filesets directory tree unless in reuse mode */ 804*7736SAndrew.W.Wilson@sun.com if (!reusing && (avd_get_bool(fileset->fs_prealloc))) { 805*7736SAndrew.W.Wilson@sun.com filebench_log(LOG_INFO, 806*7736SAndrew.W.Wilson@sun.com "making tree for filset %s", path); 8075184Sek110237 808*7736SAndrew.W.Wilson@sun.com (void) mkdir(path, 0755); 809*7736SAndrew.W.Wilson@sun.com 810*7736SAndrew.W.Wilson@sun.com if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR) 811*7736SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 812*7736SAndrew.W.Wilson@sun.com } 8135673Saw148015 8145184Sek110237 start = gethrtime(); 8155184Sek110237 8165673Saw148015 filebench_log(LOG_VERBOSE, "Creating %s %s...", 8176212Saw148015 fileset_entity_name(fileset), fileset_name); 8185673Saw148015 8196212Saw148015 if (!avd_get_bool(fileset->fs_prealloc)) 8205673Saw148015 goto exit; 8215184Sek110237 8226212Saw148015 randno = ((RAND_MAX * (100 8236212Saw148015 - avd_get_int(fileset->fs_preallocpercent))) / 100); 8246212Saw148015 8255184Sek110237 while (entry = fileset_pick(fileset, pickflags, 0)) { 8265673Saw148015 pthread_t tid; 827*7736SAndrew.W.Wilson@sun.com int newrand; 8285184Sek110237 8295184Sek110237 pickflags = FILESET_PICKUNIQUE; 8305184Sek110237 8315673Saw148015 /* entry doesn't need to be locked during initialization */ 8327556SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE); 8335673Saw148015 834*7736SAndrew.W.Wilson@sun.com newrand = rand(); 835*7736SAndrew.W.Wilson@sun.com 836*7736SAndrew.W.Wilson@sun.com if (newrand < randno) 8375184Sek110237 continue; 8385184Sek110237 8395184Sek110237 preallocated++; 8405184Sek110237 8415673Saw148015 if (reusing) 8425673Saw148015 entry->fse_flags |= FSE_REUSING; 8435673Saw148015 else 8445673Saw148015 entry->fse_flags &= (~FSE_REUSING); 8455673Saw148015 8467556SAndrew.W.Wilson@sun.com /* fire off allocation threads for each file if paralloc set */ 8476212Saw148015 if (avd_get_bool(fileset->fs_paralloc)) { 8485184Sek110237 8497556SAndrew.W.Wilson@sun.com /* limit total number of simultaneous allocations */ 8507556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock( 8517556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 8527556SAndrew.W.Wilson@sun.com while (filebench_shm->shm_fsparalloc_count 8537556SAndrew.W.Wilson@sun.com >= MAX_PARALLOC_THREADS) { 8545673Saw148015 (void) pthread_cond_wait( 8557556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv, 8567556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 8575673Saw148015 } 8585673Saw148015 8597556SAndrew.W.Wilson@sun.com /* quit if any allocation thread reports and error */ 8607556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_fsparalloc_count < 0) { 8617556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock( 8627556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 8637556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 8645184Sek110237 } 8655184Sek110237 8667556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count++; 8677556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock( 8687556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 8695184Sek110237 8707556SAndrew.W.Wilson@sun.com /* 8717556SAndrew.W.Wilson@sun.com * Fire off a detached allocation thread per file. 8727556SAndrew.W.Wilson@sun.com * The thread will self destruct when it finishes 8737556SAndrew.W.Wilson@sun.com * writing pre-allocation data to the file. 8747556SAndrew.W.Wilson@sun.com */ 8755673Saw148015 if (pthread_create(&tid, NULL, 8765673Saw148015 (void *(*)(void*))fileset_alloc_thread, 8777556SAndrew.W.Wilson@sun.com entry) == 0) { 8787556SAndrew.W.Wilson@sun.com /* 8797556SAndrew.W.Wilson@sun.com * A thread was created; detach it so it can 8807556SAndrew.W.Wilson@sun.com * fully quit when finished. 8817556SAndrew.W.Wilson@sun.com */ 8827556SAndrew.W.Wilson@sun.com (void) pthread_detach(tid); 8837556SAndrew.W.Wilson@sun.com } else { 8845184Sek110237 filebench_log(LOG_ERROR, 8855673Saw148015 "File prealloc thread create failed"); 8865673Saw148015 filebench_shutdown(1); 8875184Sek110237 } 8885184Sek110237 8895673Saw148015 } else { 8907556SAndrew.W.Wilson@sun.com if (fileset_alloc_file(entry) == FILEBENCH_ERROR) 8917556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 8925673Saw148015 } 8935673Saw148015 } 8945184Sek110237 8955673Saw148015 exit: 8965184Sek110237 filebench_log(LOG_VERBOSE, 8976286Saw148015 "Preallocated %d of %llu of %s %s in %llu seconds", 8985184Sek110237 preallocated, 8996286Saw148015 (u_longlong_t)fileset->fs_constentries, 9006212Saw148015 fileset_entity_name(fileset), fileset_name, 9016286Saw148015 (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1)); 9025184Sek110237 9037556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 9045184Sek110237 } 9055184Sek110237 9065184Sek110237 /* 9075184Sek110237 * Adds an entry to the fileset's file list. Single threaded so 9085184Sek110237 * no locking needed. 9095184Sek110237 */ 9105184Sek110237 static void 9115184Sek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry) 9125184Sek110237 { 9135184Sek110237 if (fileset->fs_filelist == NULL) { 9145184Sek110237 fileset->fs_filelist = entry; 9155184Sek110237 entry->fse_filenext = NULL; 9165184Sek110237 } else { 9175184Sek110237 entry->fse_filenext = fileset->fs_filelist; 9185184Sek110237 fileset->fs_filelist = entry; 9195184Sek110237 } 9205184Sek110237 } 9215184Sek110237 9225184Sek110237 /* 9235184Sek110237 * Adds an entry to the fileset's directory list. Single 9245184Sek110237 * threaded so no locking needed. 9255184Sek110237 */ 9265184Sek110237 static void 9275184Sek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) 9285184Sek110237 { 9295184Sek110237 if (fileset->fs_dirlist == NULL) { 9305184Sek110237 fileset->fs_dirlist = entry; 9315184Sek110237 entry->fse_dirnext = NULL; 9325184Sek110237 } else { 9335184Sek110237 entry->fse_dirnext = fileset->fs_dirlist; 9345184Sek110237 fileset->fs_dirlist = entry; 9355184Sek110237 } 9365184Sek110237 } 9375184Sek110237 9385184Sek110237 /* 9395184Sek110237 * Obtaines a filesetentry entity for a file to be placed in a 9405184Sek110237 * (sub)directory of a fileset. The size of the file may be 9416212Saw148015 * specified by fileset_meansize, or calculated from a gamma 9426212Saw148015 * distribution of parameter fileset_sizegamma and of mean size 9436212Saw148015 * fileset_meansize. The filesetentry entity is placed on the file 9445184Sek110237 * list in the specified parent filesetentry entity, which may 9455184Sek110237 * be a directory filesetentry, or the root filesetentry in the 9465184Sek110237 * fileset. It is also placed on the fileset's list of all 9477556SAndrew.W.Wilson@sun.com * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR 9487556SAndrew.W.Wilson@sun.com * if ipc memory for the path string cannot be allocated. 9495184Sek110237 */ 9505184Sek110237 static int 9515184Sek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) 9525184Sek110237 { 9535184Sek110237 char tmpname[16]; 9545184Sek110237 filesetentry_t *entry; 9555184Sek110237 double drand; 9565184Sek110237 9575184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 9585184Sek110237 == NULL) { 9595184Sek110237 filebench_log(LOG_ERROR, 9605184Sek110237 "fileset_populate_file: Can't malloc filesetentry"); 9617556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 9625184Sek110237 } 9635184Sek110237 9647556SAndrew.W.Wilson@sun.com /* Another currently idle file */ 9657556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 9667556SAndrew.W.Wilson@sun.com fileset->fs_idle_files++; 9677556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 9687556SAndrew.W.Wilson@sun.com 9695184Sek110237 entry->fse_parent = parent; 9705184Sek110237 entry->fse_fileset = fileset; 9717556SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_FREE; 9725184Sek110237 fileset_insfilelist(fileset, entry); 9735184Sek110237 9745184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 9755184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 9765184Sek110237 filebench_log(LOG_ERROR, 9775184Sek110237 "fileset_populate_file: Can't alloc path string"); 9787556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 9795184Sek110237 } 9805184Sek110237 9816212Saw148015 /* see if random variable was supplied for file size */ 9826212Saw148015 if (fileset->fs_meansize == -1) { 9836212Saw148015 entry->fse_size = (off64_t)avd_get_int(fileset->fs_size); 9846212Saw148015 } else { 9856212Saw148015 double gamma; 9865184Sek110237 9876212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 9886212Saw148015 if (gamma > 0) { 9896212Saw148015 drand = gamma_dist_knuth(gamma, 9906212Saw148015 fileset->fs_meansize / gamma); 9916212Saw148015 entry->fse_size = (off64_t)drand; 9926212Saw148015 } else { 9936212Saw148015 entry->fse_size = (off64_t)fileset->fs_meansize; 9946212Saw148015 } 9955184Sek110237 } 9965184Sek110237 9975184Sek110237 fileset->fs_bytes += entry->fse_size; 9985184Sek110237 9995184Sek110237 fileset->fs_realfiles++; 10007556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 10015184Sek110237 } 10025184Sek110237 10035184Sek110237 /* 10045184Sek110237 * Creates a directory node in a fileset, by obtaining a 10055184Sek110237 * filesetentry entity for the node and initializing it 10065184Sek110237 * according to parameters of the fileset. It determines a 10075184Sek110237 * directory tree depth and directory width, optionally using 10085184Sek110237 * a gamma distribution. If its calculated depth is less then 10095184Sek110237 * its actual depth in the directory tree, it becomes a leaf 10105184Sek110237 * node and files itself with "width" number of file type 10115184Sek110237 * filesetentries, otherwise it files itself with "width" 10125184Sek110237 * number of directory type filesetentries, using recursive 10135184Sek110237 * calls to fileset_populate_subdir. The end result of the 10145184Sek110237 * initial call to this routine is a tree of directories of 10155184Sek110237 * random width and varying depth with sufficient leaf 10165184Sek110237 * directories to contain all required files. 10177556SAndrew.W.Wilson@sun.com * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path 10187556SAndrew.W.Wilson@sun.com * string memory cannot be allocated and returns the error code (currently 10197556SAndrew.W.Wilson@sun.com * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive 10205184Sek110237 * calls to fileset_populate_subdir. 10215184Sek110237 */ 10225184Sek110237 static int 10235184Sek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, 10245184Sek110237 int serial, double depth) 10255184Sek110237 { 10266212Saw148015 double randepth, drand, ranwidth; 10275184Sek110237 int isleaf = 0; 10285184Sek110237 char tmpname[16]; 10295184Sek110237 filesetentry_t *entry; 10305184Sek110237 int i; 10315184Sek110237 10325184Sek110237 depth += 1; 10335184Sek110237 10345184Sek110237 /* Create dir node */ 10355184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 10365184Sek110237 == NULL) { 10375184Sek110237 filebench_log(LOG_ERROR, 10385184Sek110237 "fileset_populate_subdir: Can't malloc filesetentry"); 10397556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 10405184Sek110237 } 10415184Sek110237 10427556SAndrew.W.Wilson@sun.com /* another idle directory */ 10437556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock); 10447556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs++; 10457556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock); 10465184Sek110237 10475184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 10485184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 10495184Sek110237 filebench_log(LOG_ERROR, 10505184Sek110237 "fileset_populate_subdir: Can't alloc path string"); 10517556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 10525184Sek110237 } 10535184Sek110237 10545184Sek110237 entry->fse_parent = parent; 10557556SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_DIR | FSE_FREE; 10565184Sek110237 fileset_insdirlist(fileset, entry); 10575184Sek110237 10586212Saw148015 if (fileset->fs_dirdepthrv) { 10596212Saw148015 randepth = (int)avd_get_int(fileset->fs_dirdepthrv); 10605184Sek110237 } else { 10616212Saw148015 double gamma; 10626212Saw148015 10636212Saw148015 gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0; 10646212Saw148015 if (gamma > 0) { 10656212Saw148015 drand = gamma_dist_knuth(gamma, 10666212Saw148015 fileset->fs_meandepth / gamma); 10676212Saw148015 randepth = (int)drand; 10686212Saw148015 } else { 10696212Saw148015 randepth = (int)fileset->fs_meandepth; 10706212Saw148015 } 10715184Sek110237 } 10725184Sek110237 10736212Saw148015 if (fileset->fs_meanwidth == -1) { 10746212Saw148015 ranwidth = avd_get_dbl(fileset->fs_dirwidth); 10756212Saw148015 } else { 10766212Saw148015 double gamma; 10775184Sek110237 10786212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 10796212Saw148015 if (gamma > 0) { 10806212Saw148015 drand = gamma_dist_knuth(gamma, 10816212Saw148015 fileset->fs_meanwidth / gamma); 10826212Saw148015 ranwidth = drand; 10836212Saw148015 } else { 10846212Saw148015 ranwidth = fileset->fs_meanwidth; 10856212Saw148015 } 10865184Sek110237 } 10875184Sek110237 10885184Sek110237 if (randepth == 0) 10895184Sek110237 randepth = 1; 10905184Sek110237 if (ranwidth == 0) 10915184Sek110237 ranwidth = 1; 10925184Sek110237 if (depth >= randepth) 10935184Sek110237 isleaf = 1; 10945184Sek110237 10955184Sek110237 /* 10965184Sek110237 * Create directory of random width according to distribution, or 10975184Sek110237 * if root directory, continue until #files required 10985184Sek110237 */ 10996212Saw148015 for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && 11006212Saw148015 (fileset->fs_realfiles < fileset->fs_constentries); 11016212Saw148015 i++) { 11025184Sek110237 int ret = 0; 11035184Sek110237 11045184Sek110237 if (parent && isleaf) 11055184Sek110237 ret = fileset_populate_file(fileset, entry, i); 11065184Sek110237 else 11075184Sek110237 ret = fileset_populate_subdir(fileset, entry, i, depth); 11085184Sek110237 11095184Sek110237 if (ret != 0) 11105184Sek110237 return (ret); 11115184Sek110237 } 11127556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 11135184Sek110237 } 11145184Sek110237 11155184Sek110237 /* 11165184Sek110237 * Populates a fileset with files and subdirectory entries. Uses 11176212Saw148015 * the supplied fileset_dirwidth and fileset_entries (number of files) to 11186212Saw148015 * calculate the required fileset_meandepth (of subdirectories) and 11196212Saw148015 * initialize the fileset_meanwidth and fileset_meansize variables. Then 11205184Sek110237 * calls fileset_populate_subdir() to do the recursive 11215184Sek110237 * subdirectory entry creation and leaf file entry creation. All 11225184Sek110237 * of the above is skipped if the fileset has already been 11235184Sek110237 * populated. Returns 0 on success, or an error code from the 11245184Sek110237 * call to fileset_populate_subdir if that call fails. 11255184Sek110237 */ 11265184Sek110237 static int 11275184Sek110237 fileset_populate(fileset_t *fileset) 11285184Sek110237 { 11296212Saw148015 int entries = (int)avd_get_int(fileset->fs_entries); 11306212Saw148015 int meandirwidth; 11315184Sek110237 int ret; 11325184Sek110237 11335184Sek110237 /* Skip if already populated */ 11345184Sek110237 if (fileset->fs_bytes > 0) 11355184Sek110237 goto exists; 11365184Sek110237 11375673Saw148015 #ifdef HAVE_RAW_SUPPORT 11385673Saw148015 /* check for raw device */ 11395673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 11407556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 11415673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 11425673Saw148015 11436212Saw148015 /* save value of entries obtained for later, in case it was random */ 11446212Saw148015 fileset->fs_constentries = entries; 11456212Saw148015 11467556SAndrew.W.Wilson@sun.com /* declare all files currently non existant */ 11477556SAndrew.W.Wilson@sun.com fileset->fs_num_act_files = 0; 11487556SAndrew.W.Wilson@sun.com 11497556SAndrew.W.Wilson@sun.com /* initialize idle files and directories condition variables */ 11507556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr()); 11517556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr()); 11527556SAndrew.W.Wilson@sun.com 11537556SAndrew.W.Wilson@sun.com /* no files or dirs idle (or busy) yet */ 11547556SAndrew.W.Wilson@sun.com fileset->fs_idle_files = 0; 11557556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs = 0; 11567556SAndrew.W.Wilson@sun.com 11577556SAndrew.W.Wilson@sun.com /* initialize locks and other condition variables */ 11587556SAndrew.W.Wilson@sun.com (void) pthread_mutex_init(&fileset->fs_pick_lock, 11597556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL)); 11607556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr()); 11617556SAndrew.W.Wilson@sun.com 11626212Saw148015 /* is dirwidth a random variable? */ 11636212Saw148015 if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { 11646212Saw148015 meandirwidth = 11656212Saw148015 (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean; 11666212Saw148015 fileset->fs_meanwidth = -1; 11676212Saw148015 } else { 11686212Saw148015 meandirwidth = (int)avd_get_int(fileset->fs_dirwidth); 11696212Saw148015 fileset->fs_meanwidth = (double)meandirwidth; 11706212Saw148015 } 11716212Saw148015 11725184Sek110237 /* 11735184Sek110237 * Input params are: 11745184Sek110237 * # of files 11755184Sek110237 * ave # of files per dir 11765184Sek110237 * max size of dir 11775184Sek110237 * # ave size of file 11785184Sek110237 * max size of file 11795184Sek110237 */ 11806212Saw148015 fileset->fs_meandepth = log(entries) / log(meandirwidth); 11816212Saw148015 11826212Saw148015 /* Has a random variable been supplied for dirdepth? */ 11836212Saw148015 if (fileset->fs_dirdepthrv) { 11846212Saw148015 /* yes, so set the random variable's mean value to meandepth */ 11856212Saw148015 fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean = 11866212Saw148015 fileset->fs_meandepth; 11876212Saw148015 } 11886212Saw148015 11896212Saw148015 /* test for random size variable */ 11906212Saw148015 if (AVD_IS_RANDOM(fileset->fs_size)) 11916212Saw148015 fileset->fs_meansize = -1; 11926212Saw148015 else 11936212Saw148015 fileset->fs_meansize = avd_get_int(fileset->fs_size); 11945184Sek110237 11955184Sek110237 if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0) 11965184Sek110237 return (ret); 11975184Sek110237 11985184Sek110237 11995184Sek110237 exists: 12005673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 12016286Saw148015 filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu", 12026212Saw148015 avd_get_str(fileset->fs_name), 12036286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 12045673Saw148015 } else { 12056286Saw148015 filebench_log(LOG_VERBOSE, "Fileset %s: %d files, " 12066286Saw148015 "avg dir = %d, avg depth = %.1lf, mbytes=%llu", 12076212Saw148015 avd_get_str(fileset->fs_name), entries, 12086212Saw148015 meandirwidth, 12095673Saw148015 fileset->fs_meandepth, 12106286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 12115673Saw148015 } 12126701Saw148015 12137556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 12145184Sek110237 } 12155184Sek110237 12165184Sek110237 /* 12176212Saw148015 * Allocates a fileset instance, initializes fileset_dirgamma and 12186212Saw148015 * fileset_sizegamma default values, and sets the fileset name to the 12195184Sek110237 * supplied name string. Puts the allocated fileset on the 12205184Sek110237 * master fileset list and returns a pointer to it. 12216701Saw148015 * 12226701Saw148015 * This routine implements the 'define fileset' calls found in a .f 12236701Saw148015 * workload, such as in the following example: 12246701Saw148015 * define fileset name=drew4ever, entries=$nfiles 12255184Sek110237 */ 12265184Sek110237 fileset_t * 12276212Saw148015 fileset_define(avd_t name) 12285184Sek110237 { 12295184Sek110237 fileset_t *fileset; 12305184Sek110237 12315184Sek110237 if (name == NULL) 12325184Sek110237 return (NULL); 12335184Sek110237 12345184Sek110237 if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) { 12355184Sek110237 filebench_log(LOG_ERROR, 12365184Sek110237 "fileset_define: Can't malloc fileset"); 12375184Sek110237 return (NULL); 12385184Sek110237 } 12395184Sek110237 12406212Saw148015 filebench_log(LOG_DEBUG_IMPL, 12416212Saw148015 "Defining file %s", avd_get_str(name)); 12425184Sek110237 12436391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 12445184Sek110237 12456212Saw148015 fileset->fs_dirgamma = avd_int_alloc(1500); 12466212Saw148015 fileset->fs_sizegamma = avd_int_alloc(1500); 12475184Sek110237 12485184Sek110237 /* Add fileset to global list */ 12496391Saw148015 if (filebench_shm->shm_filesetlist == NULL) { 12506391Saw148015 filebench_shm->shm_filesetlist = fileset; 12515184Sek110237 fileset->fs_next = NULL; 12525184Sek110237 } else { 12536391Saw148015 fileset->fs_next = filebench_shm->shm_filesetlist; 12546391Saw148015 filebench_shm->shm_filesetlist = fileset; 12555184Sek110237 } 12565184Sek110237 12576391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 12585184Sek110237 12596212Saw148015 fileset->fs_name = name; 12605184Sek110237 12615184Sek110237 return (fileset); 12625184Sek110237 } 12635184Sek110237 12645184Sek110237 /* 12655184Sek110237 * If supplied with a pointer to a fileset and the fileset's 12666212Saw148015 * fileset_prealloc flag is set, calls fileset_populate() to populate 12675184Sek110237 * the fileset with filesetentries, then calls fileset_create() 12685184Sek110237 * to make actual directories and files for the filesetentries. 12695184Sek110237 * Otherwise, it applies fileset_populate() and fileset_create() 12705184Sek110237 * to all the filesets on the master fileset list. It always 12715184Sek110237 * returns zero (0) if one fileset is populated / created, 12725184Sek110237 * otherwise it returns the sum of returned values from 12735184Sek110237 * fileset_create() and fileset_populate(), which 12745184Sek110237 * will be a negative one (-1) times the number of 12755184Sek110237 * fileset_create() calls which failed. 12765184Sek110237 */ 12775184Sek110237 int 12785184Sek110237 fileset_createset(fileset_t *fileset) 12795184Sek110237 { 12805184Sek110237 fileset_t *list; 12815184Sek110237 int ret = 0; 12825184Sek110237 12835673Saw148015 /* set up for possible parallel allocate */ 12847556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count = 0; 12857556SAndrew.W.Wilson@sun.com (void) pthread_cond_init( 12867556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv, 12877556SAndrew.W.Wilson@sun.com ipc_condattr()); 12885673Saw148015 12896212Saw148015 if (fileset && avd_get_bool(fileset->fs_prealloc)) { 12905673Saw148015 12916305Saw148015 /* check for raw files */ 12926305Saw148015 if (fileset_checkraw(fileset)) { 12936305Saw148015 filebench_log(LOG_INFO, 12946305Saw148015 "file %s/%s is a RAW device", 12956305Saw148015 avd_get_str(fileset->fs_path), 12966305Saw148015 avd_get_str(fileset->fs_name)); 12977556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 12986305Saw148015 } 12996305Saw148015 13005673Saw148015 filebench_log(LOG_INFO, 13015673Saw148015 "creating/pre-allocating %s %s", 13026212Saw148015 fileset_entity_name(fileset), 13036212Saw148015 avd_get_str(fileset->fs_name)); 13045673Saw148015 13057556SAndrew.W.Wilson@sun.com if ((ret = fileset_populate(fileset)) != FILEBENCH_OK) 13065184Sek110237 return (ret); 13075673Saw148015 13087556SAndrew.W.Wilson@sun.com if ((ret = fileset_create(fileset)) != FILEBENCH_OK) 13095673Saw148015 return (ret); 13105673Saw148015 } else { 13115673Saw148015 13125673Saw148015 filebench_log(LOG_INFO, 13135673Saw148015 "Creating/pre-allocating files and filesets"); 13145673Saw148015 13156391Saw148015 list = filebench_shm->shm_filesetlist; 13165673Saw148015 while (list) { 13176305Saw148015 /* check for raw files */ 13186305Saw148015 if (fileset_checkraw(list)) { 13196305Saw148015 filebench_log(LOG_INFO, 13206305Saw148015 "file %s/%s is a RAW device", 13216305Saw148015 avd_get_str(list->fs_path), 13226305Saw148015 avd_get_str(list->fs_name)); 13236305Saw148015 list = list->fs_next; 13246305Saw148015 continue; 13256305Saw148015 } 13266305Saw148015 13277556SAndrew.W.Wilson@sun.com if ((ret = fileset_populate(list)) != FILEBENCH_OK) 13285673Saw148015 return (ret); 13297556SAndrew.W.Wilson@sun.com 13307556SAndrew.W.Wilson@sun.com if ((ret = fileset_create(list)) != FILEBENCH_OK) 13315673Saw148015 return (ret); 13327556SAndrew.W.Wilson@sun.com 13335673Saw148015 list = list->fs_next; 13345673Saw148015 } 13355184Sek110237 } 13365184Sek110237 13375673Saw148015 /* wait for allocation threads to finish */ 13385673Saw148015 filebench_log(LOG_INFO, 13395673Saw148015 "waiting for fileset pre-allocation to finish"); 13405184Sek110237 13417556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); 13427556SAndrew.W.Wilson@sun.com while (filebench_shm->shm_fsparalloc_count > 0) 13437556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait( 13447556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv, 13457556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock); 13467556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); 13475673Saw148015 13487556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_fsparalloc_count < 0) 13497556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 13505673Saw148015 13517556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 13525184Sek110237 } 13535184Sek110237 13545184Sek110237 /* 13555184Sek110237 * Searches through the master fileset list for the named fileset. 13565184Sek110237 * If found, returns pointer to same, otherwise returns NULL. 13575184Sek110237 */ 13585184Sek110237 fileset_t * 13595184Sek110237 fileset_find(char *name) 13605184Sek110237 { 13616391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 13625184Sek110237 13636391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 13645184Sek110237 13655184Sek110237 while (fileset) { 13666212Saw148015 if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) { 13676391Saw148015 (void) ipc_mutex_unlock( 13686391Saw148015 &filebench_shm->shm_fileset_lock); 13695184Sek110237 return (fileset); 13705184Sek110237 } 13715184Sek110237 fileset = fileset->fs_next; 13725184Sek110237 } 13736391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 13745184Sek110237 13755184Sek110237 return (NULL); 13765184Sek110237 } 13775673Saw148015 13785673Saw148015 /* 13795673Saw148015 * Iterates over all the file sets in the filesetlist, 13805673Saw148015 * executing the supplied command "*cmd()" on them. Also 13815673Saw148015 * indicates to the executed command if it is the first 13825673Saw148015 * time the command has been executed since the current 13835673Saw148015 * call to fileset_iter. 13845673Saw148015 */ 13855673Saw148015 void 13865673Saw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first)) 13875673Saw148015 { 13886391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 13895673Saw148015 int count = 0; 13905673Saw148015 13916391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 13925673Saw148015 13935673Saw148015 while (fileset) { 13945673Saw148015 cmd(fileset, count == 0); 13955673Saw148015 fileset = fileset->fs_next; 13965673Saw148015 count++; 13975673Saw148015 } 13985673Saw148015 13996391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 14005673Saw148015 } 14015673Saw148015 14025673Saw148015 /* 14035673Saw148015 * Prints information to the filebench log about the file 14045673Saw148015 * object. Also prints a header on the first call. 14055673Saw148015 */ 14065673Saw148015 int 14075673Saw148015 fileset_print(fileset_t *fileset, int first) 14085673Saw148015 { 14096212Saw148015 int pathlength; 14106212Saw148015 char *fileset_path; 14116212Saw148015 char *fileset_name; 14126212Saw148015 static char pad[] = " "; /* 30 spaces */ 14136212Saw148015 14146212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 14156212Saw148015 filebench_log(LOG_ERROR, "%s path not set", 14166212Saw148015 fileset_entity_name(fileset)); 14177556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 14186212Saw148015 } 14196212Saw148015 14206212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 14216212Saw148015 filebench_log(LOG_ERROR, "%s name not set", 14226212Saw148015 fileset_entity_name(fileset)); 14237556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 14246212Saw148015 } 14256212Saw148015 14266212Saw148015 pathlength = strlen(fileset_path) + strlen(fileset_name); 14275673Saw148015 14285673Saw148015 if (pathlength > 29) 14295673Saw148015 pathlength = 29; 14305673Saw148015 14315673Saw148015 if (first) { 14325673Saw148015 filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s", 14335673Saw148015 "file size", 14345673Saw148015 "dir width", 14355673Saw148015 "entries"); 14365673Saw148015 } 14375673Saw148015 14385673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 14395673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { 14405673Saw148015 filebench_log(LOG_INFO, 14415673Saw148015 "%s/%s%s (Raw Device)", 14426212Saw148015 fileset_path, fileset_name, &pad[pathlength]); 14435673Saw148015 } else { 14445673Saw148015 filebench_log(LOG_INFO, 14456286Saw148015 "%s/%s%s%9llu (Single File)", 14466212Saw148015 fileset_path, fileset_name, &pad[pathlength], 14476286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size)); 14485673Saw148015 } 14495673Saw148015 } else { 14506286Saw148015 filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu", 14516212Saw148015 fileset_path, fileset_name, 14525673Saw148015 &pad[pathlength], 14536286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size), 14546286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_dirwidth), 14556286Saw148015 (u_longlong_t)fileset->fs_constentries); 14565673Saw148015 } 14577556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 14585673Saw148015 } 14595673Saw148015 /* 14605673Saw148015 * checks to see if the path/name pair points to a raw device. If 14615673Saw148015 * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1. 14625673Saw148015 * If RAW is not defined, or it is not a raw device, it clears the 14635673Saw148015 * raw device flag and returns 0. 14645673Saw148015 */ 14655673Saw148015 int 14665673Saw148015 fileset_checkraw(fileset_t *fileset) 14675673Saw148015 { 14685673Saw148015 char path[MAXPATHLEN]; 14695673Saw148015 struct stat64 sb; 14706305Saw148015 char *pathname; 14716305Saw148015 char *setname; 14725673Saw148015 14735673Saw148015 fileset->fs_attrs &= (~FILESET_IS_RAW_DEV); 14745673Saw148015 14755673Saw148015 #ifdef HAVE_RAW_SUPPORT 14765673Saw148015 /* check for raw device */ 14776305Saw148015 if ((pathname = avd_get_str(fileset->fs_path)) == NULL) 14787556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 14796305Saw148015 14806305Saw148015 if ((setname = avd_get_str(fileset->fs_name)) == NULL) 14817556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 14826305Saw148015 14836305Saw148015 (void) strcpy(path, pathname); 14845673Saw148015 (void) strcat(path, "/"); 14856305Saw148015 (void) strcat(path, setname); 14865673Saw148015 if ((stat64(path, &sb) == 0) && 14875673Saw148015 ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { 14885673Saw148015 fileset->fs_attrs |= FILESET_IS_RAW_DEV; 14896305Saw148015 if (!(fileset->fs_attrs & FILESET_IS_FILE)) { 14906305Saw148015 filebench_log(LOG_ERROR, 14916305Saw148015 "WARNING Fileset %s/%s Cannot be RAW device", 14926305Saw148015 avd_get_str(fileset->fs_path), 14936305Saw148015 avd_get_str(fileset->fs_name)); 14946305Saw148015 filebench_shutdown(1); 14956305Saw148015 } 14966305Saw148015 14975673Saw148015 return (1); 14985673Saw148015 } 14995673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 15005673Saw148015 15017556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK); 15025673Saw148015 } 1503