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