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. 24*6613Sek110237 * 25*6613Sek110237 * Portions Copyright 2008 Denis Cheng 265184Sek110237 */ 275184Sek110237 285184Sek110237 #pragma ident "%Z%%M% %I% %E% SMI" 295184Sek110237 305184Sek110237 315184Sek110237 #include <fcntl.h> 325184Sek110237 #include <pthread.h> 335184Sek110237 #include <errno.h> 345184Sek110237 #include <math.h> 355184Sek110237 #include <libgen.h> 365184Sek110237 #include <sys/mman.h> 37*6613Sek110237 38*6613Sek110237 #include "filebench.h" 395184Sek110237 #include "fileset.h" 405184Sek110237 #include "gamma_dist.h" 415184Sek110237 425184Sek110237 /* 435184Sek110237 * File sets, of type fileset_t, are entities which contain 445184Sek110237 * information about collections of files and subdirectories in Filebench. 455184Sek110237 * The fileset, once populated, consists of a tree of fileset entries of 465184Sek110237 * type filesetentry_t which specify files and directories. The fileset 476212Saw148015 * is rooted in a directory specified by fileset_path, and once the populated 485184Sek110237 * fileset has been created, has a tree of directories and files 495184Sek110237 * corresponding to the fileset's filesetentry tree. 505184Sek110237 */ 515184Sek110237 526305Saw148015 static int fileset_checkraw(fileset_t *fileset); 536305Saw148015 545673Saw148015 /* parallel allocation control */ 555673Saw148015 #define MAX_PARALLOC_THREADS 32 565673Saw148015 static pthread_mutex_t paralloc_lock = PTHREAD_MUTEX_INITIALIZER; 575673Saw148015 static pthread_cond_t paralloc_cv = PTHREAD_COND_INITIALIZER; 585673Saw148015 static int paralloc_count; 595673Saw148015 605673Saw148015 /* 615673Saw148015 * returns pointer to file or fileset 625673Saw148015 * string, as appropriate 635673Saw148015 */ 645673Saw148015 static char * 655673Saw148015 fileset_entity_name(fileset_t *fileset) 665673Saw148015 { 675673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) 685673Saw148015 return ("file"); 695673Saw148015 else 705673Saw148015 return ("fileset"); 715673Saw148015 } 725673Saw148015 735184Sek110237 /* 745184Sek110237 * Removes the last file or directory name from a pathname. 755184Sek110237 * Basically removes characters from the end of the path by 765184Sek110237 * setting them to \0 until a forward slash '/' is 775184Sek110237 * encountered. It also removes the forward slash. 785184Sek110237 */ 795184Sek110237 static char * 805184Sek110237 trunc_dirname(char *dir) 815184Sek110237 { 825184Sek110237 char *s = dir + strlen(dir); 835184Sek110237 845184Sek110237 while (s != dir) { 855184Sek110237 int c = *s; 865184Sek110237 875184Sek110237 *s = 0; 885184Sek110237 if (c == '/') 895184Sek110237 break; 905184Sek110237 s--; 915184Sek110237 } 925184Sek110237 return (dir); 935184Sek110237 } 945184Sek110237 955184Sek110237 /* 965184Sek110237 * Prints a list of allowed options and how to specify them. 975184Sek110237 */ 985184Sek110237 void 995184Sek110237 fileset_usage(void) 1005184Sek110237 { 1015673Saw148015 (void) fprintf(stderr, 1025673Saw148015 "define [file name=<name> | fileset name=<name>],path=<pathname>," 1035673Saw148015 ",entries=<number>\n"); 1045673Saw148015 (void) fprintf(stderr, 1056212Saw148015 " [,filesize=[size]]\n"); 1066212Saw148015 (void) fprintf(stderr, 1075673Saw148015 " [,dirwidth=[width]]\n"); 1085673Saw148015 (void) fprintf(stderr, 1096212Saw148015 " [,dirdepthrv=$random_variable_name]\n"); 1106212Saw148015 (void) fprintf(stderr, 1115673Saw148015 " [,dirgamma=[100-10000]] " 1125184Sek110237 "(Gamma * 1000)\n"); 1135184Sek110237 (void) fprintf(stderr, 1145673Saw148015 " [,sizegamma=[100-10000]] (Gamma * 1000)\n"); 1155184Sek110237 (void) fprintf(stderr, 1165184Sek110237 " [,prealloc=[percent]]\n"); 1175673Saw148015 (void) fprintf(stderr, " [,paralloc]\n"); 1185184Sek110237 (void) fprintf(stderr, " [,reuse]\n"); 1195184Sek110237 (void) fprintf(stderr, "\n"); 1205184Sek110237 } 1215184Sek110237 1225184Sek110237 /* 1235184Sek110237 * Frees up memory mapped file region of supplied size. The 1245184Sek110237 * file descriptor "fd" indicates which memory mapped file. 1255184Sek110237 * If successful, returns 0. Otherwise returns -1 if "size" 1265184Sek110237 * is zero, or -1 times the number of times msync() failed. 1275184Sek110237 */ 1285184Sek110237 static int 1295184Sek110237 fileset_freemem(int fd, off64_t size) 1305184Sek110237 { 1315184Sek110237 off64_t left; 1325184Sek110237 int ret = 0; 1335184Sek110237 1345184Sek110237 for (left = size; left > 0; left -= MMAP_SIZE) { 1355184Sek110237 off64_t thismapsize; 1365184Sek110237 caddr_t addr; 1375184Sek110237 1385184Sek110237 thismapsize = MIN(MMAP_SIZE, left); 1395184Sek110237 addr = mmap64(0, thismapsize, PROT_READ|PROT_WRITE, 1405184Sek110237 MAP_SHARED, fd, size - left); 1415184Sek110237 ret += msync(addr, thismapsize, MS_INVALIDATE); 1425184Sek110237 (void) munmap(addr, thismapsize); 1435184Sek110237 } 1445184Sek110237 return (ret); 1455184Sek110237 } 1465184Sek110237 1475184Sek110237 /* 1485184Sek110237 * Creates a path string from the filesetentry_t "*entry" 1495184Sek110237 * and all of its parent's path names. The resulting path 1505184Sek110237 * is a concatination of all the individual parent paths. 1515184Sek110237 * Allocates memory for the path string and returns a 1525184Sek110237 * pointer to it. 1535184Sek110237 */ 1545184Sek110237 char * 1555184Sek110237 fileset_resolvepath(filesetentry_t *entry) 1565184Sek110237 { 1575184Sek110237 filesetentry_t *fsep = entry; 1585184Sek110237 char path[MAXPATHLEN]; 1595184Sek110237 char pathtmp[MAXPATHLEN]; 1605184Sek110237 char *s; 1615184Sek110237 1625184Sek110237 *path = 0; 1635184Sek110237 while (fsep->fse_parent) { 1645184Sek110237 (void) strcpy(pathtmp, "/"); 1655184Sek110237 (void) strcat(pathtmp, fsep->fse_path); 1665184Sek110237 (void) strcat(pathtmp, path); 1675184Sek110237 (void) strcpy(path, pathtmp); 1685184Sek110237 fsep = fsep->fse_parent; 1695184Sek110237 } 1705184Sek110237 1715184Sek110237 s = malloc(strlen(path) + 1); 1725184Sek110237 (void) strcpy(s, path); 1735184Sek110237 return (s); 1745184Sek110237 } 1755184Sek110237 1765184Sek110237 /* 1775184Sek110237 * Creates multiple nested directories as required by the 1785184Sek110237 * supplied path. Starts at the end of the path, creating 1795184Sek110237 * a list of directories to mkdir, up to the root of the 1805184Sek110237 * path, then mkdirs them one at a time from the root on down. 1815184Sek110237 */ 1825184Sek110237 static int 1835184Sek110237 fileset_mkdir(char *path, int mode) 1845184Sek110237 { 1855184Sek110237 char *p; 1865184Sek110237 char *dirs[65536]; 1875184Sek110237 int i = 0; 1885184Sek110237 1895184Sek110237 if ((p = strdup(path)) == NULL) 1905184Sek110237 goto null_str; 1915184Sek110237 1925184Sek110237 /* 1935184Sek110237 * Fill an array of subdirectory path names until either we 1945184Sek110237 * reach the root or encounter an already existing subdirectory 1955184Sek110237 */ 1965184Sek110237 /* CONSTCOND */ 1975184Sek110237 while (1) { 1985184Sek110237 struct stat64 sb; 1995184Sek110237 2005184Sek110237 if (stat64(p, &sb) == 0) 2015184Sek110237 break; 2025184Sek110237 if (strlen(p) < 3) 2035184Sek110237 break; 2045184Sek110237 if ((dirs[i] = strdup(p)) == NULL) { 2055184Sek110237 free(p); 2065184Sek110237 goto null_str; 2075184Sek110237 } 2085184Sek110237 2095184Sek110237 (void) trunc_dirname(p); 2105184Sek110237 i++; 2115184Sek110237 } 2125184Sek110237 2135184Sek110237 /* Make the directories, from closest to root downwards. */ 2145184Sek110237 for (--i; i >= 0; i--) { 2155184Sek110237 (void) mkdir(dirs[i], mode); 2165184Sek110237 free(dirs[i]); 2175184Sek110237 } 2185184Sek110237 2195184Sek110237 free(p); 2205184Sek110237 return (0); 2215184Sek110237 2225184Sek110237 null_str: 2235184Sek110237 /* clean up */ 2245184Sek110237 for (--i; i >= 0; i--) 2255184Sek110237 free(dirs[i]); 2265184Sek110237 2275184Sek110237 filebench_log(LOG_ERROR, 2285184Sek110237 "Failed to create directory path %s: Out of memory", path); 2295184Sek110237 2305184Sek110237 return (-1); 2315184Sek110237 } 2325184Sek110237 2335673Saw148015 /* 2345673Saw148015 * creates the subdirectory tree for a fileset. 2355673Saw148015 */ 2365673Saw148015 static int 2375673Saw148015 fileset_create_subdirs(fileset_t *fileset, char *filesetpath) 2385673Saw148015 { 2395673Saw148015 filesetentry_t *direntry; 2405673Saw148015 char full_path[MAXPATHLEN]; 2415673Saw148015 char *part_path; 2425673Saw148015 2435673Saw148015 /* walk the subdirectory list, enstanciating subdirs */ 2445673Saw148015 direntry = fileset->fs_dirlist; 2455673Saw148015 while (direntry) { 2465673Saw148015 (void) strcpy(full_path, filesetpath); 2475673Saw148015 part_path = fileset_resolvepath(direntry); 2485673Saw148015 (void) strcat(full_path, part_path); 2495673Saw148015 free(part_path); 2505673Saw148015 2515673Saw148015 /* now create this portion of the subdirectory tree */ 2525673Saw148015 if (fileset_mkdir(full_path, 0755) == -1) 2535673Saw148015 return (-1); 2545673Saw148015 2555673Saw148015 direntry = direntry->fse_dirnext; 2565673Saw148015 } 2575673Saw148015 return (0); 2585673Saw148015 } 2595673Saw148015 2605673Saw148015 /* 2615673Saw148015 * given a fileset entry, determines if the associated file 2625673Saw148015 * needs to be allocated or not, and if so does the allocation. 2635673Saw148015 */ 2645673Saw148015 static int 2655673Saw148015 fileset_alloc_file(filesetentry_t *entry) 2665673Saw148015 { 2675673Saw148015 char path[MAXPATHLEN]; 2685673Saw148015 char *buf; 2695673Saw148015 struct stat64 sb; 2705673Saw148015 char *pathtmp; 2715673Saw148015 off64_t seek; 2725673Saw148015 int fd; 2735673Saw148015 2745673Saw148015 *path = 0; 2756212Saw148015 (void) strcpy(path, avd_get_str(entry->fse_fileset->fs_path)); 2765673Saw148015 (void) strcat(path, "/"); 2776212Saw148015 (void) strcat(path, avd_get_str(entry->fse_fileset->fs_name)); 2785673Saw148015 pathtmp = fileset_resolvepath(entry); 2795673Saw148015 (void) strcat(path, pathtmp); 2805673Saw148015 2815673Saw148015 filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); 2825673Saw148015 2835673Saw148015 /* see if reusing and this file exists */ 2845673Saw148015 if ((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0)) { 2855673Saw148015 if ((fd = open64(path, O_RDWR)) < 0) { 2865673Saw148015 filebench_log(LOG_INFO, 2875673Saw148015 "Attempted but failed to Re-use file %s", 2885673Saw148015 path); 2895673Saw148015 return (-1); 2905673Saw148015 } 2915673Saw148015 2925673Saw148015 if (sb.st_size == (off64_t)entry->fse_size) { 2935673Saw148015 filebench_log(LOG_INFO, 2945673Saw148015 "Re-using file %s", path); 2955673Saw148015 2966212Saw148015 if (!avd_get_bool(entry->fse_fileset->fs_cached)) 2975673Saw148015 (void) fileset_freemem(fd, 2985673Saw148015 entry->fse_size); 2995673Saw148015 3005673Saw148015 entry->fse_flags |= FSE_EXISTS; 3015673Saw148015 (void) close(fd); 3025673Saw148015 return (0); 3035673Saw148015 3045673Saw148015 } else if (sb.st_size > (off64_t)entry->fse_size) { 3055673Saw148015 /* reuse, but too large */ 3065673Saw148015 filebench_log(LOG_INFO, 3075673Saw148015 "Truncating & re-using file %s", path); 3085673Saw148015 309*6613Sek110237 #ifdef HAVE_FTRUNCATE64 310*6613Sek110237 (void) ftruncate64(fd, (off64_t)entry->fse_size); 311*6613Sek110237 #else 312*6613Sek110237 (void) ftruncate(fd, (off_t)entry->fse_size); 313*6613Sek110237 #endif 3145673Saw148015 3156212Saw148015 if (!avd_get_bool(entry->fse_fileset->fs_cached)) 3165673Saw148015 (void) fileset_freemem(fd, 3175673Saw148015 entry->fse_size); 3185673Saw148015 3195673Saw148015 entry->fse_flags |= FSE_EXISTS; 3205673Saw148015 (void) close(fd); 3215673Saw148015 return (0); 3225673Saw148015 } 3235673Saw148015 } else { 3245673Saw148015 3255673Saw148015 /* No file or not reusing, so create */ 3265673Saw148015 if ((fd = open64(path, O_RDWR | O_CREAT, 0644)) < 0) { 3275673Saw148015 filebench_log(LOG_ERROR, 3285673Saw148015 "Failed to pre-allocate file %s: %s", 3295673Saw148015 path, strerror(errno)); 3305673Saw148015 3315673Saw148015 return (-1); 3325673Saw148015 } 3335673Saw148015 } 3345673Saw148015 3355673Saw148015 if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) 3365673Saw148015 return (-1); 3375673Saw148015 3385673Saw148015 entry->fse_flags |= FSE_EXISTS; 3395673Saw148015 3405673Saw148015 for (seek = 0; seek < entry->fse_size; ) { 3415673Saw148015 off64_t wsize; 3425673Saw148015 int ret = 0; 3435673Saw148015 3445673Saw148015 /* 3455673Saw148015 * Write FILE_ALLOC_BLOCK's worth, 3465673Saw148015 * except on last write 3475673Saw148015 */ 3485673Saw148015 wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK); 3495673Saw148015 3505673Saw148015 ret = write(fd, buf, wsize); 3515673Saw148015 if (ret != wsize) { 3525673Saw148015 filebench_log(LOG_ERROR, 3535673Saw148015 "Failed to pre-allocate file %s: %s", 3545673Saw148015 path, strerror(errno)); 3555673Saw148015 (void) close(fd); 3565673Saw148015 free(buf); 3575673Saw148015 return (-1); 3585673Saw148015 } 3595673Saw148015 seek += wsize; 3605673Saw148015 } 3615673Saw148015 3626212Saw148015 if (!avd_get_bool(entry->fse_fileset->fs_cached)) 3635673Saw148015 (void) fileset_freemem(fd, entry->fse_size); 3645673Saw148015 3655673Saw148015 (void) close(fd); 3665673Saw148015 3675673Saw148015 free(buf); 3685673Saw148015 3695673Saw148015 filebench_log(LOG_DEBUG_IMPL, 3706286Saw148015 "Pre-allocated file %s size %llu", 3716286Saw148015 path, (u_longlong_t)entry->fse_size); 3725673Saw148015 3735673Saw148015 return (0); 3745673Saw148015 } 3755673Saw148015 3765673Saw148015 /* 3775673Saw148015 * given a fileset entry, determines if the associated file 3785673Saw148015 * needs to be allocated or not, and if so does the allocation. 3795673Saw148015 */ 3805673Saw148015 static void * 3815673Saw148015 fileset_alloc_thread(filesetentry_t *entry) 3825673Saw148015 { 3835673Saw148015 if (fileset_alloc_file(entry) == -1) { 3845673Saw148015 (void) pthread_mutex_lock(¶lloc_lock); 3855673Saw148015 paralloc_count = -1; 3865673Saw148015 } else { 3875673Saw148015 (void) pthread_mutex_lock(¶lloc_lock); 3885673Saw148015 paralloc_count--; 3895673Saw148015 } 3905673Saw148015 3915673Saw148015 (void) pthread_cond_signal(¶lloc_cv); 3925673Saw148015 (void) pthread_mutex_unlock(¶lloc_lock); 3935673Saw148015 3945673Saw148015 pthread_exit(NULL); 3955673Saw148015 return (NULL); 3965673Saw148015 } 3975673Saw148015 3985184Sek110237 3995184Sek110237 /* 4005184Sek110237 * First creates the parent directories of the file using 4015184Sek110237 * fileset_mkdir(). Then Optionally sets the O_DSYNC flag 4025184Sek110237 * and opens the file with open64(). It unlocks the fileset 4035184Sek110237 * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags 4045184Sek110237 * as requested, and returns the file descriptor integer 4055184Sek110237 * for the opened file. 4065184Sek110237 */ 4075184Sek110237 int 4085184Sek110237 fileset_openfile(fileset_t *fileset, 4095184Sek110237 filesetentry_t *entry, int flag, int mode, int attrs) 4105184Sek110237 { 4115184Sek110237 char path[MAXPATHLEN]; 4125184Sek110237 char dir[MAXPATHLEN]; 4135184Sek110237 char *pathtmp; 4145184Sek110237 struct stat64 sb; 4155184Sek110237 int fd; 4165184Sek110237 int open_attrs = 0; 4175184Sek110237 4185184Sek110237 *path = 0; 4196212Saw148015 (void) strcpy(path, avd_get_str(fileset->fs_path)); 4205184Sek110237 (void) strcat(path, "/"); 4216212Saw148015 (void) strcat(path, avd_get_str(fileset->fs_name)); 4225184Sek110237 pathtmp = fileset_resolvepath(entry); 4235184Sek110237 (void) strcat(path, pathtmp); 4245184Sek110237 (void) strcpy(dir, path); 4255184Sek110237 free(pathtmp); 4265184Sek110237 (void) trunc_dirname(dir); 4275184Sek110237 4285184Sek110237 /* If we are going to create a file, create the parent dirs */ 4295184Sek110237 if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) { 4305184Sek110237 if (fileset_mkdir(dir, 0755) == -1) 4315184Sek110237 return (-1); 4325184Sek110237 } 4335184Sek110237 4345184Sek110237 if (flag & O_CREAT) 4355184Sek110237 entry->fse_flags |= FSE_EXISTS; 4365184Sek110237 4375184Sek110237 if (attrs & FLOW_ATTR_DSYNC) { 4385184Sek110237 #ifdef sun 4395184Sek110237 open_attrs |= O_DSYNC; 4405184Sek110237 #else 4415184Sek110237 open_attrs |= O_FSYNC; 4425184Sek110237 #endif 4435184Sek110237 } 4445184Sek110237 4455184Sek110237 if ((fd = open64(path, flag | open_attrs, mode)) < 0) { 4465184Sek110237 filebench_log(LOG_ERROR, 4475184Sek110237 "Failed to open file %s: %s", 4485184Sek110237 path, strerror(errno)); 4495184Sek110237 (void) ipc_mutex_unlock(&entry->fse_lock); 4505184Sek110237 return (-1); 4515184Sek110237 } 4525184Sek110237 (void) ipc_mutex_unlock(&entry->fse_lock); 4535184Sek110237 4545184Sek110237 #ifdef sun 4555184Sek110237 if (attrs & FLOW_ATTR_DIRECTIO) 4565184Sek110237 (void) directio(fd, DIRECTIO_ON); 4575184Sek110237 else 4585184Sek110237 (void) directio(fd, DIRECTIO_OFF); 4595184Sek110237 #endif 4605184Sek110237 4615184Sek110237 return (fd); 4625184Sek110237 } 4635184Sek110237 4645184Sek110237 4655184Sek110237 /* 4665184Sek110237 * Selects a fileset entry from a fileset. If the 4675184Sek110237 * FILESET_PICKDIR flag is set it will pick a directory 4685184Sek110237 * entry, otherwise a file entry. The FILESET_PICKRESET 4695184Sek110237 * flag will cause it to reset the free list to the 4705184Sek110237 * overall list (file or directory). The FILESET_PICKUNIQUE 4715184Sek110237 * flag will take an entry off of one of the free (unused) 4725184Sek110237 * lists (file or directory), otherwise the entry will be 4735184Sek110237 * picked off of one of the rotor lists (file or directory). 4745184Sek110237 * The FILESET_PICKEXISTS will insure that only extant 4755184Sek110237 * (FSE_EXISTS) state files are selected, while 4765184Sek110237 * FILESET_PICKNOEXIST insures that only non extant 4775184Sek110237 * (not FSE_EXISTS) state files are selected. 4786391Saw148015 * Note that the selected fileset entry (file) is returned 4796391Saw148015 * with its fse_lock field locked. 4805184Sek110237 */ 4815184Sek110237 filesetentry_t * 4825184Sek110237 fileset_pick(fileset_t *fileset, int flags, int tid) 4835184Sek110237 { 4845184Sek110237 filesetentry_t *entry = NULL; 4855184Sek110237 filesetentry_t *first = NULL; 4865184Sek110237 4876391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 4885184Sek110237 4895184Sek110237 while (entry == NULL) { 4905184Sek110237 4915184Sek110237 if ((flags & FILESET_PICKDIR) && (flags & FILESET_PICKRESET)) { 4925184Sek110237 entry = fileset->fs_dirlist; 4935184Sek110237 while (entry) { 4945184Sek110237 entry->fse_flags |= FSE_FREE; 4955184Sek110237 entry = entry->fse_dirnext; 4965184Sek110237 } 4975184Sek110237 fileset->fs_dirfree = fileset->fs_dirlist; 4985184Sek110237 } 4995184Sek110237 5005184Sek110237 if (!(flags & FILESET_PICKDIR) && (flags & FILESET_PICKRESET)) { 5015184Sek110237 entry = fileset->fs_filelist; 5025184Sek110237 while (entry) { 5035184Sek110237 entry->fse_flags |= FSE_FREE; 5045184Sek110237 entry = entry->fse_filenext; 5055184Sek110237 } 5065184Sek110237 fileset->fs_filefree = fileset->fs_filelist; 5075184Sek110237 } 5085184Sek110237 5095184Sek110237 if (flags & FILESET_PICKUNIQUE) { 5105184Sek110237 if (flags & FILESET_PICKDIR) { 5115184Sek110237 entry = fileset->fs_dirfree; 5125184Sek110237 if (entry == NULL) 5135184Sek110237 goto empty; 5145184Sek110237 fileset->fs_dirfree = entry->fse_dirnext; 5155184Sek110237 } else { 5165184Sek110237 entry = fileset->fs_filefree; 5175184Sek110237 if (entry == NULL) 5185184Sek110237 goto empty; 5195184Sek110237 fileset->fs_filefree = entry->fse_filenext; 5205184Sek110237 } 5215184Sek110237 entry->fse_flags &= ~FSE_FREE; 5225184Sek110237 } else { 5235184Sek110237 if (flags & FILESET_PICKDIR) { 5245184Sek110237 entry = fileset->fs_dirrotor; 5255184Sek110237 if (entry == NULL) 5265184Sek110237 fileset->fs_dirrotor = 5275184Sek110237 entry = fileset->fs_dirlist; 5285184Sek110237 fileset->fs_dirrotor = entry->fse_dirnext; 5295184Sek110237 } else { 5305184Sek110237 entry = fileset->fs_filerotor[tid]; 5315184Sek110237 if (entry == NULL) 5325184Sek110237 fileset->fs_filerotor[tid] = 5335184Sek110237 entry = fileset->fs_filelist; 5345184Sek110237 fileset->fs_filerotor[tid] = 5355184Sek110237 entry->fse_filenext; 5365184Sek110237 } 5375184Sek110237 } 5385184Sek110237 5395184Sek110237 if (first == entry) 5405184Sek110237 goto empty; 5415184Sek110237 5425184Sek110237 if (first == NULL) 5435184Sek110237 first = entry; 5445184Sek110237 5455184Sek110237 /* Return locked entry */ 5465184Sek110237 (void) ipc_mutex_lock(&entry->fse_lock); 5475184Sek110237 5485184Sek110237 /* If we ask for an existing file, go round again */ 5495184Sek110237 if ((flags & FILESET_PICKEXISTS) && 5505184Sek110237 !(entry->fse_flags & FSE_EXISTS)) { 5515184Sek110237 (void) ipc_mutex_unlock(&entry->fse_lock); 5525184Sek110237 entry = NULL; 5535184Sek110237 } 5545184Sek110237 5555184Sek110237 /* If we ask for not an existing file, go round again */ 5565184Sek110237 if ((flags & FILESET_PICKNOEXIST) && 5575184Sek110237 (entry->fse_flags & FSE_EXISTS)) { 5585184Sek110237 (void) ipc_mutex_unlock(&entry->fse_lock); 5595184Sek110237 entry = NULL; 5605184Sek110237 } 5615184Sek110237 } 5625184Sek110237 5636391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 5645184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path); 5655184Sek110237 return (entry); 5665184Sek110237 5675184Sek110237 empty: 5686391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 5695184Sek110237 return (NULL); 5705184Sek110237 } 5715184Sek110237 5725184Sek110237 /* 5735184Sek110237 * Given a fileset "fileset", create the associated files as 5745184Sek110237 * specified in the attributes of the fileset. The fileset is 5756212Saw148015 * rooted in a directory whose pathname is in fileset_path. If the 5765184Sek110237 * directory exists, meaning that there is already a fileset, 5776212Saw148015 * and the fileset_reuse attribute is false, then remove it and all 5785184Sek110237 * its contained files and subdirectories. Next, the routine 5795184Sek110237 * creates a root directory for the fileset. All the file type 5805184Sek110237 * filesetentries are cycled through creating as needed 5815184Sek110237 * their containing subdirectory trees in the filesystem and 5826212Saw148015 * creating actual files for fileset_preallocpercent of them. The 5835184Sek110237 * created files are filled with fse_size bytes of unitialized 5845184Sek110237 * data. The routine returns -1 on errors, 0 on success. 5855184Sek110237 */ 5865184Sek110237 static int 5875184Sek110237 fileset_create(fileset_t *fileset) 5885184Sek110237 { 5895184Sek110237 filesetentry_t *entry; 5905184Sek110237 char path[MAXPATHLEN]; 5915184Sek110237 struct stat64 sb; 5925184Sek110237 int pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET; 5935184Sek110237 hrtime_t start = gethrtime(); 5946212Saw148015 char *fileset_path; 5956212Saw148015 char *fileset_name; 5966212Saw148015 int randno; 5975184Sek110237 int preallocated = 0; 5985184Sek110237 int reusing = 0; 5995184Sek110237 6006212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 6015673Saw148015 filebench_log(LOG_ERROR, "%s path not set", 6025673Saw148015 fileset_entity_name(fileset)); 6035184Sek110237 return (-1); 6045184Sek110237 } 6055184Sek110237 6066212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 6076212Saw148015 filebench_log(LOG_ERROR, "%s name not set", 6086212Saw148015 fileset_entity_name(fileset)); 6096212Saw148015 return (-1); 6106212Saw148015 } 6116212Saw148015 6125673Saw148015 #ifdef HAVE_RAW_SUPPORT 6135673Saw148015 /* treat raw device as special case */ 6145673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 6155673Saw148015 return (0); 6165673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 6175673Saw148015 6185184Sek110237 /* XXX Add check to see if there is enough space */ 6195184Sek110237 6205184Sek110237 /* Remove existing */ 6216212Saw148015 (void) strcpy(path, fileset_path); 6225184Sek110237 (void) strcat(path, "/"); 6236212Saw148015 (void) strcat(path, fileset_name); 6245184Sek110237 if ((stat64(path, &sb) == 0) && (strlen(path) > 3) && 6256212Saw148015 (strlen(avd_get_str(fileset->fs_path)) > 2)) { 6266212Saw148015 if (!avd_get_bool(fileset->fs_reuse)) { 6275184Sek110237 char cmd[MAXPATHLEN]; 6285184Sek110237 6295184Sek110237 (void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path); 6305184Sek110237 (void) system(cmd); 6315184Sek110237 filebench_log(LOG_VERBOSE, 6326286Saw148015 "Removed any existing %s %s in %llu seconds", 6336212Saw148015 fileset_entity_name(fileset), fileset_name, 6346286Saw148015 (u_longlong_t)(((gethrtime() - start) / 6356286Saw148015 1000000000) + 1)); 6365184Sek110237 } else { 6375184Sek110237 /* we are re-using */ 6385184Sek110237 reusing = 1; 639*6613Sek110237 filebench_log(LOG_VERBOSE, "Re-using %s %s.", 640*6613Sek110237 fileset_entity_name(fileset), fileset_name); 6415184Sek110237 } 6425184Sek110237 } 6435184Sek110237 (void) mkdir(path, 0755); 6445184Sek110237 6455673Saw148015 /* make the filesets directory tree */ 6465673Saw148015 if (fileset_create_subdirs(fileset, path) == -1) 6475673Saw148015 return (-1); 6485673Saw148015 6495184Sek110237 start = gethrtime(); 6505184Sek110237 6515673Saw148015 filebench_log(LOG_VERBOSE, "Creating %s %s...", 6526212Saw148015 fileset_entity_name(fileset), fileset_name); 6535673Saw148015 6546212Saw148015 if (!avd_get_bool(fileset->fs_prealloc)) 6555673Saw148015 goto exit; 6565184Sek110237 6576212Saw148015 randno = ((RAND_MAX * (100 6586212Saw148015 - avd_get_int(fileset->fs_preallocpercent))) / 100); 6596212Saw148015 6605184Sek110237 while (entry = fileset_pick(fileset, pickflags, 0)) { 6615673Saw148015 pthread_t tid; 6625184Sek110237 6635184Sek110237 pickflags = FILESET_PICKUNIQUE; 6645184Sek110237 6655184Sek110237 entry->fse_flags &= ~FSE_EXISTS; 6665184Sek110237 6675673Saw148015 /* entry doesn't need to be locked during initialization */ 6685673Saw148015 (void) ipc_mutex_unlock(&entry->fse_lock); 6695673Saw148015 6705673Saw148015 if (rand() < randno) 6715184Sek110237 continue; 6725184Sek110237 6735184Sek110237 preallocated++; 6745184Sek110237 6755673Saw148015 if (reusing) 6765673Saw148015 entry->fse_flags |= FSE_REUSING; 6775673Saw148015 else 6785673Saw148015 entry->fse_flags &= (~FSE_REUSING); 6795673Saw148015 6806212Saw148015 if (avd_get_bool(fileset->fs_paralloc)) { 6815184Sek110237 6825673Saw148015 /* fire off a separate allocation thread */ 6835673Saw148015 (void) pthread_mutex_lock(¶lloc_lock); 6845673Saw148015 while (paralloc_count >= MAX_PARALLOC_THREADS) { 6855673Saw148015 (void) pthread_cond_wait( 6865673Saw148015 ¶lloc_cv, ¶lloc_lock); 6875673Saw148015 } 6885673Saw148015 6895673Saw148015 if (paralloc_count < 0) { 6905673Saw148015 (void) pthread_mutex_unlock(¶lloc_lock); 6915184Sek110237 return (-1); 6925184Sek110237 } 6935184Sek110237 6945673Saw148015 paralloc_count++; 6955673Saw148015 (void) pthread_mutex_unlock(¶lloc_lock); 6965184Sek110237 6975673Saw148015 if (pthread_create(&tid, NULL, 6985673Saw148015 (void *(*)(void*))fileset_alloc_thread, 6995673Saw148015 entry) != 0) { 7005184Sek110237 filebench_log(LOG_ERROR, 7015673Saw148015 "File prealloc thread create failed"); 7025673Saw148015 filebench_shutdown(1); 7035184Sek110237 } 7045184Sek110237 7055673Saw148015 } else { 7065673Saw148015 if (fileset_alloc_file(entry) == -1) 7075673Saw148015 return (-1); 7085673Saw148015 } 7095673Saw148015 } 7105184Sek110237 7115673Saw148015 exit: 7125184Sek110237 filebench_log(LOG_VERBOSE, 7136286Saw148015 "Preallocated %d of %llu of %s %s in %llu seconds", 7145184Sek110237 preallocated, 7156286Saw148015 (u_longlong_t)fileset->fs_constentries, 7166212Saw148015 fileset_entity_name(fileset), fileset_name, 7176286Saw148015 (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1)); 7185184Sek110237 7195184Sek110237 return (0); 7205184Sek110237 } 7215184Sek110237 7225184Sek110237 /* 7235184Sek110237 * Adds an entry to the fileset's file list. Single threaded so 7245184Sek110237 * no locking needed. 7255184Sek110237 */ 7265184Sek110237 static void 7275184Sek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry) 7285184Sek110237 { 7295184Sek110237 if (fileset->fs_filelist == NULL) { 7305184Sek110237 fileset->fs_filelist = entry; 7315184Sek110237 entry->fse_filenext = NULL; 7325184Sek110237 } else { 7335184Sek110237 entry->fse_filenext = fileset->fs_filelist; 7345184Sek110237 fileset->fs_filelist = entry; 7355184Sek110237 } 7365184Sek110237 } 7375184Sek110237 7385184Sek110237 /* 7395184Sek110237 * Adds an entry to the fileset's directory list. Single 7405184Sek110237 * threaded so no locking needed. 7415184Sek110237 */ 7425184Sek110237 static void 7435184Sek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) 7445184Sek110237 { 7455184Sek110237 if (fileset->fs_dirlist == NULL) { 7465184Sek110237 fileset->fs_dirlist = entry; 7475184Sek110237 entry->fse_dirnext = NULL; 7485184Sek110237 } else { 7495184Sek110237 entry->fse_dirnext = fileset->fs_dirlist; 7505184Sek110237 fileset->fs_dirlist = entry; 7515184Sek110237 } 7525184Sek110237 } 7535184Sek110237 7545184Sek110237 /* 7555184Sek110237 * Obtaines a filesetentry entity for a file to be placed in a 7565184Sek110237 * (sub)directory of a fileset. The size of the file may be 7576212Saw148015 * specified by fileset_meansize, or calculated from a gamma 7586212Saw148015 * distribution of parameter fileset_sizegamma and of mean size 7596212Saw148015 * fileset_meansize. The filesetentry entity is placed on the file 7605184Sek110237 * list in the specified parent filesetentry entity, which may 7615184Sek110237 * be a directory filesetentry, or the root filesetentry in the 7625184Sek110237 * fileset. It is also placed on the fileset's list of all 7635184Sek110237 * contained files. Returns 0 if successful or -1 if ipc memory 7645184Sek110237 * for the path string cannot be allocated. 7655184Sek110237 */ 7665184Sek110237 static int 7675184Sek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) 7685184Sek110237 { 7695184Sek110237 char tmpname[16]; 7705184Sek110237 filesetentry_t *entry; 7715184Sek110237 double drand; 7725184Sek110237 7735184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 7745184Sek110237 == NULL) { 7755184Sek110237 filebench_log(LOG_ERROR, 7765184Sek110237 "fileset_populate_file: Can't malloc filesetentry"); 7775184Sek110237 return (-1); 7785184Sek110237 } 7795184Sek110237 7805184Sek110237 (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); 7815184Sek110237 entry->fse_parent = parent; 7825184Sek110237 entry->fse_fileset = fileset; 7835184Sek110237 entry->fse_flags |= FSE_FREE; 7845184Sek110237 fileset_insfilelist(fileset, entry); 7855184Sek110237 7865184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 7875184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 7885184Sek110237 filebench_log(LOG_ERROR, 7895184Sek110237 "fileset_populate_file: Can't alloc path string"); 7905184Sek110237 return (-1); 7915184Sek110237 } 7925184Sek110237 7936212Saw148015 /* see if random variable was supplied for file size */ 7946212Saw148015 if (fileset->fs_meansize == -1) { 7956212Saw148015 entry->fse_size = (off64_t)avd_get_int(fileset->fs_size); 7966212Saw148015 } else { 7976212Saw148015 double gamma; 7985184Sek110237 7996212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 8006212Saw148015 if (gamma > 0) { 8016212Saw148015 drand = gamma_dist_knuth(gamma, 8026212Saw148015 fileset->fs_meansize / gamma); 8036212Saw148015 entry->fse_size = (off64_t)drand; 8046212Saw148015 } else { 8056212Saw148015 entry->fse_size = (off64_t)fileset->fs_meansize; 8066212Saw148015 } 8075184Sek110237 } 8085184Sek110237 8095184Sek110237 fileset->fs_bytes += entry->fse_size; 8105184Sek110237 8115184Sek110237 fileset->fs_realfiles++; 8125184Sek110237 return (0); 8135184Sek110237 } 8145184Sek110237 8155184Sek110237 /* 8165184Sek110237 * Creates a directory node in a fileset, by obtaining a 8175184Sek110237 * filesetentry entity for the node and initializing it 8185184Sek110237 * according to parameters of the fileset. It determines a 8195184Sek110237 * directory tree depth and directory width, optionally using 8205184Sek110237 * a gamma distribution. If its calculated depth is less then 8215184Sek110237 * its actual depth in the directory tree, it becomes a leaf 8225184Sek110237 * node and files itself with "width" number of file type 8235184Sek110237 * filesetentries, otherwise it files itself with "width" 8245184Sek110237 * number of directory type filesetentries, using recursive 8255184Sek110237 * calls to fileset_populate_subdir. The end result of the 8265184Sek110237 * initial call to this routine is a tree of directories of 8275184Sek110237 * random width and varying depth with sufficient leaf 8285184Sek110237 * directories to contain all required files. 8295184Sek110237 * Returns 0 on success. Returns -1 if ipc path string memory 8305184Sek110237 * cannot be allocated and returns an error code (currently 8315184Sek110237 * also -1) from calls to fileset_populate_file or recursive 8325184Sek110237 * calls to fileset_populate_subdir. 8335184Sek110237 */ 8345184Sek110237 static int 8355184Sek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, 8365184Sek110237 int serial, double depth) 8375184Sek110237 { 8386212Saw148015 double randepth, drand, ranwidth; 8395184Sek110237 int isleaf = 0; 8405184Sek110237 char tmpname[16]; 8415184Sek110237 filesetentry_t *entry; 8425184Sek110237 int i; 8435184Sek110237 8445184Sek110237 depth += 1; 8455184Sek110237 8465184Sek110237 /* Create dir node */ 8475184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) 8485184Sek110237 == NULL) { 8495184Sek110237 filebench_log(LOG_ERROR, 8505184Sek110237 "fileset_populate_subdir: Can't malloc filesetentry"); 8515184Sek110237 return (-1); 8525184Sek110237 } 8535184Sek110237 8545184Sek110237 (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); 8555184Sek110237 8565184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); 8575184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { 8585184Sek110237 filebench_log(LOG_ERROR, 8595184Sek110237 "fileset_populate_subdir: Can't alloc path string"); 8605184Sek110237 return (-1); 8615184Sek110237 } 8625184Sek110237 8635184Sek110237 entry->fse_parent = parent; 8645184Sek110237 entry->fse_flags |= FSE_DIR | FSE_FREE; 8655184Sek110237 fileset_insdirlist(fileset, entry); 8665184Sek110237 8676212Saw148015 if (fileset->fs_dirdepthrv) { 8686212Saw148015 randepth = (int)avd_get_int(fileset->fs_dirdepthrv); 8695184Sek110237 } else { 8706212Saw148015 double gamma; 8716212Saw148015 8726212Saw148015 gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0; 8736212Saw148015 if (gamma > 0) { 8746212Saw148015 drand = gamma_dist_knuth(gamma, 8756212Saw148015 fileset->fs_meandepth / gamma); 8766212Saw148015 randepth = (int)drand; 8776212Saw148015 } else { 8786212Saw148015 randepth = (int)fileset->fs_meandepth; 8796212Saw148015 } 8805184Sek110237 } 8815184Sek110237 8826212Saw148015 if (fileset->fs_meanwidth == -1) { 8836212Saw148015 ranwidth = avd_get_dbl(fileset->fs_dirwidth); 8846212Saw148015 } else { 8856212Saw148015 double gamma; 8865184Sek110237 8876212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; 8886212Saw148015 if (gamma > 0) { 8896212Saw148015 drand = gamma_dist_knuth(gamma, 8906212Saw148015 fileset->fs_meanwidth / gamma); 8916212Saw148015 ranwidth = drand; 8926212Saw148015 } else { 8936212Saw148015 ranwidth = fileset->fs_meanwidth; 8946212Saw148015 } 8955184Sek110237 } 8965184Sek110237 8975184Sek110237 if (randepth == 0) 8985184Sek110237 randepth = 1; 8995184Sek110237 if (ranwidth == 0) 9005184Sek110237 ranwidth = 1; 9015184Sek110237 if (depth >= randepth) 9025184Sek110237 isleaf = 1; 9035184Sek110237 9045184Sek110237 /* 9055184Sek110237 * Create directory of random width according to distribution, or 9065184Sek110237 * if root directory, continue until #files required 9075184Sek110237 */ 9086212Saw148015 for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && 9096212Saw148015 (fileset->fs_realfiles < fileset->fs_constentries); 9106212Saw148015 i++) { 9115184Sek110237 int ret = 0; 9125184Sek110237 9135184Sek110237 if (parent && isleaf) 9145184Sek110237 ret = fileset_populate_file(fileset, entry, i); 9155184Sek110237 else 9165184Sek110237 ret = fileset_populate_subdir(fileset, entry, i, depth); 9175184Sek110237 9185184Sek110237 if (ret != 0) 9195184Sek110237 return (ret); 9205184Sek110237 } 9215184Sek110237 return (0); 9225184Sek110237 } 9235184Sek110237 9245184Sek110237 /* 9255184Sek110237 * Populates a fileset with files and subdirectory entries. Uses 9266212Saw148015 * the supplied fileset_dirwidth and fileset_entries (number of files) to 9276212Saw148015 * calculate the required fileset_meandepth (of subdirectories) and 9286212Saw148015 * initialize the fileset_meanwidth and fileset_meansize variables. Then 9295184Sek110237 * calls fileset_populate_subdir() to do the recursive 9305184Sek110237 * subdirectory entry creation and leaf file entry creation. All 9315184Sek110237 * of the above is skipped if the fileset has already been 9325184Sek110237 * populated. Returns 0 on success, or an error code from the 9335184Sek110237 * call to fileset_populate_subdir if that call fails. 9345184Sek110237 */ 9355184Sek110237 static int 9365184Sek110237 fileset_populate(fileset_t *fileset) 9375184Sek110237 { 9386212Saw148015 int entries = (int)avd_get_int(fileset->fs_entries); 9396212Saw148015 int meandirwidth; 9405184Sek110237 int ret; 9415184Sek110237 9425184Sek110237 /* Skip if already populated */ 9435184Sek110237 if (fileset->fs_bytes > 0) 9445184Sek110237 goto exists; 9455184Sek110237 9465673Saw148015 #ifdef HAVE_RAW_SUPPORT 9475673Saw148015 /* check for raw device */ 9485673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) 9495673Saw148015 return (0); 9505673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 9515673Saw148015 9526212Saw148015 /* save value of entries obtained for later, in case it was random */ 9536212Saw148015 fileset->fs_constentries = entries; 9546212Saw148015 9556212Saw148015 /* is dirwidth a random variable? */ 9566212Saw148015 if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { 9576212Saw148015 meandirwidth = 9586212Saw148015 (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean; 9596212Saw148015 fileset->fs_meanwidth = -1; 9606212Saw148015 } else { 9616212Saw148015 meandirwidth = (int)avd_get_int(fileset->fs_dirwidth); 9626212Saw148015 fileset->fs_meanwidth = (double)meandirwidth; 9636212Saw148015 } 9646212Saw148015 9655184Sek110237 /* 9665184Sek110237 * Input params are: 9675184Sek110237 * # of files 9685184Sek110237 * ave # of files per dir 9695184Sek110237 * max size of dir 9705184Sek110237 * # ave size of file 9715184Sek110237 * max size of file 9725184Sek110237 */ 9736212Saw148015 fileset->fs_meandepth = log(entries) / log(meandirwidth); 9746212Saw148015 9756212Saw148015 /* Has a random variable been supplied for dirdepth? */ 9766212Saw148015 if (fileset->fs_dirdepthrv) { 9776212Saw148015 /* yes, so set the random variable's mean value to meandepth */ 9786212Saw148015 fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean = 9796212Saw148015 fileset->fs_meandepth; 9806212Saw148015 } 9816212Saw148015 9826212Saw148015 /* test for random size variable */ 9836212Saw148015 if (AVD_IS_RANDOM(fileset->fs_size)) 9846212Saw148015 fileset->fs_meansize = -1; 9856212Saw148015 else 9866212Saw148015 fileset->fs_meansize = avd_get_int(fileset->fs_size); 9875184Sek110237 9885184Sek110237 if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0) 9895184Sek110237 return (ret); 9905184Sek110237 9915184Sek110237 9925184Sek110237 exists: 9935673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 9946286Saw148015 filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu", 9956212Saw148015 avd_get_str(fileset->fs_name), 9966286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 9975673Saw148015 } else { 9986286Saw148015 filebench_log(LOG_VERBOSE, "Fileset %s: %d files, " 9996286Saw148015 "avg dir = %d, avg depth = %.1lf, mbytes=%llu", 10006212Saw148015 avd_get_str(fileset->fs_name), entries, 10016212Saw148015 meandirwidth, 10025673Saw148015 fileset->fs_meandepth, 10036286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); 10045673Saw148015 } 10055184Sek110237 return (0); 10065184Sek110237 } 10075184Sek110237 10085184Sek110237 /* 10096212Saw148015 * Allocates a fileset instance, initializes fileset_dirgamma and 10106212Saw148015 * fileset_sizegamma default values, and sets the fileset name to the 10115184Sek110237 * supplied name string. Puts the allocated fileset on the 10125184Sek110237 * master fileset list and returns a pointer to it. 10135184Sek110237 */ 10145184Sek110237 fileset_t * 10156212Saw148015 fileset_define(avd_t name) 10165184Sek110237 { 10175184Sek110237 fileset_t *fileset; 10185184Sek110237 10195184Sek110237 if (name == NULL) 10205184Sek110237 return (NULL); 10215184Sek110237 10225184Sek110237 if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) { 10235184Sek110237 filebench_log(LOG_ERROR, 10245184Sek110237 "fileset_define: Can't malloc fileset"); 10255184Sek110237 return (NULL); 10265184Sek110237 } 10275184Sek110237 10286212Saw148015 filebench_log(LOG_DEBUG_IMPL, 10296212Saw148015 "Defining file %s", avd_get_str(name)); 10305184Sek110237 10316391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 10325184Sek110237 10336212Saw148015 fileset->fs_dirgamma = avd_int_alloc(1500); 10346212Saw148015 fileset->fs_sizegamma = avd_int_alloc(1500); 10355184Sek110237 10365184Sek110237 /* Add fileset to global list */ 10376391Saw148015 if (filebench_shm->shm_filesetlist == NULL) { 10386391Saw148015 filebench_shm->shm_filesetlist = fileset; 10395184Sek110237 fileset->fs_next = NULL; 10405184Sek110237 } else { 10416391Saw148015 fileset->fs_next = filebench_shm->shm_filesetlist; 10426391Saw148015 filebench_shm->shm_filesetlist = fileset; 10435184Sek110237 } 10445184Sek110237 10456391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 10465184Sek110237 10476212Saw148015 fileset->fs_name = name; 10485184Sek110237 10495184Sek110237 return (fileset); 10505184Sek110237 } 10515184Sek110237 10525184Sek110237 /* 10535184Sek110237 * If supplied with a pointer to a fileset and the fileset's 10546212Saw148015 * fileset_prealloc flag is set, calls fileset_populate() to populate 10555184Sek110237 * the fileset with filesetentries, then calls fileset_create() 10565184Sek110237 * to make actual directories and files for the filesetentries. 10575184Sek110237 * Otherwise, it applies fileset_populate() and fileset_create() 10585184Sek110237 * to all the filesets on the master fileset list. It always 10595184Sek110237 * returns zero (0) if one fileset is populated / created, 10605184Sek110237 * otherwise it returns the sum of returned values from 10615184Sek110237 * fileset_create() and fileset_populate(), which 10625184Sek110237 * will be a negative one (-1) times the number of 10635184Sek110237 * fileset_create() calls which failed. 10645184Sek110237 */ 10655184Sek110237 int 10665184Sek110237 fileset_createset(fileset_t *fileset) 10675184Sek110237 { 10685184Sek110237 fileset_t *list; 10695184Sek110237 int ret = 0; 10705184Sek110237 10715673Saw148015 /* set up for possible parallel allocate */ 10725673Saw148015 paralloc_count = 0; 10735673Saw148015 10746212Saw148015 if (fileset && avd_get_bool(fileset->fs_prealloc)) { 10755673Saw148015 10766305Saw148015 /* check for raw files */ 10776305Saw148015 if (fileset_checkraw(fileset)) { 10786305Saw148015 filebench_log(LOG_INFO, 10796305Saw148015 "file %s/%s is a RAW device", 10806305Saw148015 avd_get_str(fileset->fs_path), 10816305Saw148015 avd_get_str(fileset->fs_name)); 10826305Saw148015 return (0); 10836305Saw148015 } 10846305Saw148015 10855673Saw148015 filebench_log(LOG_INFO, 10865673Saw148015 "creating/pre-allocating %s %s", 10876212Saw148015 fileset_entity_name(fileset), 10886212Saw148015 avd_get_str(fileset->fs_name)); 10895673Saw148015 10905184Sek110237 if ((ret = fileset_populate(fileset)) != 0) 10915184Sek110237 return (ret); 10925673Saw148015 10935673Saw148015 if ((ret = fileset_create(fileset)) != 0) 10945673Saw148015 return (ret); 10955673Saw148015 } else { 10965673Saw148015 10975673Saw148015 filebench_log(LOG_INFO, 10985673Saw148015 "Creating/pre-allocating files and filesets"); 10995673Saw148015 11006391Saw148015 list = filebench_shm->shm_filesetlist; 11015673Saw148015 while (list) { 11026305Saw148015 /* check for raw files */ 11036305Saw148015 if (fileset_checkraw(list)) { 11046305Saw148015 filebench_log(LOG_INFO, 11056305Saw148015 "file %s/%s is a RAW device", 11066305Saw148015 avd_get_str(list->fs_path), 11076305Saw148015 avd_get_str(list->fs_name)); 11086305Saw148015 list = list->fs_next; 11096305Saw148015 continue; 11106305Saw148015 } 11116305Saw148015 11125673Saw148015 if ((ret = fileset_populate(list)) != 0) 11135673Saw148015 return (ret); 11145673Saw148015 if ((ret = fileset_create(list)) != 0) 11155673Saw148015 return (ret); 11165673Saw148015 list = list->fs_next; 11175673Saw148015 } 11185184Sek110237 } 11195184Sek110237 11205673Saw148015 /* wait for allocation threads to finish */ 11215673Saw148015 filebench_log(LOG_INFO, 11225673Saw148015 "waiting for fileset pre-allocation to finish"); 11235184Sek110237 11245673Saw148015 (void) pthread_mutex_lock(¶lloc_lock); 11255673Saw148015 while (paralloc_count > 0) 11265673Saw148015 (void) pthread_cond_wait(¶lloc_cv, ¶lloc_lock); 11275673Saw148015 (void) pthread_mutex_unlock(¶lloc_lock); 11285673Saw148015 11295673Saw148015 if (paralloc_count < 0) 11305673Saw148015 return (-1); 11315673Saw148015 11325673Saw148015 return (0); 11335184Sek110237 } 11345184Sek110237 11355184Sek110237 /* 11365184Sek110237 * Searches through the master fileset list for the named fileset. 11375184Sek110237 * If found, returns pointer to same, otherwise returns NULL. 11385184Sek110237 */ 11395184Sek110237 fileset_t * 11405184Sek110237 fileset_find(char *name) 11415184Sek110237 { 11426391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 11435184Sek110237 11446391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 11455184Sek110237 11465184Sek110237 while (fileset) { 11476212Saw148015 if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) { 11486391Saw148015 (void) ipc_mutex_unlock( 11496391Saw148015 &filebench_shm->shm_fileset_lock); 11505184Sek110237 return (fileset); 11515184Sek110237 } 11525184Sek110237 fileset = fileset->fs_next; 11535184Sek110237 } 11546391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 11555184Sek110237 11565184Sek110237 return (NULL); 11575184Sek110237 } 11585673Saw148015 11595673Saw148015 /* 11605673Saw148015 * Iterates over all the file sets in the filesetlist, 11615673Saw148015 * executing the supplied command "*cmd()" on them. Also 11625673Saw148015 * indicates to the executed command if it is the first 11635673Saw148015 * time the command has been executed since the current 11645673Saw148015 * call to fileset_iter. 11655673Saw148015 */ 11665673Saw148015 void 11675673Saw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first)) 11685673Saw148015 { 11696391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist; 11705673Saw148015 int count = 0; 11715673Saw148015 11726391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); 11735673Saw148015 11745673Saw148015 while (fileset) { 11755673Saw148015 cmd(fileset, count == 0); 11765673Saw148015 fileset = fileset->fs_next; 11775673Saw148015 count++; 11785673Saw148015 } 11795673Saw148015 11806391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); 11815673Saw148015 } 11825673Saw148015 11835673Saw148015 /* 11845673Saw148015 * Prints information to the filebench log about the file 11855673Saw148015 * object. Also prints a header on the first call. 11865673Saw148015 */ 11875673Saw148015 int 11885673Saw148015 fileset_print(fileset_t *fileset, int first) 11895673Saw148015 { 11906212Saw148015 int pathlength; 11916212Saw148015 char *fileset_path; 11926212Saw148015 char *fileset_name; 11936212Saw148015 static char pad[] = " "; /* 30 spaces */ 11946212Saw148015 11956212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { 11966212Saw148015 filebench_log(LOG_ERROR, "%s path not set", 11976212Saw148015 fileset_entity_name(fileset)); 11986212Saw148015 return (-1); 11996212Saw148015 } 12006212Saw148015 12016212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { 12026212Saw148015 filebench_log(LOG_ERROR, "%s name not set", 12036212Saw148015 fileset_entity_name(fileset)); 12046212Saw148015 return (-1); 12056212Saw148015 } 12066212Saw148015 12076212Saw148015 pathlength = strlen(fileset_path) + strlen(fileset_name); 12085673Saw148015 12095673Saw148015 if (pathlength > 29) 12105673Saw148015 pathlength = 29; 12115673Saw148015 12125673Saw148015 if (first) { 12135673Saw148015 filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s", 12145673Saw148015 "file size", 12155673Saw148015 "dir width", 12165673Saw148015 "entries"); 12175673Saw148015 } 12185673Saw148015 12195673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) { 12205673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { 12215673Saw148015 filebench_log(LOG_INFO, 12225673Saw148015 "%s/%s%s (Raw Device)", 12236212Saw148015 fileset_path, fileset_name, &pad[pathlength]); 12245673Saw148015 } else { 12255673Saw148015 filebench_log(LOG_INFO, 12266286Saw148015 "%s/%s%s%9llu (Single File)", 12276212Saw148015 fileset_path, fileset_name, &pad[pathlength], 12286286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size)); 12295673Saw148015 } 12305673Saw148015 } else { 12316286Saw148015 filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu", 12326212Saw148015 fileset_path, fileset_name, 12335673Saw148015 &pad[pathlength], 12346286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size), 12356286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_dirwidth), 12366286Saw148015 (u_longlong_t)fileset->fs_constentries); 12375673Saw148015 } 12385673Saw148015 return (0); 12395673Saw148015 } 12405673Saw148015 /* 12415673Saw148015 * checks to see if the path/name pair points to a raw device. If 12425673Saw148015 * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1. 12435673Saw148015 * If RAW is not defined, or it is not a raw device, it clears the 12445673Saw148015 * raw device flag and returns 0. 12455673Saw148015 */ 12465673Saw148015 int 12475673Saw148015 fileset_checkraw(fileset_t *fileset) 12485673Saw148015 { 12495673Saw148015 char path[MAXPATHLEN]; 12505673Saw148015 struct stat64 sb; 12516305Saw148015 char *pathname; 12526305Saw148015 char *setname; 12535673Saw148015 12545673Saw148015 fileset->fs_attrs &= (~FILESET_IS_RAW_DEV); 12555673Saw148015 12565673Saw148015 #ifdef HAVE_RAW_SUPPORT 12575673Saw148015 /* check for raw device */ 12586305Saw148015 if ((pathname = avd_get_str(fileset->fs_path)) == NULL) 12596305Saw148015 return (0); 12606305Saw148015 12616305Saw148015 if ((setname = avd_get_str(fileset->fs_name)) == NULL) 12626305Saw148015 return (0); 12636305Saw148015 12646305Saw148015 (void) strcpy(path, pathname); 12655673Saw148015 (void) strcat(path, "/"); 12666305Saw148015 (void) strcat(path, setname); 12675673Saw148015 if ((stat64(path, &sb) == 0) && 12685673Saw148015 ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { 12695673Saw148015 fileset->fs_attrs |= FILESET_IS_RAW_DEV; 12706305Saw148015 if (!(fileset->fs_attrs & FILESET_IS_FILE)) { 12716305Saw148015 filebench_log(LOG_ERROR, 12726305Saw148015 "WARNING Fileset %s/%s Cannot be RAW device", 12736305Saw148015 avd_get_str(fileset->fs_path), 12746305Saw148015 avd_get_str(fileset->fs_name)); 12756305Saw148015 filebench_shutdown(1); 12766305Saw148015 } 12776305Saw148015 12785673Saw148015 return (1); 12795673Saw148015 } 12805673Saw148015 #endif /* HAVE_RAW_SUPPORT */ 12815673Saw148015 12825673Saw148015 return (0); 12835673Saw148015 } 1284