15184Sek110237 /*
25184Sek110237  * CDDL HEADER START
35184Sek110237  *
45184Sek110237  * The contents of this file are subject to the terms of the
55184Sek110237  * Common Development and Distribution License (the "License").
65184Sek110237  * You may not use this file except in compliance with the License.
75184Sek110237  *
85184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95184Sek110237  * or http://www.opensolaris.org/os/licensing.
105184Sek110237  * See the License for the specific language governing permissions
115184Sek110237  * and limitations under the License.
125184Sek110237  *
135184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
145184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
165184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
175184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
185184Sek110237  *
195184Sek110237  * CDDL HEADER END
205184Sek110237  */
215184Sek110237 /*
226212Saw148015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235184Sek110237  * Use is subject to license terms.
246613Sek110237  *
256613Sek110237  * Portions Copyright 2008 Denis Cheng
265184Sek110237  */
275184Sek110237 
285184Sek110237 #include <fcntl.h>
295184Sek110237 #include <pthread.h>
305184Sek110237 #include <errno.h>
315184Sek110237 #include <math.h>
325184Sek110237 #include <libgen.h>
335184Sek110237 #include <sys/mman.h>
34*8404SAndrew.W.Wilson@sun.com #include <sys/shm.h>
356613Sek110237 
366613Sek110237 #include "filebench.h"
375184Sek110237 #include "fileset.h"
385184Sek110237 #include "gamma_dist.h"
397946SAndrew.W.Wilson@sun.com #include "utils.h"
405184Sek110237 
415184Sek110237 /*
425184Sek110237  * File sets, of type fileset_t, are entities which contain
435184Sek110237  * information about collections of files and subdirectories in Filebench.
445184Sek110237  * The fileset, once populated, consists of a tree of fileset entries of
455184Sek110237  * type filesetentry_t which specify files and directories.  The fileset
466212Saw148015  * is rooted in a directory specified by fileset_path, and once the populated
475184Sek110237  * fileset has been created, has a tree of directories and files
485184Sek110237  * corresponding to the fileset's filesetentry tree.
496701Saw148015  *
507556SAndrew.W.Wilson@sun.com  * Fileset entities are allocated by fileset_define() which is called from
517556SAndrew.W.Wilson@sun.com  * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding
527556SAndrew.W.Wilson@sun.com  * to the eventual directory and file tree to be instantiated on the storage
537946SAndrew.W.Wilson@sun.com  * medium is built by fileset_populate(), which is This routine is called
547946SAndrew.W.Wilson@sun.com  * from fileset_createset(), which is in turn called by fileset_createset().
557946SAndrew.W.Wilson@sun.com  * After calling fileset_populate(), fileset_createset() will call
567946SAndrew.W.Wilson@sun.com  * fileset_create() to pre-allocate designated files and directories.
577556SAndrew.W.Wilson@sun.com  *
587556SAndrew.W.Wilson@sun.com  * Fileset_createset() is called from parser_gram.y: parser_create_fileset()
597556SAndrew.W.Wilson@sun.com  * when a "create fileset" or "run" command is encountered. When the
607556SAndrew.W.Wilson@sun.com  * "create fileset" command is used, it is generally paired with
616701Saw148015  * a "create processes" command, and must appear first, in order to
626701Saw148015  * instantiate all the files in the fileset before trying to use them.
635184Sek110237  */
645184Sek110237 
656305Saw148015 static int fileset_checkraw(fileset_t *fileset);
666305Saw148015 
677556SAndrew.W.Wilson@sun.com /* maximum parallel allocation control */
685673Saw148015 #define	MAX_PARALLOC_THREADS 32
695673Saw148015 
705673Saw148015 /*
715673Saw148015  * returns pointer to file or fileset
725673Saw148015  * string, as appropriate
735673Saw148015  */
745673Saw148015 static char *
755673Saw148015 fileset_entity_name(fileset_t *fileset)
765673Saw148015 {
775673Saw148015 	if (fileset->fs_attrs & FILESET_IS_FILE)
785673Saw148015 		return ("file");
795673Saw148015 	else
805673Saw148015 		return ("fileset");
815673Saw148015 }
825673Saw148015 
835184Sek110237 /*
845184Sek110237  * Removes the last file or directory name from a pathname.
855184Sek110237  * Basically removes characters from the end of the path by
865184Sek110237  * setting them to \0 until a forward slash '/' is
875184Sek110237  * encountered. It also removes the forward slash.
885184Sek110237  */
895184Sek110237 static char *
905184Sek110237 trunc_dirname(char *dir)
915184Sek110237 {
925184Sek110237 	char *s = dir + strlen(dir);
935184Sek110237 
945184Sek110237 	while (s != dir) {
955184Sek110237 		int c = *s;
965184Sek110237 
975184Sek110237 		*s = 0;
985184Sek110237 		if (c == '/')
995184Sek110237 			break;
1005184Sek110237 		s--;
1015184Sek110237 	}
1025184Sek110237 	return (dir);
1035184Sek110237 }
1045184Sek110237 
1055184Sek110237 /*
1065184Sek110237  * Prints a list of allowed options and how to specify them.
1075184Sek110237  */
1085184Sek110237 void
1095184Sek110237 fileset_usage(void)
1105184Sek110237 {
1115673Saw148015 	(void) fprintf(stderr,
1125673Saw148015 	    "define [file name=<name> | fileset name=<name>],path=<pathname>,"
1135673Saw148015 	    ",entries=<number>\n");
1145673Saw148015 	(void) fprintf(stderr,
1156212Saw148015 	    "		        [,filesize=[size]]\n");
1166212Saw148015 	(void) fprintf(stderr,
1175673Saw148015 	    "		        [,dirwidth=[width]]\n");
1185673Saw148015 	(void) fprintf(stderr,
1196212Saw148015 	    "		        [,dirdepthrv=$random_variable_name]\n");
1206212Saw148015 	(void) fprintf(stderr,
1215673Saw148015 	    "		        [,dirgamma=[100-10000]] "
1225184Sek110237 	    "(Gamma * 1000)\n");
1235184Sek110237 	(void) fprintf(stderr,
1245673Saw148015 	    "		        [,sizegamma=[100-10000]] (Gamma * 1000)\n");
1255184Sek110237 	(void) fprintf(stderr,
1265184Sek110237 	    "		        [,prealloc=[percent]]\n");
1275673Saw148015 	(void) fprintf(stderr, "		        [,paralloc]\n");
1285184Sek110237 	(void) fprintf(stderr, "		        [,reuse]\n");
1295184Sek110237 	(void) fprintf(stderr, "\n");
1305184Sek110237 }
1315184Sek110237 
1325184Sek110237 /*
1335184Sek110237  * Frees up memory mapped file region of supplied size. The
1345184Sek110237  * file descriptor "fd" indicates which memory mapped file.
1357946SAndrew.W.Wilson@sun.com  * If successful, returns 0. Otherwise returns -1 if "size"
1367946SAndrew.W.Wilson@sun.com  * is zero, or -1 times the number of times msync() failed.
1375184Sek110237  */
1385184Sek110237 static int
1395184Sek110237 fileset_freemem(int fd, off64_t size)
1405184Sek110237 {
1415184Sek110237 	off64_t left;
1425184Sek110237 	int ret = 0;
1435184Sek110237 
1445184Sek110237 	for (left = size; left > 0; left -= MMAP_SIZE) {
1455184Sek110237 		off64_t thismapsize;
1465184Sek110237 		caddr_t addr;
1475184Sek110237 
1485184Sek110237 		thismapsize = MIN(MMAP_SIZE, left);
1495184Sek110237 		addr = mmap64(0, thismapsize, PROT_READ|PROT_WRITE,
1505184Sek110237 		    MAP_SHARED, fd, size - left);
1515184Sek110237 		ret += msync(addr, thismapsize, MS_INVALIDATE);
1525184Sek110237 		(void) munmap(addr, thismapsize);
1535184Sek110237 	}
1545184Sek110237 	return (ret);
1555184Sek110237 }
1565184Sek110237 
1575184Sek110237 /*
1585184Sek110237  * Creates a path string from the filesetentry_t "*entry"
1595184Sek110237  * and all of its parent's path names. The resulting path
1605184Sek110237  * is a concatination of all the individual parent paths.
1615184Sek110237  * Allocates memory for the path string and returns a
1625184Sek110237  * pointer to it.
1635184Sek110237  */
1645184Sek110237 char *
1655184Sek110237 fileset_resolvepath(filesetentry_t *entry)
1665184Sek110237 {
1675184Sek110237 	filesetentry_t *fsep = entry;
1685184Sek110237 	char path[MAXPATHLEN];
1695184Sek110237 	char pathtmp[MAXPATHLEN];
1705184Sek110237 	char *s;
1715184Sek110237 
1727946SAndrew.W.Wilson@sun.com 	path[0] = '\0';
1735184Sek110237 	while (fsep->fse_parent) {
1745184Sek110237 		(void) strcpy(pathtmp, "/");
1757946SAndrew.W.Wilson@sun.com 		(void) fb_strlcat(pathtmp, fsep->fse_path, MAXPATHLEN);
1767946SAndrew.W.Wilson@sun.com 		(void) fb_strlcat(pathtmp, path, MAXPATHLEN);
1777946SAndrew.W.Wilson@sun.com 		(void) fb_strlcpy(path, pathtmp, MAXPATHLEN);
1785184Sek110237 		fsep = fsep->fse_parent;
1795184Sek110237 	}
1805184Sek110237 
1815184Sek110237 	s = malloc(strlen(path) + 1);
1827946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(s, path, MAXPATHLEN);
1835184Sek110237 	return (s);
1845184Sek110237 }
1855184Sek110237 
1865184Sek110237 /*
1875184Sek110237  * Creates multiple nested directories as required by the
1885184Sek110237  * supplied path. Starts at the end of the path, creating
1895184Sek110237  * a list of directories to mkdir, up to the root of the
1905184Sek110237  * path, then mkdirs them one at a time from the root on down.
1915184Sek110237  */
1925184Sek110237 static int
1935184Sek110237 fileset_mkdir(char *path, int mode)
1945184Sek110237 {
1955184Sek110237 	char *p;
1965184Sek110237 	char *dirs[65536];
1975184Sek110237 	int i = 0;
1985184Sek110237 
1995184Sek110237 	if ((p = strdup(path)) == NULL)
2005184Sek110237 		goto null_str;
2015184Sek110237 
2025184Sek110237 	/*
2035184Sek110237 	 * Fill an array of subdirectory path names until either we
2045184Sek110237 	 * reach the root or encounter an already existing subdirectory
2055184Sek110237 	 */
2065184Sek110237 	/* CONSTCOND */
2075184Sek110237 	while (1) {
2085184Sek110237 		struct stat64 sb;
2095184Sek110237 
2105184Sek110237 		if (stat64(p, &sb) == 0)
2115184Sek110237 			break;
2125184Sek110237 		if (strlen(p) < 3)
2135184Sek110237 			break;
2145184Sek110237 		if ((dirs[i] = strdup(p)) == NULL) {
2155184Sek110237 			free(p);
2165184Sek110237 			goto null_str;
2175184Sek110237 		}
2185184Sek110237 
2195184Sek110237 		(void) trunc_dirname(p);
2205184Sek110237 		i++;
2215184Sek110237 	}
2225184Sek110237 
2235184Sek110237 	/* Make the directories, from closest to root downwards. */
2245184Sek110237 	for (--i; i >= 0; i--) {
2255184Sek110237 		(void) mkdir(dirs[i], mode);
2265184Sek110237 		free(dirs[i]);
2275184Sek110237 	}
2285184Sek110237 
2295184Sek110237 	free(p);
2307556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
2315184Sek110237 
2325184Sek110237 null_str:
2335184Sek110237 	/* clean up */
2345184Sek110237 	for (--i; i >= 0; i--)
2355184Sek110237 		free(dirs[i]);
2365184Sek110237 
2375184Sek110237 	filebench_log(LOG_ERROR,
2385184Sek110237 	    "Failed to create directory path %s: Out of memory", path);
2397556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_ERROR);
2405184Sek110237 }
2415184Sek110237 
2425673Saw148015 /*
2435673Saw148015  * creates the subdirectory tree for a fileset.
2445673Saw148015  */
2455673Saw148015 static int
2465673Saw148015 fileset_create_subdirs(fileset_t *fileset, char *filesetpath)
2475673Saw148015 {
2485673Saw148015 	filesetentry_t *direntry;
2495673Saw148015 	char full_path[MAXPATHLEN];
2505673Saw148015 	char *part_path;
2515673Saw148015 
2525673Saw148015 	/* walk the subdirectory list, enstanciating subdirs */
2535673Saw148015 	direntry = fileset->fs_dirlist;
2545673Saw148015 	while (direntry) {
2557946SAndrew.W.Wilson@sun.com 		(void) fb_strlcpy(full_path, filesetpath, MAXPATHLEN);
2565673Saw148015 		part_path = fileset_resolvepath(direntry);
2577946SAndrew.W.Wilson@sun.com 		(void) fb_strlcat(full_path, part_path, MAXPATHLEN);
2585673Saw148015 		free(part_path);
2595673Saw148015 
2605673Saw148015 		/* now create this portion of the subdirectory tree */
2617556SAndrew.W.Wilson@sun.com 		if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR)
2627556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
2635673Saw148015 
264*8404SAndrew.W.Wilson@sun.com 		direntry = direntry->fse_nextoftype;
2655673Saw148015 	}
2667556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
2675673Saw148015 }
2685673Saw148015 
2695673Saw148015 /*
270*8404SAndrew.W.Wilson@sun.com  * move filesetentry between exist tree and non-exist tree, source_tree
271*8404SAndrew.W.Wilson@sun.com  * to destination tree.
272*8404SAndrew.W.Wilson@sun.com  */
273*8404SAndrew.W.Wilson@sun.com static void
274*8404SAndrew.W.Wilson@sun.com fileset_move_entry(avl_tree_t *src_tree, avl_tree_t *dst_tree,
275*8404SAndrew.W.Wilson@sun.com     filesetentry_t *entry)
276*8404SAndrew.W.Wilson@sun.com {
277*8404SAndrew.W.Wilson@sun.com 	avl_remove(src_tree, entry);
278*8404SAndrew.W.Wilson@sun.com 	avl_add(dst_tree, entry);
279*8404SAndrew.W.Wilson@sun.com }
280*8404SAndrew.W.Wilson@sun.com 
281*8404SAndrew.W.Wilson@sun.com /*
2827946SAndrew.W.Wilson@sun.com  * given a fileset entry, determines if the associated leaf directory
2837946SAndrew.W.Wilson@sun.com  * needs to be made or not, and if so does the mkdir.
2847946SAndrew.W.Wilson@sun.com  */
2857946SAndrew.W.Wilson@sun.com static int
2867946SAndrew.W.Wilson@sun.com fileset_alloc_leafdir(filesetentry_t *entry)
2877946SAndrew.W.Wilson@sun.com {
2887946SAndrew.W.Wilson@sun.com 	fileset_t *fileset;
2897946SAndrew.W.Wilson@sun.com 	char path[MAXPATHLEN];
2907946SAndrew.W.Wilson@sun.com 	struct stat64 sb;
2917946SAndrew.W.Wilson@sun.com 	char *pathtmp;
2927946SAndrew.W.Wilson@sun.com 
2937946SAndrew.W.Wilson@sun.com 	fileset = entry->fse_fileset;
2947946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
2957946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
2967946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
2977946SAndrew.W.Wilson@sun.com 	pathtmp = fileset_resolvepath(entry);
2987946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
2997946SAndrew.W.Wilson@sun.com 	free(pathtmp);
3007946SAndrew.W.Wilson@sun.com 
3017946SAndrew.W.Wilson@sun.com 	filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
3027946SAndrew.W.Wilson@sun.com 
3037946SAndrew.W.Wilson@sun.com 	/* see if not reusing and this directory does not exist */
3047946SAndrew.W.Wilson@sun.com 	if (!((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0))) {
3057946SAndrew.W.Wilson@sun.com 
3067946SAndrew.W.Wilson@sun.com 		/* No file or not reusing, so create */
3077946SAndrew.W.Wilson@sun.com 		if (mkdir(path, 0755) < 0) {
3087946SAndrew.W.Wilson@sun.com 			filebench_log(LOG_ERROR,
3097946SAndrew.W.Wilson@sun.com 			    "Failed to pre-allocate leaf directory %s: %s",
3107946SAndrew.W.Wilson@sun.com 			    path, strerror(errno));
311*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
3127946SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
3137946SAndrew.W.Wilson@sun.com 		}
3147946SAndrew.W.Wilson@sun.com 	}
3157946SAndrew.W.Wilson@sun.com 
316*8404SAndrew.W.Wilson@sun.com 	/* unbusy the allocated entry */
317*8404SAndrew.W.Wilson@sun.com 	fileset_unbusy(entry, TRUE, TRUE, 0);
3187946SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
3197946SAndrew.W.Wilson@sun.com }
3207946SAndrew.W.Wilson@sun.com 
3217946SAndrew.W.Wilson@sun.com /*
3225673Saw148015  * given a fileset entry, determines if the associated file
3235673Saw148015  * needs to be allocated or not, and if so does the allocation.
3245673Saw148015  */
3255673Saw148015 static int
3265673Saw148015 fileset_alloc_file(filesetentry_t *entry)
3275673Saw148015 {
3287946SAndrew.W.Wilson@sun.com 	fileset_t *fileset;
3295673Saw148015 	char path[MAXPATHLEN];
3305673Saw148015 	char *buf;
3315673Saw148015 	struct stat64 sb;
3325673Saw148015 	char *pathtmp;
3335673Saw148015 	off64_t seek;
3345673Saw148015 	int fd;
3355673Saw148015 
3367946SAndrew.W.Wilson@sun.com 	fileset = entry->fse_fileset;
3377946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
3387946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
3397946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
3405673Saw148015 	pathtmp = fileset_resolvepath(entry);
3417946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
3427946SAndrew.W.Wilson@sun.com 	free(pathtmp);
3435673Saw148015 
3445673Saw148015 	filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
3455673Saw148015 
3465673Saw148015 	/* see if reusing and this file exists */
3475673Saw148015 	if ((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0)) {
3485673Saw148015 		if ((fd = open64(path, O_RDWR)) < 0) {
3495673Saw148015 			filebench_log(LOG_INFO,
3505673Saw148015 			    "Attempted but failed to Re-use file %s",
3515673Saw148015 			    path);
352*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
3537556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
3545673Saw148015 		}
3555673Saw148015 
3565673Saw148015 		if (sb.st_size == (off64_t)entry->fse_size) {
3577556SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
3585673Saw148015 			    "Re-using file %s", path);
3595673Saw148015 
3607946SAndrew.W.Wilson@sun.com 			if (!avd_get_bool(fileset->fs_cached))
3615673Saw148015 				(void) fileset_freemem(fd,
3625673Saw148015 				    entry->fse_size);
3635673Saw148015 
364*8404SAndrew.W.Wilson@sun.com 			(void) close(fd);
3656701Saw148015 
366*8404SAndrew.W.Wilson@sun.com 			/* unbusy the allocated entry */
367*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, TRUE, 0);
3687556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_OK);
3695673Saw148015 
3705673Saw148015 		} else if (sb.st_size > (off64_t)entry->fse_size) {
3715673Saw148015 			/* reuse, but too large */
372*8404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
3735673Saw148015 			    "Truncating & re-using file %s", path);
3745673Saw148015 
3756613Sek110237 #ifdef HAVE_FTRUNCATE64
3766613Sek110237 			(void) ftruncate64(fd, (off64_t)entry->fse_size);
3776613Sek110237 #else
3786613Sek110237 			(void) ftruncate(fd, (off_t)entry->fse_size);
3796613Sek110237 #endif
3805673Saw148015 
3817946SAndrew.W.Wilson@sun.com 			if (!avd_get_bool(fileset->fs_cached))
3825673Saw148015 				(void) fileset_freemem(fd,
3835673Saw148015 				    entry->fse_size);
3845673Saw148015 
385*8404SAndrew.W.Wilson@sun.com 			(void) close(fd);
3866701Saw148015 
387*8404SAndrew.W.Wilson@sun.com 			/* unbusy the allocated entry */
388*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, TRUE, 0);
3897556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_OK);
3905673Saw148015 		}
3915673Saw148015 	} else {
3925673Saw148015 
3935673Saw148015 		/* No file or not reusing, so create */
3945673Saw148015 		if ((fd = open64(path, O_RDWR | O_CREAT, 0644)) < 0) {
3955673Saw148015 			filebench_log(LOG_ERROR,
3965673Saw148015 			    "Failed to pre-allocate file %s: %s",
3975673Saw148015 			    path, strerror(errno));
3985673Saw148015 
399*8404SAndrew.W.Wilson@sun.com 			/* unbusy the unallocated entry */
400*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
4017556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
4025673Saw148015 		}
4035673Saw148015 	}
4045673Saw148015 
405*8404SAndrew.W.Wilson@sun.com 	if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) {
406*8404SAndrew.W.Wilson@sun.com 		/* unbusy the unallocated entry */
407*8404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, TRUE, FALSE, 0);
4087556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
409*8404SAndrew.W.Wilson@sun.com 	}
4106701Saw148015 
4115673Saw148015 	for (seek = 0; seek < entry->fse_size; ) {
4125673Saw148015 		off64_t wsize;
4135673Saw148015 		int ret = 0;
4145673Saw148015 
4155673Saw148015 		/*
4165673Saw148015 		 * Write FILE_ALLOC_BLOCK's worth,
4175673Saw148015 		 * except on last write
4185673Saw148015 		 */
4195673Saw148015 		wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK);
4205673Saw148015 
4215673Saw148015 		ret = write(fd, buf, wsize);
4225673Saw148015 		if (ret != wsize) {
4235673Saw148015 			filebench_log(LOG_ERROR,
4245673Saw148015 			    "Failed to pre-allocate file %s: %s",
4255673Saw148015 			    path, strerror(errno));
4265673Saw148015 			(void) close(fd);
4275673Saw148015 			free(buf);
428*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
4297556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
4305673Saw148015 		}
4315673Saw148015 		seek += wsize;
4325673Saw148015 	}
4335673Saw148015 
4347946SAndrew.W.Wilson@sun.com 	if (!avd_get_bool(fileset->fs_cached))
4355673Saw148015 		(void) fileset_freemem(fd, entry->fse_size);
4365673Saw148015 
4375673Saw148015 	(void) close(fd);
4385673Saw148015 
4395673Saw148015 	free(buf);
4405673Saw148015 
441*8404SAndrew.W.Wilson@sun.com 	/* unbusy the allocated entry */
442*8404SAndrew.W.Wilson@sun.com 	fileset_unbusy(entry, TRUE, TRUE, 0);
443*8404SAndrew.W.Wilson@sun.com 
4445673Saw148015 	filebench_log(LOG_DEBUG_IMPL,
4456286Saw148015 	    "Pre-allocated file %s size %llu",
4466286Saw148015 	    path, (u_longlong_t)entry->fse_size);
4475673Saw148015 
4487556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
4495673Saw148015 }
4505673Saw148015 
4515673Saw148015 /*
4525673Saw148015  * given a fileset entry, determines if the associated file
4535673Saw148015  * needs to be allocated or not, and if so does the allocation.
4547556SAndrew.W.Wilson@sun.com  * Sets shm_fsparalloc_count to -1 on error.
4555673Saw148015  */
4565673Saw148015 static void *
4575673Saw148015 fileset_alloc_thread(filesetentry_t *entry)
4585673Saw148015 {
4597556SAndrew.W.Wilson@sun.com 	if (fileset_alloc_file(entry) == FILEBENCH_ERROR) {
4607556SAndrew.W.Wilson@sun.com 		(void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
4617556SAndrew.W.Wilson@sun.com 		filebench_shm->shm_fsparalloc_count = -1;
4625673Saw148015 	} else {
4637556SAndrew.W.Wilson@sun.com 		(void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
4647556SAndrew.W.Wilson@sun.com 		filebench_shm->shm_fsparalloc_count--;
4655673Saw148015 	}
4665673Saw148015 
4677556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv);
4687556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
4695673Saw148015 
4705673Saw148015 	pthread_exit(NULL);
4715673Saw148015 	return (NULL);
4725673Saw148015 }
4735673Saw148015 
4745184Sek110237 
4755184Sek110237 /*
4765184Sek110237  * First creates the parent directories of the file using
4775184Sek110237  * fileset_mkdir(). Then Optionally sets the O_DSYNC flag
4785184Sek110237  * and opens the file with open64(). It unlocks the fileset
4795184Sek110237  * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags
4805184Sek110237  * as requested, and returns the file descriptor integer
4815184Sek110237  * for the opened file.
4825184Sek110237  */
4835184Sek110237 int
4845184Sek110237 fileset_openfile(fileset_t *fileset,
4857736SAndrew.W.Wilson@sun.com     filesetentry_t *entry, int flag, int filemode, int attrs)
4865184Sek110237 {
4875184Sek110237 	char path[MAXPATHLEN];
4885184Sek110237 	char dir[MAXPATHLEN];
4895184Sek110237 	char *pathtmp;
4905184Sek110237 	struct stat64 sb;
4915184Sek110237 	int fd;
4925184Sek110237 	int open_attrs = 0;
4935184Sek110237 
4947946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
4957946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
4967946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
4975184Sek110237 	pathtmp = fileset_resolvepath(entry);
4987946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
4997946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(dir, path, MAXPATHLEN);
5005184Sek110237 	free(pathtmp);
5015184Sek110237 	(void) trunc_dirname(dir);
5025184Sek110237 
5035184Sek110237 	/* If we are going to create a file, create the parent dirs */
5045184Sek110237 	if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) {
5057556SAndrew.W.Wilson@sun.com 		if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR)
5067556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
5076701Saw148015 	}
5086701Saw148015 
5095184Sek110237 	if (attrs & FLOW_ATTR_DSYNC) {
5105184Sek110237 #ifdef sun
5115184Sek110237 		open_attrs |= O_DSYNC;
5125184Sek110237 #else
5135184Sek110237 		open_attrs |= O_FSYNC;
5145184Sek110237 #endif
5155184Sek110237 	}
5165184Sek110237 
5177736SAndrew.W.Wilson@sun.com 	if ((fd = open64(path, flag | open_attrs, filemode)) < 0) {
5185184Sek110237 		filebench_log(LOG_ERROR,
519*8404SAndrew.W.Wilson@sun.com 		    "Failed to open file %d, %s, with status %x: %s",
520*8404SAndrew.W.Wilson@sun.com 		    entry->fse_index, path, entry->fse_flags, strerror(errno));
5217556SAndrew.W.Wilson@sun.com 
522*8404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, FALSE, FALSE, 0);
5237556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
5245184Sek110237 	}
5257556SAndrew.W.Wilson@sun.com 
5267556SAndrew.W.Wilson@sun.com 	if (flag & O_CREAT)
527*8404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, TRUE, TRUE, 1);
5287556SAndrew.W.Wilson@sun.com 	else
529*8404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, FALSE, FALSE, 1);
5305184Sek110237 
5315184Sek110237 #ifdef sun
5325184Sek110237 	if (attrs & FLOW_ATTR_DIRECTIO)
5335184Sek110237 		(void) directio(fd, DIRECTIO_ON);
5345184Sek110237 	else
5355184Sek110237 		(void) directio(fd, DIRECTIO_OFF);
5365184Sek110237 #endif
5375184Sek110237 
5385184Sek110237 	return (fd);
5395184Sek110237 }
5405184Sek110237 
541*8404SAndrew.W.Wilson@sun.com /*
542*8404SAndrew.W.Wilson@sun.com  * removes all filesetentries from their respective btrees, and puts them
543*8404SAndrew.W.Wilson@sun.com  * on the free list. The supplied argument indicates which free list to
544*8404SAndrew.W.Wilson@sun.com  * use.
545*8404SAndrew.W.Wilson@sun.com  */
546*8404SAndrew.W.Wilson@sun.com static void
547*8404SAndrew.W.Wilson@sun.com fileset_pickreset(fileset_t *fileset, int entry_type)
548*8404SAndrew.W.Wilson@sun.com {
549*8404SAndrew.W.Wilson@sun.com 	filesetentry_t	*entry;
550*8404SAndrew.W.Wilson@sun.com 
551*8404SAndrew.W.Wilson@sun.com 	switch (entry_type & FILESET_PICKMASK) {
552*8404SAndrew.W.Wilson@sun.com 	case FILESET_PICKFILE:
553*8404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)avl_first(&fileset->fs_noex_files);
554*8404SAndrew.W.Wilson@sun.com 
555*8404SAndrew.W.Wilson@sun.com 		/* make sure non-existing files are marked free */
556*8404SAndrew.W.Wilson@sun.com 		while (entry) {
557*8404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
558*8404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
559*8404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_noex_files,
560*8404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_files, entry);
561*8404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_noex_files, entry);
562*8404SAndrew.W.Wilson@sun.com 		}
563*8404SAndrew.W.Wilson@sun.com 
564*8404SAndrew.W.Wilson@sun.com 		/* free up any existing files */
565*8404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)avl_first(&fileset->fs_exist_files);
566*8404SAndrew.W.Wilson@sun.com 
567*8404SAndrew.W.Wilson@sun.com 		while (entry) {
568*8404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
569*8404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
570*8404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_exist_files,
571*8404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_files, entry);
572*8404SAndrew.W.Wilson@sun.com 
573*8404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_exist_files, entry);
574*8404SAndrew.W.Wilson@sun.com 		}
575*8404SAndrew.W.Wilson@sun.com 
576*8404SAndrew.W.Wilson@sun.com 		break;
577*8404SAndrew.W.Wilson@sun.com 
578*8404SAndrew.W.Wilson@sun.com 	case FILESET_PICKDIR:
579*8404SAndrew.W.Wilson@sun.com 		/* nothing to reset, as all (sub)dirs always exist */
580*8404SAndrew.W.Wilson@sun.com 		break;
581*8404SAndrew.W.Wilson@sun.com 
582*8404SAndrew.W.Wilson@sun.com 	case FILESET_PICKLEAFDIR:
583*8404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)
584*8404SAndrew.W.Wilson@sun.com 		    avl_first(&fileset->fs_noex_leaf_dirs);
585*8404SAndrew.W.Wilson@sun.com 
586*8404SAndrew.W.Wilson@sun.com 		/* make sure non-existing leaf dirs are marked free */
587*8404SAndrew.W.Wilson@sun.com 		while (entry) {
588*8404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
589*8404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
590*8404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_noex_leaf_dirs,
591*8404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_leaf_dirs, entry);
592*8404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_noex_leaf_dirs, entry);
593*8404SAndrew.W.Wilson@sun.com 		}
594*8404SAndrew.W.Wilson@sun.com 
595*8404SAndrew.W.Wilson@sun.com 		/* free up any existing leaf dirs */
596*8404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)
597*8404SAndrew.W.Wilson@sun.com 		    avl_first(&fileset->fs_exist_leaf_dirs);
598*8404SAndrew.W.Wilson@sun.com 
599*8404SAndrew.W.Wilson@sun.com 		while (entry) {
600*8404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
601*8404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
602*8404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_exist_leaf_dirs,
603*8404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_leaf_dirs, entry);
604*8404SAndrew.W.Wilson@sun.com 
605*8404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_exist_leaf_dirs, entry);
606*8404SAndrew.W.Wilson@sun.com 		}
607*8404SAndrew.W.Wilson@sun.com 
608*8404SAndrew.W.Wilson@sun.com 		break;
609*8404SAndrew.W.Wilson@sun.com 	}
610*8404SAndrew.W.Wilson@sun.com }
611*8404SAndrew.W.Wilson@sun.com 
612*8404SAndrew.W.Wilson@sun.com /*
613*8404SAndrew.W.Wilson@sun.com  * find a filesetentry from the fileset using the supplied index
614*8404SAndrew.W.Wilson@sun.com  */
615*8404SAndrew.W.Wilson@sun.com static filesetentry_t *
616*8404SAndrew.W.Wilson@sun.com fileset_find_entry(avl_tree_t *atp, uint_t index)
617*8404SAndrew.W.Wilson@sun.com {
618*8404SAndrew.W.Wilson@sun.com 	avl_index_t	found_loc;
619*8404SAndrew.W.Wilson@sun.com 	filesetentry_t	desired_fse, *found_fse;
620*8404SAndrew.W.Wilson@sun.com 
621*8404SAndrew.W.Wilson@sun.com 	/* find the file with the desired index, if it is in the tree */
622*8404SAndrew.W.Wilson@sun.com 	desired_fse.fse_index = index;
623*8404SAndrew.W.Wilson@sun.com 	found_fse = avl_find(atp, (void *)(&desired_fse), &found_loc);
624*8404SAndrew.W.Wilson@sun.com 	if (found_fse != NULL)
625*8404SAndrew.W.Wilson@sun.com 		return (found_fse);
626*8404SAndrew.W.Wilson@sun.com 
627*8404SAndrew.W.Wilson@sun.com 	/* if requested node not found, find next higher node */
628*8404SAndrew.W.Wilson@sun.com 	found_fse = avl_nearest(atp, found_loc, AVL_AFTER);
629*8404SAndrew.W.Wilson@sun.com 	if (found_fse != NULL)
630*8404SAndrew.W.Wilson@sun.com 		return (found_fse);
631*8404SAndrew.W.Wilson@sun.com 
632*8404SAndrew.W.Wilson@sun.com 	/* might have hit the end, return lowest available index node */
633*8404SAndrew.W.Wilson@sun.com 	found_fse = avl_first(atp);
634*8404SAndrew.W.Wilson@sun.com 	return (found_fse);
635*8404SAndrew.W.Wilson@sun.com }
6365184Sek110237 
6375184Sek110237 /*
6385184Sek110237  * Selects a fileset entry from a fileset. If the
6397946SAndrew.W.Wilson@sun.com  * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry,
6407946SAndrew.W.Wilson@sun.com  * if the FILESET_PICKDIR flag is set it will pick a non leaf directory
641*8404SAndrew.W.Wilson@sun.com  * entry, otherwise a file entry. The FILESET_PICKUNIQUE
6425184Sek110237  * flag will take an entry off of one of the free (unused)
6435184Sek110237  * lists (file or directory), otherwise the entry will be
6445184Sek110237  * picked off of one of the rotor lists (file or directory).
6455184Sek110237  * The FILESET_PICKEXISTS will insure that only extant
6465184Sek110237  * (FSE_EXISTS) state files are selected, while
6475184Sek110237  * FILESET_PICKNOEXIST insures that only non extant
6485184Sek110237  * (not FSE_EXISTS) state files are selected.
6496391Saw148015  * Note that the selected fileset entry (file) is returned
6507556SAndrew.W.Wilson@sun.com  * with its FSE_BUSY flag (in fse_flags) set.
6515184Sek110237  */
6525184Sek110237 filesetentry_t *
653*8404SAndrew.W.Wilson@sun.com fileset_pick(fileset_t *fileset, int flags, int tid, int index)
6545184Sek110237 {
6555184Sek110237 	filesetentry_t *entry = NULL;
656*8404SAndrew.W.Wilson@sun.com 	filesetentry_t *start_point;
657*8404SAndrew.W.Wilson@sun.com 	avl_tree_t *atp;
658*8404SAndrew.W.Wilson@sun.com 	fbint_t max_entries;
6595184Sek110237 
6607556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
6617556SAndrew.W.Wilson@sun.com 
6627556SAndrew.W.Wilson@sun.com 	/* see if we have to wait for available files or directories */
6637946SAndrew.W.Wilson@sun.com 	switch (flags & FILESET_PICKMASK) {
6647946SAndrew.W.Wilson@sun.com 	case FILESET_PICKFILE:
6657946SAndrew.W.Wilson@sun.com 		if (fileset->fs_filelist == NULL)
6667946SAndrew.W.Wilson@sun.com 			goto empty;
667*8404SAndrew.W.Wilson@sun.com 
6687556SAndrew.W.Wilson@sun.com 		while (fileset->fs_idle_files == 0) {
6697556SAndrew.W.Wilson@sun.com 			(void) pthread_cond_wait(&fileset->fs_idle_files_cv,
6707556SAndrew.W.Wilson@sun.com 			    &fileset->fs_pick_lock);
6717556SAndrew.W.Wilson@sun.com 		}
672*8404SAndrew.W.Wilson@sun.com 
673*8404SAndrew.W.Wilson@sun.com 		max_entries = fileset->fs_constentries;
674*8404SAndrew.W.Wilson@sun.com 		if (flags & FILESET_PICKUNIQUE) {
675*8404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_free_files;
676*8404SAndrew.W.Wilson@sun.com 		} else if (flags & FILESET_PICKNOEXIST) {
677*8404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_noex_files;
678*8404SAndrew.W.Wilson@sun.com 		} else {
679*8404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_exist_files;
680*8404SAndrew.W.Wilson@sun.com 		}
6817946SAndrew.W.Wilson@sun.com 		break;
682*8404SAndrew.W.Wilson@sun.com 
6837946SAndrew.W.Wilson@sun.com 	case FILESET_PICKDIR:
6847946SAndrew.W.Wilson@sun.com 		if (fileset->fs_dirlist == NULL)
6857946SAndrew.W.Wilson@sun.com 			goto empty;
686*8404SAndrew.W.Wilson@sun.com 
6877946SAndrew.W.Wilson@sun.com 		while (fileset->fs_idle_dirs == 0) {
6887946SAndrew.W.Wilson@sun.com 			(void) pthread_cond_wait(&fileset->fs_idle_dirs_cv,
6897946SAndrew.W.Wilson@sun.com 			    &fileset->fs_pick_lock);
6907946SAndrew.W.Wilson@sun.com 		}
691*8404SAndrew.W.Wilson@sun.com 
692*8404SAndrew.W.Wilson@sun.com 		max_entries = 1;
693*8404SAndrew.W.Wilson@sun.com 		atp = &fileset->fs_dirs;
6947946SAndrew.W.Wilson@sun.com 		break;
695*8404SAndrew.W.Wilson@sun.com 
6967946SAndrew.W.Wilson@sun.com 	case FILESET_PICKLEAFDIR:
6977946SAndrew.W.Wilson@sun.com 		if (fileset->fs_leafdirlist == NULL)
6987946SAndrew.W.Wilson@sun.com 			goto empty;
699*8404SAndrew.W.Wilson@sun.com 
7007946SAndrew.W.Wilson@sun.com 		while (fileset->fs_idle_leafdirs == 0) {
7017946SAndrew.W.Wilson@sun.com 			(void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv,
7027946SAndrew.W.Wilson@sun.com 			    &fileset->fs_pick_lock);
7037946SAndrew.W.Wilson@sun.com 		}
704*8404SAndrew.W.Wilson@sun.com 
705*8404SAndrew.W.Wilson@sun.com 		max_entries = fileset->fs_constleafdirs;
706*8404SAndrew.W.Wilson@sun.com 		if (flags & FILESET_PICKUNIQUE) {
707*8404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_free_leaf_dirs;
708*8404SAndrew.W.Wilson@sun.com 		} else if (flags & FILESET_PICKNOEXIST) {
709*8404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_noex_leaf_dirs;
710*8404SAndrew.W.Wilson@sun.com 		} else {
711*8404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_exist_leaf_dirs;
712*8404SAndrew.W.Wilson@sun.com 		}
7137946SAndrew.W.Wilson@sun.com 		break;
7147556SAndrew.W.Wilson@sun.com 	}
7155184Sek110237 
7166701Saw148015 	/* see if asking for impossible */
717*8404SAndrew.W.Wilson@sun.com 	if (avl_is_empty(atp))
718*8404SAndrew.W.Wilson@sun.com 		goto empty;
719*8404SAndrew.W.Wilson@sun.com 
720*8404SAndrew.W.Wilson@sun.com 	if (flags & FILESET_PICKUNIQUE) {
721*8404SAndrew.W.Wilson@sun.com 		uint64_t  index64;
722*8404SAndrew.W.Wilson@sun.com 
723*8404SAndrew.W.Wilson@sun.com 		/*
724*8404SAndrew.W.Wilson@sun.com 		 * pick at random from free list in order to
725*8404SAndrew.W.Wilson@sun.com 		 * distribute initially allocated files more
726*8404SAndrew.W.Wilson@sun.com 		 * randomly on storage media. Use uniform
727*8404SAndrew.W.Wilson@sun.com 		 * random number generator to select index
728*8404SAndrew.W.Wilson@sun.com 		 * if it is not supplied with pick call.
729*8404SAndrew.W.Wilson@sun.com 		 */
730*8404SAndrew.W.Wilson@sun.com 		if (index) {
731*8404SAndrew.W.Wilson@sun.com 			index64 = index;
732*8404SAndrew.W.Wilson@sun.com 		} else {
733*8404SAndrew.W.Wilson@sun.com 			if (filebench_randomno64(&index64, max_entries, 1,
734*8404SAndrew.W.Wilson@sun.com 			    NULL) == FILEBENCH_ERROR)
7357946SAndrew.W.Wilson@sun.com 				return (NULL);
7365184Sek110237 		}
7375184Sek110237 
738*8404SAndrew.W.Wilson@sun.com 		entry = fileset_find_entry(atp, (int)index64);
739*8404SAndrew.W.Wilson@sun.com 
740*8404SAndrew.W.Wilson@sun.com 		if (entry == NULL)
741*8404SAndrew.W.Wilson@sun.com 			goto empty;
742*8404SAndrew.W.Wilson@sun.com 
743*8404SAndrew.W.Wilson@sun.com 	} else if (flags & FILESET_PICKBYINDEX) {
744*8404SAndrew.W.Wilson@sun.com 		/* pick by supplied index */
745*8404SAndrew.W.Wilson@sun.com 		entry = fileset_find_entry(atp, index);
746*8404SAndrew.W.Wilson@sun.com 
747*8404SAndrew.W.Wilson@sun.com 	} else {
748*8404SAndrew.W.Wilson@sun.com 		/* pick in rotation */
749*8404SAndrew.W.Wilson@sun.com 		switch (flags & FILESET_PICKMASK) {
750*8404SAndrew.W.Wilson@sun.com 		case FILESET_PICKFILE:
751*8404SAndrew.W.Wilson@sun.com 			if (flags & FILESET_PICKNOEXIST) {
752*8404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
753*8404SAndrew.W.Wilson@sun.com 				    fileset->fs_file_nerotor);
754*8404SAndrew.W.Wilson@sun.com 				fileset->fs_file_nerotor =
755*8404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
756*8404SAndrew.W.Wilson@sun.com 			} else {
757*8404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
758*8404SAndrew.W.Wilson@sun.com 				    fileset->fs_file_exrotor[tid]);
759*8404SAndrew.W.Wilson@sun.com 				fileset->fs_file_exrotor[tid] =
760*8404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
7615184Sek110237 			}
762*8404SAndrew.W.Wilson@sun.com 			break;
763*8404SAndrew.W.Wilson@sun.com 
764*8404SAndrew.W.Wilson@sun.com 		case FILESET_PICKDIR:
765*8404SAndrew.W.Wilson@sun.com 			entry = fileset_find_entry(atp, fileset->fs_dirrotor);
766*8404SAndrew.W.Wilson@sun.com 			fileset->fs_dirrotor = entry->fse_index + 1;
767*8404SAndrew.W.Wilson@sun.com 			break;
768*8404SAndrew.W.Wilson@sun.com 
769*8404SAndrew.W.Wilson@sun.com 		case FILESET_PICKLEAFDIR:
770*8404SAndrew.W.Wilson@sun.com 			if (flags & FILESET_PICKNOEXIST) {
771*8404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
772*8404SAndrew.W.Wilson@sun.com 				    fileset->fs_leafdir_nerotor);
773*8404SAndrew.W.Wilson@sun.com 				fileset->fs_leafdir_nerotor =
774*8404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
775*8404SAndrew.W.Wilson@sun.com 			} else {
776*8404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
777*8404SAndrew.W.Wilson@sun.com 				    fileset->fs_leafdir_exrotor);
778*8404SAndrew.W.Wilson@sun.com 				fileset->fs_leafdir_exrotor =
779*8404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
7805184Sek110237 			}
781*8404SAndrew.W.Wilson@sun.com 			break;
782*8404SAndrew.W.Wilson@sun.com 		}
783*8404SAndrew.W.Wilson@sun.com 	}
784*8404SAndrew.W.Wilson@sun.com 
785*8404SAndrew.W.Wilson@sun.com 	if (entry == NULL)
786*8404SAndrew.W.Wilson@sun.com 		goto empty;
787*8404SAndrew.W.Wilson@sun.com 
788*8404SAndrew.W.Wilson@sun.com 	/* see if entry in use */
789*8404SAndrew.W.Wilson@sun.com 	start_point = entry;
790*8404SAndrew.W.Wilson@sun.com 	while (entry->fse_flags & FSE_BUSY) {
791*8404SAndrew.W.Wilson@sun.com 
792*8404SAndrew.W.Wilson@sun.com 		/* it is, so try next */
793*8404SAndrew.W.Wilson@sun.com 		entry = AVL_NEXT(atp, entry);
794*8404SAndrew.W.Wilson@sun.com 		if (entry == NULL)
795*8404SAndrew.W.Wilson@sun.com 			entry = avl_first(atp);
796*8404SAndrew.W.Wilson@sun.com 
797*8404SAndrew.W.Wilson@sun.com 		/* see if we have wrapped around */
798*8404SAndrew.W.Wilson@sun.com 		if ((entry == NULL) || (entry == start_point)) {
799*8404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_SCRIPT,
800*8404SAndrew.W.Wilson@sun.com 			    "All %d files are busy", avl_numnodes(atp));
801*8404SAndrew.W.Wilson@sun.com 			goto empty;
8025184Sek110237 		}
8035184Sek110237 
8045184Sek110237 	}
8055184Sek110237 
8067556SAndrew.W.Wilson@sun.com 	/* update file or directory idle counts */
8077946SAndrew.W.Wilson@sun.com 	switch (flags & FILESET_PICKMASK) {
8087946SAndrew.W.Wilson@sun.com 	case FILESET_PICKFILE:
8097946SAndrew.W.Wilson@sun.com 		fileset->fs_idle_files--;
8107946SAndrew.W.Wilson@sun.com 		break;
8117946SAndrew.W.Wilson@sun.com 	case FILESET_PICKDIR:
8127556SAndrew.W.Wilson@sun.com 		fileset->fs_idle_dirs--;
8137946SAndrew.W.Wilson@sun.com 		break;
8147946SAndrew.W.Wilson@sun.com 	case FILESET_PICKLEAFDIR:
8157946SAndrew.W.Wilson@sun.com 		fileset->fs_idle_leafdirs--;
8167946SAndrew.W.Wilson@sun.com 		break;
8177946SAndrew.W.Wilson@sun.com 	}
8187556SAndrew.W.Wilson@sun.com 
8197556SAndrew.W.Wilson@sun.com 	/* Indicate that file or directory is now busy */
8207556SAndrew.W.Wilson@sun.com 	entry->fse_flags |= FSE_BUSY;
8217556SAndrew.W.Wilson@sun.com 
8227556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
8235184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path);
8245184Sek110237 	return (entry);
8255184Sek110237 
8265184Sek110237 empty:
827*8404SAndrew.W.Wilson@sun.com 	filebench_log(LOG_DEBUG_SCRIPT, "No file found");
8287556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
8295184Sek110237 	return (NULL);
8305184Sek110237 }
8315184Sek110237 
8325184Sek110237 /*
8337556SAndrew.W.Wilson@sun.com  * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads
8347556SAndrew.W.Wilson@sun.com  * that are waiting for a NOT BUSY filesetentry. Also sets whether it is
8357556SAndrew.W.Wilson@sun.com  * existant or not, or leaves that designation alone.
8367556SAndrew.W.Wilson@sun.com  */
8377556SAndrew.W.Wilson@sun.com void
838*8404SAndrew.W.Wilson@sun.com fileset_unbusy(filesetentry_t *entry, int update_exist,
839*8404SAndrew.W.Wilson@sun.com     int new_exist_val, int open_cnt_incr)
8407556SAndrew.W.Wilson@sun.com {
8417556SAndrew.W.Wilson@sun.com 	fileset_t *fileset = NULL;
8427556SAndrew.W.Wilson@sun.com 
8437556SAndrew.W.Wilson@sun.com 	if (entry)
8447556SAndrew.W.Wilson@sun.com 		fileset = entry->fse_fileset;
8457556SAndrew.W.Wilson@sun.com 
8467556SAndrew.W.Wilson@sun.com 	if (fileset == NULL) {
8477556SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!");
8487556SAndrew.W.Wilson@sun.com 		return;
8497556SAndrew.W.Wilson@sun.com 	}
8507556SAndrew.W.Wilson@sun.com 
8517556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
8527556SAndrew.W.Wilson@sun.com 
853*8404SAndrew.W.Wilson@sun.com 	/* modify FSE_EXIST flag and actual dirs/files count, if requested */
854*8404SAndrew.W.Wilson@sun.com 	if (update_exist) {
855*8404SAndrew.W.Wilson@sun.com 		if (new_exist_val == TRUE) {
856*8404SAndrew.W.Wilson@sun.com 			if (entry->fse_flags & FSE_FREE) {
857*8404SAndrew.W.Wilson@sun.com 
858*8404SAndrew.W.Wilson@sun.com 				/* asked to set and it was free */
859*8404SAndrew.W.Wilson@sun.com 				entry->fse_flags |= FSE_EXISTS;
860*8404SAndrew.W.Wilson@sun.com 				entry->fse_flags &= (~FSE_FREE);
861*8404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
862*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
863*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
864*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_files,
865*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_files, entry);
866*8404SAndrew.W.Wilson@sun.com 					break;
867*8404SAndrew.W.Wilson@sun.com 
868*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
869*8404SAndrew.W.Wilson@sun.com 					break;
870*8404SAndrew.W.Wilson@sun.com 
871*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
872*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
873*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_leaf_dirs,
874*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_leaf_dirs,
875*8404SAndrew.W.Wilson@sun.com 					    entry);
876*8404SAndrew.W.Wilson@sun.com 					break;
877*8404SAndrew.W.Wilson@sun.com 				}
878*8404SAndrew.W.Wilson@sun.com 
879*8404SAndrew.W.Wilson@sun.com 			} else if (!(entry->fse_flags & FSE_EXISTS)) {
880*8404SAndrew.W.Wilson@sun.com 
881*8404SAndrew.W.Wilson@sun.com 				/* asked to set, and it was clear */
882*8404SAndrew.W.Wilson@sun.com 				entry->fse_flags |= FSE_EXISTS;
883*8404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
884*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
885*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
886*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_files,
887*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_files, entry);
888*8404SAndrew.W.Wilson@sun.com 					break;
889*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
890*8404SAndrew.W.Wilson@sun.com 					break;
891*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
892*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
893*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_leaf_dirs,
894*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_leaf_dirs,
895*8404SAndrew.W.Wilson@sun.com 					    entry);
896*8404SAndrew.W.Wilson@sun.com 					break;
897*8404SAndrew.W.Wilson@sun.com 				}
898*8404SAndrew.W.Wilson@sun.com 			}
899*8404SAndrew.W.Wilson@sun.com 		} else {
900*8404SAndrew.W.Wilson@sun.com 			if (entry->fse_flags & FSE_FREE) {
901*8404SAndrew.W.Wilson@sun.com 				/* asked to clear, and it was free */
902*8404SAndrew.W.Wilson@sun.com 				entry->fse_flags &= (~(FSE_FREE | FSE_EXISTS));
903*8404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
904*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
905*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
906*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_files,
907*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_files, entry);
908*8404SAndrew.W.Wilson@sun.com 					break;
909*8404SAndrew.W.Wilson@sun.com 
910*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
911*8404SAndrew.W.Wilson@sun.com 					break;
912*8404SAndrew.W.Wilson@sun.com 
913*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
914*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
915*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_leaf_dirs,
916*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_leaf_dirs,
917*8404SAndrew.W.Wilson@sun.com 					    entry);
918*8404SAndrew.W.Wilson@sun.com 					break;
919*8404SAndrew.W.Wilson@sun.com 				}
920*8404SAndrew.W.Wilson@sun.com 			} else if (entry->fse_flags & FSE_EXISTS) {
921*8404SAndrew.W.Wilson@sun.com 
922*8404SAndrew.W.Wilson@sun.com 				/* asked to clear, and it was set */
923*8404SAndrew.W.Wilson@sun.com 				entry->fse_flags &= (~FSE_EXISTS);
924*8404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
925*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
926*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
927*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_files,
928*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_files, entry);
929*8404SAndrew.W.Wilson@sun.com 					break;
930*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
931*8404SAndrew.W.Wilson@sun.com 					break;
932*8404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
933*8404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
934*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_leaf_dirs,
935*8404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_leaf_dirs,
936*8404SAndrew.W.Wilson@sun.com 					    entry);
937*8404SAndrew.W.Wilson@sun.com 					break;
938*8404SAndrew.W.Wilson@sun.com 				}
939*8404SAndrew.W.Wilson@sun.com 			}
940*8404SAndrew.W.Wilson@sun.com 		}
941*8404SAndrew.W.Wilson@sun.com 	}
942*8404SAndrew.W.Wilson@sun.com 
943*8404SAndrew.W.Wilson@sun.com 	/* update open count */
944*8404SAndrew.W.Wilson@sun.com 	entry->fse_open_cnt += open_cnt_incr;
945*8404SAndrew.W.Wilson@sun.com 
9467556SAndrew.W.Wilson@sun.com 	/* increment idle count, clear FSE_BUSY and signal IF it was busy */
9477556SAndrew.W.Wilson@sun.com 	if (entry->fse_flags & FSE_BUSY) {
9487556SAndrew.W.Wilson@sun.com 
9497556SAndrew.W.Wilson@sun.com 		/* unbusy it */
9507556SAndrew.W.Wilson@sun.com 		entry->fse_flags &= (~FSE_BUSY);
9517556SAndrew.W.Wilson@sun.com 
9527556SAndrew.W.Wilson@sun.com 		/* release any threads waiting for unbusy */
9537556SAndrew.W.Wilson@sun.com 		if (entry->fse_flags & FSE_THRD_WAITNG) {
9547556SAndrew.W.Wilson@sun.com 			entry->fse_flags &= (~FSE_THRD_WAITNG);
9557556SAndrew.W.Wilson@sun.com 			(void) pthread_cond_broadcast(
9567556SAndrew.W.Wilson@sun.com 			    &fileset->fs_thrd_wait_cv);
9577556SAndrew.W.Wilson@sun.com 		}
9587556SAndrew.W.Wilson@sun.com 
9597556SAndrew.W.Wilson@sun.com 		/* increment idle count and signal waiting threads */
9607946SAndrew.W.Wilson@sun.com 		switch (entry->fse_flags & FSE_TYPE_MASK) {
9617946SAndrew.W.Wilson@sun.com 		case FSE_TYPE_FILE:
9627946SAndrew.W.Wilson@sun.com 			fileset->fs_idle_files++;
9637946SAndrew.W.Wilson@sun.com 			if (fileset->fs_idle_files == 1) {
9647946SAndrew.W.Wilson@sun.com 				(void) pthread_cond_signal(
9657946SAndrew.W.Wilson@sun.com 				    &fileset->fs_idle_files_cv);
9667946SAndrew.W.Wilson@sun.com 			}
9677946SAndrew.W.Wilson@sun.com 			break;
968*8404SAndrew.W.Wilson@sun.com 
9697946SAndrew.W.Wilson@sun.com 		case FSE_TYPE_DIR:
9707556SAndrew.W.Wilson@sun.com 			fileset->fs_idle_dirs++;
9717556SAndrew.W.Wilson@sun.com 			if (fileset->fs_idle_dirs == 1) {
9727556SAndrew.W.Wilson@sun.com 				(void) pthread_cond_signal(
9737556SAndrew.W.Wilson@sun.com 				    &fileset->fs_idle_dirs_cv);
9747556SAndrew.W.Wilson@sun.com 			}
9757946SAndrew.W.Wilson@sun.com 			break;
976*8404SAndrew.W.Wilson@sun.com 
9777946SAndrew.W.Wilson@sun.com 		case FSE_TYPE_LEAFDIR:
9787946SAndrew.W.Wilson@sun.com 			fileset->fs_idle_leafdirs++;
9797946SAndrew.W.Wilson@sun.com 			if (fileset->fs_idle_leafdirs == 1) {
9807556SAndrew.W.Wilson@sun.com 				(void) pthread_cond_signal(
9817946SAndrew.W.Wilson@sun.com 				    &fileset->fs_idle_leafdirs_cv);
9827556SAndrew.W.Wilson@sun.com 			}
9837946SAndrew.W.Wilson@sun.com 			break;
9847556SAndrew.W.Wilson@sun.com 		}
9857556SAndrew.W.Wilson@sun.com 	}
9867556SAndrew.W.Wilson@sun.com 
9877556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
9887556SAndrew.W.Wilson@sun.com }
9897556SAndrew.W.Wilson@sun.com 
9907556SAndrew.W.Wilson@sun.com /*
9915184Sek110237  * Given a fileset "fileset", create the associated files as
9925184Sek110237  * specified in the attributes of the fileset. The fileset is
9936212Saw148015  * rooted in a directory whose pathname is in fileset_path. If the
9945184Sek110237  * directory exists, meaning that there is already a fileset,
9956212Saw148015  * and the fileset_reuse attribute is false, then remove it and all
9965184Sek110237  * its contained files and subdirectories. Next, the routine
9975184Sek110237  * creates a root directory for the fileset. All the file type
9985184Sek110237  * filesetentries are cycled through creating as needed
9995184Sek110237  * their containing subdirectory trees in the filesystem and
10006212Saw148015  * creating actual files for fileset_preallocpercent of them. The
10015184Sek110237  * created files are filled with fse_size bytes of unitialized
10027556SAndrew.W.Wilson@sun.com  * data. The routine returns FILEBENCH_ERROR on errors,
10037556SAndrew.W.Wilson@sun.com  * FILEBENCH_OK on success.
10045184Sek110237  */
10055184Sek110237 static int
10065184Sek110237 fileset_create(fileset_t *fileset)
10075184Sek110237 {
10085184Sek110237 	filesetentry_t *entry;
10095184Sek110237 	char path[MAXPATHLEN];
10105184Sek110237 	struct stat64 sb;
10115184Sek110237 	hrtime_t start = gethrtime();
10126212Saw148015 	char *fileset_path;
10136212Saw148015 	char *fileset_name;
10146212Saw148015 	int randno;
10155184Sek110237 	int preallocated = 0;
10167736SAndrew.W.Wilson@sun.com 	int reusing;
10175184Sek110237 
10186212Saw148015 	if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
10195673Saw148015 		filebench_log(LOG_ERROR, "%s path not set",
10205673Saw148015 		    fileset_entity_name(fileset));
10217556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
10225184Sek110237 	}
10235184Sek110237 
10246212Saw148015 	if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
10256212Saw148015 		filebench_log(LOG_ERROR, "%s name not set",
10266212Saw148015 		    fileset_entity_name(fileset));
10277556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
10286212Saw148015 	}
10296212Saw148015 
10305673Saw148015 #ifdef HAVE_RAW_SUPPORT
10315673Saw148015 	/* treat raw device as special case */
10325673Saw148015 	if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
10337556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
10345673Saw148015 #endif /* HAVE_RAW_SUPPORT */
10355673Saw148015 
10365184Sek110237 	/* XXX Add check to see if there is enough space */
10375184Sek110237 
10387736SAndrew.W.Wilson@sun.com 	/* set up path to fileset */
10397946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
10407946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
10417946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, fileset_name, MAXPATHLEN);
10427736SAndrew.W.Wilson@sun.com 
10437736SAndrew.W.Wilson@sun.com 	/* if exists and resusing, then don't create new */
10447736SAndrew.W.Wilson@sun.com 	if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) &&
10457736SAndrew.W.Wilson@sun.com 	    (strlen(avd_get_str(fileset->fs_path)) > 2)) &&
10467736SAndrew.W.Wilson@sun.com 	    avd_get_bool(fileset->fs_reuse)) {
10477736SAndrew.W.Wilson@sun.com 		reusing = 1;
10487736SAndrew.W.Wilson@sun.com 	} else {
10497736SAndrew.W.Wilson@sun.com 		reusing = 0;
10507736SAndrew.W.Wilson@sun.com 	}
10517736SAndrew.W.Wilson@sun.com 
10527736SAndrew.W.Wilson@sun.com 	if (!reusing) {
10537736SAndrew.W.Wilson@sun.com 		char cmd[MAXPATHLEN];
10545184Sek110237 
10557736SAndrew.W.Wilson@sun.com 		/* Remove existing */
10567736SAndrew.W.Wilson@sun.com 		(void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path);
10577736SAndrew.W.Wilson@sun.com 		(void) system(cmd);
10587736SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE,
10597736SAndrew.W.Wilson@sun.com 		    "Removed any existing %s %s in %llu seconds",
10607736SAndrew.W.Wilson@sun.com 		    fileset_entity_name(fileset), fileset_name,
10617736SAndrew.W.Wilson@sun.com 		    (u_longlong_t)(((gethrtime() - start) /
10627736SAndrew.W.Wilson@sun.com 		    1000000000) + 1));
10637736SAndrew.W.Wilson@sun.com 	} else {
10647736SAndrew.W.Wilson@sun.com 		/* we are re-using */
10657736SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE, "Re-using %s %s.",
10667736SAndrew.W.Wilson@sun.com 		    fileset_entity_name(fileset), fileset_name);
10675184Sek110237 	}
10687736SAndrew.W.Wilson@sun.com 
10697736SAndrew.W.Wilson@sun.com 	/* make the filesets directory tree unless in reuse mode */
10707736SAndrew.W.Wilson@sun.com 	if (!reusing && (avd_get_bool(fileset->fs_prealloc))) {
10717946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE,
10727736SAndrew.W.Wilson@sun.com 		    "making tree for filset %s", path);
10735184Sek110237 
10747736SAndrew.W.Wilson@sun.com 		(void) mkdir(path, 0755);
10757736SAndrew.W.Wilson@sun.com 
10767736SAndrew.W.Wilson@sun.com 		if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR)
10777736SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
10787736SAndrew.W.Wilson@sun.com 	}
10795673Saw148015 
10805184Sek110237 	start = gethrtime();
10815184Sek110237 
10825673Saw148015 	filebench_log(LOG_VERBOSE, "Creating %s %s...",
10836212Saw148015 	    fileset_entity_name(fileset), fileset_name);
10845673Saw148015 
10856212Saw148015 	randno = ((RAND_MAX * (100
10866212Saw148015 	    - avd_get_int(fileset->fs_preallocpercent))) / 100);
10876212Saw148015 
10887946SAndrew.W.Wilson@sun.com 	/* alloc any files, as required */
1089*8404SAndrew.W.Wilson@sun.com 	fileset_pickreset(fileset, FILESET_PICKFILE);
1090*8404SAndrew.W.Wilson@sun.com 	while (entry = fileset_pick(fileset,
1091*8404SAndrew.W.Wilson@sun.com 	    FILESET_PICKFREE | FILESET_PICKFILE, 0, 0)) {
10925673Saw148015 		pthread_t tid;
10937736SAndrew.W.Wilson@sun.com 		int newrand;
10945184Sek110237 
10957736SAndrew.W.Wilson@sun.com 		newrand = rand();
10967736SAndrew.W.Wilson@sun.com 
1097*8404SAndrew.W.Wilson@sun.com 		if (newrand < randno) {
1098*8404SAndrew.W.Wilson@sun.com 			/* unbusy the unallocated entry */
1099*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
11005184Sek110237 			continue;
1101*8404SAndrew.W.Wilson@sun.com 		}
11025184Sek110237 
11035184Sek110237 		preallocated++;
11045184Sek110237 
11055673Saw148015 		if (reusing)
11065673Saw148015 			entry->fse_flags |= FSE_REUSING;
11075673Saw148015 		else
11085673Saw148015 			entry->fse_flags &= (~FSE_REUSING);
11095673Saw148015 
11107556SAndrew.W.Wilson@sun.com 		/* fire off allocation threads for each file if paralloc set */
11116212Saw148015 		if (avd_get_bool(fileset->fs_paralloc)) {
11125184Sek110237 
11137556SAndrew.W.Wilson@sun.com 			/* limit total number of simultaneous allocations */
11147556SAndrew.W.Wilson@sun.com 			(void) pthread_mutex_lock(
11157556SAndrew.W.Wilson@sun.com 			    &filebench_shm->shm_fsparalloc_lock);
11167556SAndrew.W.Wilson@sun.com 			while (filebench_shm->shm_fsparalloc_count
11177556SAndrew.W.Wilson@sun.com 			    >= MAX_PARALLOC_THREADS) {
11185673Saw148015 				(void) pthread_cond_wait(
11197556SAndrew.W.Wilson@sun.com 				    &filebench_shm->shm_fsparalloc_cv,
11207556SAndrew.W.Wilson@sun.com 				    &filebench_shm->shm_fsparalloc_lock);
11215673Saw148015 			}
11225673Saw148015 
11237556SAndrew.W.Wilson@sun.com 			/* quit if any allocation thread reports and error */
11247556SAndrew.W.Wilson@sun.com 			if (filebench_shm->shm_fsparalloc_count < 0) {
11257556SAndrew.W.Wilson@sun.com 				(void) pthread_mutex_unlock(
11267556SAndrew.W.Wilson@sun.com 				    &filebench_shm->shm_fsparalloc_lock);
11277556SAndrew.W.Wilson@sun.com 				return (FILEBENCH_ERROR);
11285184Sek110237 			}
11295184Sek110237 
11307556SAndrew.W.Wilson@sun.com 			filebench_shm->shm_fsparalloc_count++;
11317556SAndrew.W.Wilson@sun.com 			(void) pthread_mutex_unlock(
11327556SAndrew.W.Wilson@sun.com 			    &filebench_shm->shm_fsparalloc_lock);
11335184Sek110237 
11347556SAndrew.W.Wilson@sun.com 			/*
11357556SAndrew.W.Wilson@sun.com 			 * Fire off a detached allocation thread per file.
11367556SAndrew.W.Wilson@sun.com 			 * The thread will self destruct when it finishes
11377556SAndrew.W.Wilson@sun.com 			 * writing pre-allocation data to the file.
11387556SAndrew.W.Wilson@sun.com 			 */
11395673Saw148015 			if (pthread_create(&tid, NULL,
11405673Saw148015 			    (void *(*)(void*))fileset_alloc_thread,
11417556SAndrew.W.Wilson@sun.com 			    entry) == 0) {
11427556SAndrew.W.Wilson@sun.com 				/*
11437556SAndrew.W.Wilson@sun.com 				 * A thread was created; detach it so it can
11447556SAndrew.W.Wilson@sun.com 				 * fully quit when finished.
11457556SAndrew.W.Wilson@sun.com 				 */
11467556SAndrew.W.Wilson@sun.com 				(void) pthread_detach(tid);
11477556SAndrew.W.Wilson@sun.com 			} else {
11485184Sek110237 				filebench_log(LOG_ERROR,
11495673Saw148015 				    "File prealloc thread create failed");
11505673Saw148015 				filebench_shutdown(1);
11515184Sek110237 			}
11525184Sek110237 
11535673Saw148015 		} else {
11547556SAndrew.W.Wilson@sun.com 			if (fileset_alloc_file(entry) == FILEBENCH_ERROR)
11557556SAndrew.W.Wilson@sun.com 				return (FILEBENCH_ERROR);
11565673Saw148015 		}
11575673Saw148015 	}
11585184Sek110237 
11597946SAndrew.W.Wilson@sun.com 	/* alloc any leaf directories, as required */
1160*8404SAndrew.W.Wilson@sun.com 	fileset_pickreset(fileset, FILESET_PICKLEAFDIR);
1161*8404SAndrew.W.Wilson@sun.com 	while (entry = fileset_pick(fileset,
1162*8404SAndrew.W.Wilson@sun.com 	    FILESET_PICKFREE | FILESET_PICKLEAFDIR, 0, 0)) {
11637946SAndrew.W.Wilson@sun.com 
1164*8404SAndrew.W.Wilson@sun.com 		if (rand() < randno) {
1165*8404SAndrew.W.Wilson@sun.com 			/* unbusy the unallocated entry */
1166*8404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
11677946SAndrew.W.Wilson@sun.com 			continue;
1168*8404SAndrew.W.Wilson@sun.com 		}
11697946SAndrew.W.Wilson@sun.com 
11707946SAndrew.W.Wilson@sun.com 		preallocated++;
11717946SAndrew.W.Wilson@sun.com 
11727946SAndrew.W.Wilson@sun.com 		if (reusing)
11737946SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_REUSING;
11747946SAndrew.W.Wilson@sun.com 		else
11757946SAndrew.W.Wilson@sun.com 			entry->fse_flags &= (~FSE_REUSING);
11767946SAndrew.W.Wilson@sun.com 
11777946SAndrew.W.Wilson@sun.com 		if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR)
11787946SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
11797946SAndrew.W.Wilson@sun.com 	}
11807946SAndrew.W.Wilson@sun.com 
11815673Saw148015 exit:
11825184Sek110237 	filebench_log(LOG_VERBOSE,
11836286Saw148015 	    "Preallocated %d of %llu of %s %s in %llu seconds",
11845184Sek110237 	    preallocated,
11856286Saw148015 	    (u_longlong_t)fileset->fs_constentries,
11866212Saw148015 	    fileset_entity_name(fileset), fileset_name,
11876286Saw148015 	    (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1));
11885184Sek110237 
11897556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
11905184Sek110237 }
11915184Sek110237 
11925184Sek110237 /*
11935184Sek110237  * Adds an entry to the fileset's file list. Single threaded so
11945184Sek110237  * no locking needed.
11955184Sek110237  */
11965184Sek110237 static void
11975184Sek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry)
11985184Sek110237 {
1199*8404SAndrew.W.Wilson@sun.com 	entry->fse_flags = FSE_TYPE_FILE | FSE_FREE;
1200*8404SAndrew.W.Wilson@sun.com 	avl_add(&fileset->fs_free_files, entry);
1201*8404SAndrew.W.Wilson@sun.com 
12025184Sek110237 	if (fileset->fs_filelist == NULL) {
12035184Sek110237 		fileset->fs_filelist = entry;
1204*8404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = NULL;
12055184Sek110237 	} else {
1206*8404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = fileset->fs_filelist;
12075184Sek110237 		fileset->fs_filelist = entry;
12085184Sek110237 	}
12095184Sek110237 }
12105184Sek110237 
12115184Sek110237 /*
12125184Sek110237  * Adds an entry to the fileset's directory list. Single
12135184Sek110237  * threaded so no locking needed.
12145184Sek110237  */
12155184Sek110237 static void
12165184Sek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry)
12175184Sek110237 {
1218*8404SAndrew.W.Wilson@sun.com 	entry->fse_flags = FSE_TYPE_DIR | FSE_EXISTS;
1219*8404SAndrew.W.Wilson@sun.com 	avl_add(&fileset->fs_dirs, entry);
1220*8404SAndrew.W.Wilson@sun.com 
12215184Sek110237 	if (fileset->fs_dirlist == NULL) {
12225184Sek110237 		fileset->fs_dirlist = entry;
1223*8404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = NULL;
12245184Sek110237 	} else {
1225*8404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = fileset->fs_dirlist;
12265184Sek110237 		fileset->fs_dirlist = entry;
12275184Sek110237 	}
12285184Sek110237 }
12295184Sek110237 
12305184Sek110237 /*
12317946SAndrew.W.Wilson@sun.com  * Adds an entry to the fileset's leaf directory list. Single
12327946SAndrew.W.Wilson@sun.com  * threaded so no locking needed.
12337946SAndrew.W.Wilson@sun.com  */
12347946SAndrew.W.Wilson@sun.com static void
12357946SAndrew.W.Wilson@sun.com fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry)
12367946SAndrew.W.Wilson@sun.com {
1237*8404SAndrew.W.Wilson@sun.com 	entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE;
1238*8404SAndrew.W.Wilson@sun.com 	avl_add(&fileset->fs_free_leaf_dirs, entry);
1239*8404SAndrew.W.Wilson@sun.com 
12407946SAndrew.W.Wilson@sun.com 	if (fileset->fs_leafdirlist == NULL) {
12417946SAndrew.W.Wilson@sun.com 		fileset->fs_leafdirlist = entry;
1242*8404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = NULL;
12437946SAndrew.W.Wilson@sun.com 	} else {
1244*8404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = fileset->fs_leafdirlist;
12457946SAndrew.W.Wilson@sun.com 		fileset->fs_leafdirlist = entry;
12467946SAndrew.W.Wilson@sun.com 	}
12477946SAndrew.W.Wilson@sun.com }
12487946SAndrew.W.Wilson@sun.com 
12497946SAndrew.W.Wilson@sun.com /*
1250*8404SAndrew.W.Wilson@sun.com  * Compares two fileset entries to determine their relative order
1251*8404SAndrew.W.Wilson@sun.com  */
1252*8404SAndrew.W.Wilson@sun.com static int
1253*8404SAndrew.W.Wilson@sun.com fileset_entry_compare(const void *node_1, const void *node_2)
1254*8404SAndrew.W.Wilson@sun.com {
1255*8404SAndrew.W.Wilson@sun.com 	if (((filesetentry_t *)node_1)->fse_index <
1256*8404SAndrew.W.Wilson@sun.com 	    ((filesetentry_t *)node_2)->fse_index)
1257*8404SAndrew.W.Wilson@sun.com 		return (-1);
1258*8404SAndrew.W.Wilson@sun.com 
1259*8404SAndrew.W.Wilson@sun.com 	if (((filesetentry_t *)node_1)->fse_index ==
1260*8404SAndrew.W.Wilson@sun.com 	    ((filesetentry_t *)node_2)->fse_index)
1261*8404SAndrew.W.Wilson@sun.com 		return (0);
1262*8404SAndrew.W.Wilson@sun.com 
1263*8404SAndrew.W.Wilson@sun.com 	return (1);
1264*8404SAndrew.W.Wilson@sun.com }
1265*8404SAndrew.W.Wilson@sun.com 
1266*8404SAndrew.W.Wilson@sun.com /*
12677946SAndrew.W.Wilson@sun.com  * Obtains a filesetentry entity for a file to be placed in a
12685184Sek110237  * (sub)directory of a fileset. The size of the file may be
12696212Saw148015  * specified by fileset_meansize, or calculated from a gamma
12706212Saw148015  * distribution of parameter fileset_sizegamma and of mean size
12716212Saw148015  * fileset_meansize. The filesetentry entity is placed on the file
12725184Sek110237  * list in the specified parent filesetentry entity, which may
12735184Sek110237  * be a directory filesetentry, or the root filesetentry in the
12745184Sek110237  * fileset. It is also placed on the fileset's list of all
12757556SAndrew.W.Wilson@sun.com  * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR
12767556SAndrew.W.Wilson@sun.com  * if ipc memory for the path string cannot be allocated.
12775184Sek110237  */
12785184Sek110237 static int
12795184Sek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
12805184Sek110237 {
12815184Sek110237 	char tmpname[16];
12825184Sek110237 	filesetentry_t *entry;
12835184Sek110237 	double drand;
1284*8404SAndrew.W.Wilson@sun.com 	uint_t index;
12855184Sek110237 
12865184Sek110237 	if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
12875184Sek110237 	    == NULL) {
12885184Sek110237 		filebench_log(LOG_ERROR,
12895184Sek110237 		    "fileset_populate_file: Can't malloc filesetentry");
12907556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
12915184Sek110237 	}
12925184Sek110237 
12937556SAndrew.W.Wilson@sun.com 	/* Another currently idle file */
12947556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
1295*8404SAndrew.W.Wilson@sun.com 	index = fileset->fs_idle_files++;
12967556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
12977556SAndrew.W.Wilson@sun.com 
1298*8404SAndrew.W.Wilson@sun.com 	entry->fse_index = index;
12995184Sek110237 	entry->fse_parent = parent;
13005184Sek110237 	entry->fse_fileset = fileset;
13015184Sek110237 	fileset_insfilelist(fileset, entry);
13025184Sek110237 
13035184Sek110237 	(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
13045184Sek110237 	if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
13055184Sek110237 		filebench_log(LOG_ERROR,
13065184Sek110237 		    "fileset_populate_file: Can't alloc path string");
13077556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13085184Sek110237 	}
13095184Sek110237 
13106212Saw148015 	/* see if random variable was supplied for file size */
13116212Saw148015 	if (fileset->fs_meansize == -1) {
13126212Saw148015 		entry->fse_size = (off64_t)avd_get_int(fileset->fs_size);
13136212Saw148015 	} else {
13146212Saw148015 		double gamma;
13155184Sek110237 
13166212Saw148015 		gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0;
13176212Saw148015 		if (gamma > 0) {
13186212Saw148015 			drand = gamma_dist_knuth(gamma,
13196212Saw148015 			    fileset->fs_meansize / gamma);
13206212Saw148015 			entry->fse_size = (off64_t)drand;
13216212Saw148015 		} else {
13226212Saw148015 			entry->fse_size = (off64_t)fileset->fs_meansize;
13236212Saw148015 		}
13245184Sek110237 	}
13255184Sek110237 
13265184Sek110237 	fileset->fs_bytes += entry->fse_size;
13275184Sek110237 
13285184Sek110237 	fileset->fs_realfiles++;
13297556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
13305184Sek110237 }
13315184Sek110237 
13325184Sek110237 /*
13337946SAndrew.W.Wilson@sun.com  * Obtaines a filesetentry entity for a leaf directory to be placed in a
13347946SAndrew.W.Wilson@sun.com  * (sub)directory of a fileset. The leaf directory will always be empty so
13357946SAndrew.W.Wilson@sun.com  * it can be created and deleted (mkdir, rmdir) at will. The filesetentry
13367946SAndrew.W.Wilson@sun.com  * entity is placed on the leaf directory list in the specified parent
13377946SAndrew.W.Wilson@sun.com  * filesetentry entity, which may be a (sub) directory filesetentry, or
13387946SAndrew.W.Wilson@sun.com  * the root filesetentry in the fileset. It is also placed on the fileset's
13397946SAndrew.W.Wilson@sun.com  * list of all contained leaf directories. Returns FILEBENCH_OK if successful
13407946SAndrew.W.Wilson@sun.com  * or FILEBENCH_ERROR if ipc memory cannot be allocated.
13417946SAndrew.W.Wilson@sun.com  */
13427946SAndrew.W.Wilson@sun.com static int
13437946SAndrew.W.Wilson@sun.com fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial)
13447946SAndrew.W.Wilson@sun.com {
13457946SAndrew.W.Wilson@sun.com 	char tmpname[16];
13467946SAndrew.W.Wilson@sun.com 	filesetentry_t *entry;
1347*8404SAndrew.W.Wilson@sun.com 	uint_t index;
13487946SAndrew.W.Wilson@sun.com 
13497946SAndrew.W.Wilson@sun.com 	if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
13507946SAndrew.W.Wilson@sun.com 	    == NULL) {
13517946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
13527946SAndrew.W.Wilson@sun.com 		    "fileset_populate_file: Can't malloc filesetentry");
13537946SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13547946SAndrew.W.Wilson@sun.com 	}
13557946SAndrew.W.Wilson@sun.com 
13567946SAndrew.W.Wilson@sun.com 	/* Another currently idle leaf directory */
13577946SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
1358*8404SAndrew.W.Wilson@sun.com 	index = fileset->fs_idle_leafdirs++;
13597946SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
13607946SAndrew.W.Wilson@sun.com 
1361*8404SAndrew.W.Wilson@sun.com 	entry->fse_index = index;
13627946SAndrew.W.Wilson@sun.com 	entry->fse_parent = parent;
13637946SAndrew.W.Wilson@sun.com 	entry->fse_fileset = fileset;
13647946SAndrew.W.Wilson@sun.com 	fileset_insleafdirlist(fileset, entry);
13657946SAndrew.W.Wilson@sun.com 
13667946SAndrew.W.Wilson@sun.com 	(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
13677946SAndrew.W.Wilson@sun.com 	if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
13687946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
13697946SAndrew.W.Wilson@sun.com 		    "fileset_populate_file: Can't alloc path string");
13707946SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13717946SAndrew.W.Wilson@sun.com 	}
13727946SAndrew.W.Wilson@sun.com 
13737946SAndrew.W.Wilson@sun.com 	fileset->fs_realleafdirs++;
13747946SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
13757946SAndrew.W.Wilson@sun.com }
13767946SAndrew.W.Wilson@sun.com 
13777946SAndrew.W.Wilson@sun.com /*
13785184Sek110237  * Creates a directory node in a fileset, by obtaining a
13795184Sek110237  * filesetentry entity for the node and initializing it
13805184Sek110237  * according to parameters of the fileset. It determines a
13815184Sek110237  * directory tree depth and directory width, optionally using
13825184Sek110237  * a gamma distribution. If its calculated depth is less then
13835184Sek110237  * its actual depth in the directory tree, it becomes a leaf
13845184Sek110237  * node and files itself with "width" number of file type
13855184Sek110237  * filesetentries, otherwise it files itself with "width"
13865184Sek110237  * number of directory type filesetentries, using recursive
13875184Sek110237  * calls to fileset_populate_subdir. The end result of the
13885184Sek110237  * initial call to this routine is a tree of directories of
13895184Sek110237  * random width and varying depth with sufficient leaf
13905184Sek110237  * directories to contain all required files.
13917556SAndrew.W.Wilson@sun.com  * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path
13927556SAndrew.W.Wilson@sun.com  * string memory cannot be allocated and returns the error code (currently
13937556SAndrew.W.Wilson@sun.com  * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive
13945184Sek110237  * calls to fileset_populate_subdir.
13955184Sek110237  */
13965184Sek110237 static int
13975184Sek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
13985184Sek110237     int serial, double depth)
13995184Sek110237 {
14006212Saw148015 	double randepth, drand, ranwidth;
14015184Sek110237 	int isleaf = 0;
14025184Sek110237 	char tmpname[16];
14035184Sek110237 	filesetentry_t *entry;
14045184Sek110237 	int i;
1405*8404SAndrew.W.Wilson@sun.com 	uint_t index;
14065184Sek110237 
14075184Sek110237 	depth += 1;
14085184Sek110237 
14095184Sek110237 	/* Create dir node */
14105184Sek110237 	if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
14115184Sek110237 	    == NULL) {
14125184Sek110237 		filebench_log(LOG_ERROR,
14135184Sek110237 		    "fileset_populate_subdir: Can't malloc filesetentry");
14147556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
14155184Sek110237 	}
14165184Sek110237 
14177556SAndrew.W.Wilson@sun.com 	/* another idle directory */
14187556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
1419*8404SAndrew.W.Wilson@sun.com 	index = fileset->fs_idle_dirs++;
14207556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
14215184Sek110237 
14225184Sek110237 	(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
14235184Sek110237 	if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
14245184Sek110237 		filebench_log(LOG_ERROR,
14255184Sek110237 		    "fileset_populate_subdir: Can't alloc path string");
14267556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
14275184Sek110237 	}
14285184Sek110237 
1429*8404SAndrew.W.Wilson@sun.com 	entry->fse_index = index;
14305184Sek110237 	entry->fse_parent = parent;
14317946SAndrew.W.Wilson@sun.com 	entry->fse_fileset = fileset;
14325184Sek110237 	fileset_insdirlist(fileset, entry);
14335184Sek110237 
14346212Saw148015 	if (fileset->fs_dirdepthrv) {
14356212Saw148015 		randepth = (int)avd_get_int(fileset->fs_dirdepthrv);
14365184Sek110237 	} else {
14376212Saw148015 		double gamma;
14386212Saw148015 
14396212Saw148015 		gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0;
14406212Saw148015 		if (gamma > 0) {
14416212Saw148015 			drand = gamma_dist_knuth(gamma,
14426212Saw148015 			    fileset->fs_meandepth / gamma);
14436212Saw148015 			randepth = (int)drand;
14446212Saw148015 		} else {
14456212Saw148015 			randepth = (int)fileset->fs_meandepth;
14466212Saw148015 		}
14475184Sek110237 	}
14485184Sek110237 
14496212Saw148015 	if (fileset->fs_meanwidth == -1) {
14506212Saw148015 		ranwidth = avd_get_dbl(fileset->fs_dirwidth);
14516212Saw148015 	} else {
14526212Saw148015 		double gamma;
14535184Sek110237 
14546212Saw148015 		gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0;
14556212Saw148015 		if (gamma > 0) {
14566212Saw148015 			drand = gamma_dist_knuth(gamma,
14576212Saw148015 			    fileset->fs_meanwidth / gamma);
14586212Saw148015 			ranwidth = drand;
14596212Saw148015 		} else {
14606212Saw148015 			ranwidth = fileset->fs_meanwidth;
14616212Saw148015 		}
14625184Sek110237 	}
14635184Sek110237 
14645184Sek110237 	if (randepth == 0)
14655184Sek110237 		randepth = 1;
14665184Sek110237 	if (ranwidth == 0)
14675184Sek110237 		ranwidth = 1;
14685184Sek110237 	if (depth >= randepth)
14695184Sek110237 		isleaf = 1;
14705184Sek110237 
14715184Sek110237 	/*
14727946SAndrew.W.Wilson@sun.com 	 * Create directory of random width filled with files according
14737946SAndrew.W.Wilson@sun.com 	 * to distribution, or if root directory, continue until #files required
14745184Sek110237 	 */
14756212Saw148015 	for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
14766212Saw148015 	    (fileset->fs_realfiles < fileset->fs_constentries);
14776212Saw148015 	    i++) {
14785184Sek110237 		int ret = 0;
14795184Sek110237 
14805184Sek110237 		if (parent && isleaf)
14815184Sek110237 			ret = fileset_populate_file(fileset, entry, i);
14825184Sek110237 		else
14835184Sek110237 			ret = fileset_populate_subdir(fileset, entry, i, depth);
14845184Sek110237 
14855184Sek110237 		if (ret != 0)
14865184Sek110237 			return (ret);
14875184Sek110237 	}
14887946SAndrew.W.Wilson@sun.com 
14897946SAndrew.W.Wilson@sun.com 	/*
14907946SAndrew.W.Wilson@sun.com 	 * Create directory of random width filled with leaf directories
14917946SAndrew.W.Wilson@sun.com 	 * according to distribution, or if root directory, continue until
14927946SAndrew.W.Wilson@sun.com 	 * the number of leaf directories required has been generated.
14937946SAndrew.W.Wilson@sun.com 	 */
14947946SAndrew.W.Wilson@sun.com 	for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
14957946SAndrew.W.Wilson@sun.com 	    (fileset->fs_realleafdirs < fileset->fs_constleafdirs);
14967946SAndrew.W.Wilson@sun.com 	    i++) {
14977946SAndrew.W.Wilson@sun.com 		int ret = 0;
14987946SAndrew.W.Wilson@sun.com 
14997946SAndrew.W.Wilson@sun.com 		if (parent && isleaf)
15007946SAndrew.W.Wilson@sun.com 			ret = fileset_populate_leafdir(fileset, entry, i);
15017946SAndrew.W.Wilson@sun.com 		else
15027946SAndrew.W.Wilson@sun.com 			ret = fileset_populate_subdir(fileset, entry, i, depth);
15037946SAndrew.W.Wilson@sun.com 
15047946SAndrew.W.Wilson@sun.com 		if (ret != 0)
15057946SAndrew.W.Wilson@sun.com 			return (ret);
15067946SAndrew.W.Wilson@sun.com 	}
15077946SAndrew.W.Wilson@sun.com 
15087556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
15095184Sek110237 }
15105184Sek110237 
15115184Sek110237 /*
15125184Sek110237  * Populates a fileset with files and subdirectory entries. Uses
15136212Saw148015  * the supplied fileset_dirwidth and fileset_entries (number of files) to
15146212Saw148015  * calculate the required fileset_meandepth (of subdirectories) and
15156212Saw148015  * initialize the fileset_meanwidth and fileset_meansize variables. Then
15165184Sek110237  * calls fileset_populate_subdir() to do the recursive
15175184Sek110237  * subdirectory entry creation and leaf file entry creation. All
15185184Sek110237  * of the above is skipped if the fileset has already been
15195184Sek110237  * populated. Returns 0 on success, or an error code from the
15205184Sek110237  * call to fileset_populate_subdir if that call fails.
15215184Sek110237  */
15225184Sek110237 static int
15235184Sek110237 fileset_populate(fileset_t *fileset)
15245184Sek110237 {
1525*8404SAndrew.W.Wilson@sun.com 	fbint_t entries = avd_get_int(fileset->fs_entries);
1526*8404SAndrew.W.Wilson@sun.com 	fbint_t leafdirs = avd_get_int(fileset->fs_leafdirs);
15276212Saw148015 	int meandirwidth;
15285184Sek110237 	int ret;
15295184Sek110237 
15305184Sek110237 	/* Skip if already populated */
15315184Sek110237 	if (fileset->fs_bytes > 0)
15325184Sek110237 		goto exists;
15335184Sek110237 
15345673Saw148015 #ifdef HAVE_RAW_SUPPORT
15355673Saw148015 	/* check for raw device */
15365673Saw148015 	if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
15377556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
15385673Saw148015 #endif /* HAVE_RAW_SUPPORT */
15395673Saw148015 
15407946SAndrew.W.Wilson@sun.com 	/*
15417946SAndrew.W.Wilson@sun.com 	 * save value of entries and leaf dirs obtained for later
15427946SAndrew.W.Wilson@sun.com 	 * in case it was random
15437946SAndrew.W.Wilson@sun.com 	 */
15446212Saw148015 	fileset->fs_constentries = entries;
15457946SAndrew.W.Wilson@sun.com 	fileset->fs_constleafdirs = leafdirs;
15466212Saw148015 
15477556SAndrew.W.Wilson@sun.com 	/* initialize idle files and directories condition variables */
15487946SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr());
15497556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr());
15507946SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr());
15517556SAndrew.W.Wilson@sun.com 
15527556SAndrew.W.Wilson@sun.com 	/* no files or dirs idle (or busy) yet */
15537556SAndrew.W.Wilson@sun.com 	fileset->fs_idle_files = 0;
15547556SAndrew.W.Wilson@sun.com 	fileset->fs_idle_dirs = 0;
15557946SAndrew.W.Wilson@sun.com 	fileset->fs_idle_leafdirs = 0;
15567556SAndrew.W.Wilson@sun.com 
15577556SAndrew.W.Wilson@sun.com 	/* initialize locks and other condition variables */
15587556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_init(&fileset->fs_pick_lock,
15597556SAndrew.W.Wilson@sun.com 	    ipc_mutexattr(IPC_MUTEX_NORMAL));
1560*8404SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_init(&fileset->fs_histo_lock,
1561*8404SAndrew.W.Wilson@sun.com 	    ipc_mutexattr(IPC_MUTEX_NORMAL));
15627556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr());
15637556SAndrew.W.Wilson@sun.com 
1564*8404SAndrew.W.Wilson@sun.com 	/* Initialize avl btrees */
1565*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_free_files), fileset_entry_compare,
1566*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1567*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_noex_files), fileset_entry_compare,
1568*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1569*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_exist_files), fileset_entry_compare,
1570*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1571*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_free_leaf_dirs), fileset_entry_compare,
1572*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1573*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_noex_leaf_dirs), fileset_entry_compare,
1574*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1575*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_exist_leaf_dirs), fileset_entry_compare,
1576*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1577*8404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_dirs), fileset_entry_compare,
1578*8404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
1579*8404SAndrew.W.Wilson@sun.com 
15806212Saw148015 	/* is dirwidth a random variable? */
15816212Saw148015 	if (AVD_IS_RANDOM(fileset->fs_dirwidth)) {
15826212Saw148015 		meandirwidth =
15836212Saw148015 		    (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean;
15846212Saw148015 		fileset->fs_meanwidth = -1;
15856212Saw148015 	} else {
15866212Saw148015 		meandirwidth = (int)avd_get_int(fileset->fs_dirwidth);
15876212Saw148015 		fileset->fs_meanwidth = (double)meandirwidth;
15886212Saw148015 	}
15896212Saw148015 
15905184Sek110237 	/*
15915184Sek110237 	 * Input params are:
15925184Sek110237 	 *	# of files
15935184Sek110237 	 *	ave # of files per dir
15945184Sek110237 	 *	max size of dir
15955184Sek110237 	 *	# ave size of file
15965184Sek110237 	 *	max size of file
15975184Sek110237 	 */
15987946SAndrew.W.Wilson@sun.com 	fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth);
15996212Saw148015 
16006212Saw148015 	/* Has a random variable been supplied for dirdepth? */
16016212Saw148015 	if (fileset->fs_dirdepthrv) {
16026212Saw148015 		/* yes, so set the random variable's mean value to meandepth */
16036212Saw148015 		fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean =
16046212Saw148015 		    fileset->fs_meandepth;
16056212Saw148015 	}
16066212Saw148015 
16076212Saw148015 	/* test for random size variable */
16086212Saw148015 	if (AVD_IS_RANDOM(fileset->fs_size))
16096212Saw148015 		fileset->fs_meansize = -1;
16106212Saw148015 	else
16116212Saw148015 		fileset->fs_meansize = avd_get_int(fileset->fs_size);
16125184Sek110237 
16135184Sek110237 	if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0)
16145184Sek110237 		return (ret);
16155184Sek110237 
16165184Sek110237 
16175184Sek110237 exists:
16185673Saw148015 	if (fileset->fs_attrs & FILESET_IS_FILE) {
16196286Saw148015 		filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu",
16206212Saw148015 		    avd_get_str(fileset->fs_name),
16216286Saw148015 		    (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
16225673Saw148015 	} else {
16237946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs "
16246286Saw148015 		    "avg dir = %d, avg depth = %.1lf, mbytes=%llu",
16257946SAndrew.W.Wilson@sun.com 		    avd_get_str(fileset->fs_name), entries, leafdirs,
16266212Saw148015 		    meandirwidth,
16275673Saw148015 		    fileset->fs_meandepth,
16286286Saw148015 		    (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
16295673Saw148015 	}
16306701Saw148015 
16317556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
16325184Sek110237 }
16335184Sek110237 
16345184Sek110237 /*
16356212Saw148015  * Allocates a fileset instance, initializes fileset_dirgamma and
16366212Saw148015  * fileset_sizegamma default values, and sets the fileset name to the
16375184Sek110237  * supplied name string. Puts the allocated fileset on the
16385184Sek110237  * master fileset list and returns a pointer to it.
16396701Saw148015  *
16406701Saw148015  * This routine implements the 'define fileset' calls found in a .f
16416701Saw148015  * workload, such as in the following example:
16426701Saw148015  * define fileset name=drew4ever, entries=$nfiles
16435184Sek110237  */
16445184Sek110237 fileset_t *
16456212Saw148015 fileset_define(avd_t name)
16465184Sek110237 {
16475184Sek110237 	fileset_t *fileset;
16485184Sek110237 
16495184Sek110237 	if (name == NULL)
16505184Sek110237 		return (NULL);
16515184Sek110237 
16525184Sek110237 	if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) {
16535184Sek110237 		filebench_log(LOG_ERROR,
16545184Sek110237 		    "fileset_define: Can't malloc fileset");
16555184Sek110237 		return (NULL);
16565184Sek110237 	}
16575184Sek110237 
16586212Saw148015 	filebench_log(LOG_DEBUG_IMPL,
16596212Saw148015 	    "Defining file %s", avd_get_str(name));
16605184Sek110237 
16616391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
16625184Sek110237 
16636212Saw148015 	fileset->fs_dirgamma = avd_int_alloc(1500);
16646212Saw148015 	fileset->fs_sizegamma = avd_int_alloc(1500);
1665*8404SAndrew.W.Wilson@sun.com 	fileset->fs_histo_id = -1;
16665184Sek110237 
16675184Sek110237 	/* Add fileset to global list */
16686391Saw148015 	if (filebench_shm->shm_filesetlist == NULL) {
16696391Saw148015 		filebench_shm->shm_filesetlist = fileset;
16705184Sek110237 		fileset->fs_next = NULL;
16715184Sek110237 	} else {
16726391Saw148015 		fileset->fs_next = filebench_shm->shm_filesetlist;
16736391Saw148015 		filebench_shm->shm_filesetlist = fileset;
16745184Sek110237 	}
16755184Sek110237 
16766391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
16775184Sek110237 
16786212Saw148015 	fileset->fs_name = name;
16795184Sek110237 
16805184Sek110237 	return (fileset);
16815184Sek110237 }
16825184Sek110237 
16835184Sek110237 /*
16845184Sek110237  * If supplied with a pointer to a fileset and the fileset's
16856212Saw148015  * fileset_prealloc flag is set, calls fileset_populate() to populate
16865184Sek110237  * the fileset with filesetentries, then calls fileset_create()
16875184Sek110237  * to make actual directories and files for the filesetentries.
16885184Sek110237  * Otherwise, it applies fileset_populate() and fileset_create()
16895184Sek110237  * to all the filesets on the master fileset list. It always
16905184Sek110237  * returns zero (0) if one fileset is populated / created,
16915184Sek110237  * otherwise it returns the sum of returned values from
16925184Sek110237  * fileset_create() and fileset_populate(), which
16935184Sek110237  * will be a negative one (-1) times the number of
16945184Sek110237  * fileset_create() calls which failed.
16955184Sek110237  */
16965184Sek110237 int
16975184Sek110237 fileset_createset(fileset_t *fileset)
16985184Sek110237 {
16995184Sek110237 	fileset_t *list;
17005184Sek110237 	int ret = 0;
17015184Sek110237 
17025673Saw148015 	/* set up for possible parallel allocate */
17037556SAndrew.W.Wilson@sun.com 	filebench_shm->shm_fsparalloc_count = 0;
17047556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(
17057556SAndrew.W.Wilson@sun.com 	    &filebench_shm->shm_fsparalloc_cv,
17067556SAndrew.W.Wilson@sun.com 	    ipc_condattr());
17075673Saw148015 
17086212Saw148015 	if (fileset && avd_get_bool(fileset->fs_prealloc)) {
17095673Saw148015 
17106305Saw148015 		/* check for raw files */
17116305Saw148015 		if (fileset_checkraw(fileset)) {
17126305Saw148015 			filebench_log(LOG_INFO,
17136305Saw148015 			    "file %s/%s is a RAW device",
17146305Saw148015 			    avd_get_str(fileset->fs_path),
17156305Saw148015 			    avd_get_str(fileset->fs_name));
17167556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_OK);
17176305Saw148015 		}
17186305Saw148015 
17195673Saw148015 		filebench_log(LOG_INFO,
17205673Saw148015 		    "creating/pre-allocating %s %s",
17216212Saw148015 		    fileset_entity_name(fileset),
17226212Saw148015 		    avd_get_str(fileset->fs_name));
17235673Saw148015 
17247556SAndrew.W.Wilson@sun.com 		if ((ret = fileset_populate(fileset)) != FILEBENCH_OK)
17255184Sek110237 			return (ret);
17265673Saw148015 
17277556SAndrew.W.Wilson@sun.com 		if ((ret = fileset_create(fileset)) != FILEBENCH_OK)
17285673Saw148015 			return (ret);
17295673Saw148015 	} else {
17305673Saw148015 
17315673Saw148015 		filebench_log(LOG_INFO,
17325673Saw148015 		    "Creating/pre-allocating files and filesets");
17335673Saw148015 
17346391Saw148015 		list = filebench_shm->shm_filesetlist;
17355673Saw148015 		while (list) {
17366305Saw148015 			/* check for raw files */
17376305Saw148015 			if (fileset_checkraw(list)) {
17386305Saw148015 				filebench_log(LOG_INFO,
17396305Saw148015 				    "file %s/%s is a RAW device",
17406305Saw148015 				    avd_get_str(list->fs_path),
17416305Saw148015 				    avd_get_str(list->fs_name));
17426305Saw148015 				list = list->fs_next;
17436305Saw148015 				continue;
17446305Saw148015 			}
17456305Saw148015 
17467556SAndrew.W.Wilson@sun.com 			if ((ret = fileset_populate(list)) != FILEBENCH_OK)
17475673Saw148015 				return (ret);
17487556SAndrew.W.Wilson@sun.com 
17497556SAndrew.W.Wilson@sun.com 			if ((ret = fileset_create(list)) != FILEBENCH_OK)
17505673Saw148015 				return (ret);
17517556SAndrew.W.Wilson@sun.com 
17525673Saw148015 			list = list->fs_next;
17535673Saw148015 		}
17545184Sek110237 	}
17555184Sek110237 
17565673Saw148015 	/* wait for allocation threads to finish */
17575673Saw148015 	filebench_log(LOG_INFO,
17585673Saw148015 	    "waiting for fileset pre-allocation to finish");
17595184Sek110237 
17607556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
17617556SAndrew.W.Wilson@sun.com 	while (filebench_shm->shm_fsparalloc_count > 0)
17627556SAndrew.W.Wilson@sun.com 		(void) pthread_cond_wait(
17637556SAndrew.W.Wilson@sun.com 		    &filebench_shm->shm_fsparalloc_cv,
17647556SAndrew.W.Wilson@sun.com 		    &filebench_shm->shm_fsparalloc_lock);
17657556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
17665673Saw148015 
17677556SAndrew.W.Wilson@sun.com 	if (filebench_shm->shm_fsparalloc_count < 0)
17687556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
17695673Saw148015 
17707556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
17715184Sek110237 }
17725184Sek110237 
17735184Sek110237 /*
17745184Sek110237  * Searches through the master fileset list for the named fileset.
17755184Sek110237  * If found, returns pointer to same, otherwise returns NULL.
17765184Sek110237  */
17775184Sek110237 fileset_t *
17785184Sek110237 fileset_find(char *name)
17795184Sek110237 {
17806391Saw148015 	fileset_t *fileset = filebench_shm->shm_filesetlist;
17815184Sek110237 
17826391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
17835184Sek110237 
17845184Sek110237 	while (fileset) {
17856212Saw148015 		if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) {
17866391Saw148015 			(void) ipc_mutex_unlock(
17876391Saw148015 			    &filebench_shm->shm_fileset_lock);
17885184Sek110237 			return (fileset);
17895184Sek110237 		}
17905184Sek110237 		fileset = fileset->fs_next;
17915184Sek110237 	}
17926391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
17935184Sek110237 
17945184Sek110237 	return (NULL);
17955184Sek110237 }
17965673Saw148015 
17975673Saw148015 /*
17985673Saw148015  * Iterates over all the file sets in the filesetlist,
17995673Saw148015  * executing the supplied command "*cmd()" on them. Also
18005673Saw148015  * indicates to the executed command if it is the first
18015673Saw148015  * time the command has been executed since the current
18025673Saw148015  * call to fileset_iter.
18035673Saw148015  */
1804*8404SAndrew.W.Wilson@sun.com int
18055673Saw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first))
18065673Saw148015 {
18076391Saw148015 	fileset_t *fileset = filebench_shm->shm_filesetlist;
18085673Saw148015 	int count = 0;
18095673Saw148015 
18106391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
18115673Saw148015 
18125673Saw148015 	while (fileset) {
1813*8404SAndrew.W.Wilson@sun.com 		if (cmd(fileset, count == 0) == FILEBENCH_ERROR) {
1814*8404SAndrew.W.Wilson@sun.com 			(void) ipc_mutex_unlock(
1815*8404SAndrew.W.Wilson@sun.com 			    &filebench_shm->shm_fileset_lock);
1816*8404SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
1817*8404SAndrew.W.Wilson@sun.com 		}
18185673Saw148015 		fileset = fileset->fs_next;
18195673Saw148015 		count++;
18205673Saw148015 	}
18215673Saw148015 
18226391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
1823*8404SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
18245673Saw148015 }
18255673Saw148015 
18265673Saw148015 /*
18275673Saw148015  * Prints information to the filebench log about the file
18285673Saw148015  * object. Also prints a header on the first call.
18295673Saw148015  */
18305673Saw148015 int
18315673Saw148015 fileset_print(fileset_t *fileset, int first)
18325673Saw148015 {
18336212Saw148015 	int pathlength;
18346212Saw148015 	char *fileset_path;
18356212Saw148015 	char *fileset_name;
18366212Saw148015 	static char pad[] = "                              "; /* 30 spaces */
18376212Saw148015 
18386212Saw148015 	if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
18396212Saw148015 		filebench_log(LOG_ERROR, "%s path not set",
18406212Saw148015 		    fileset_entity_name(fileset));
18417556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
18426212Saw148015 	}
18436212Saw148015 
18446212Saw148015 	if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
18456212Saw148015 		filebench_log(LOG_ERROR, "%s name not set",
18466212Saw148015 		    fileset_entity_name(fileset));
18477556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
18486212Saw148015 	}
18496212Saw148015 
18506212Saw148015 	pathlength = strlen(fileset_path) + strlen(fileset_name);
18515673Saw148015 
18525673Saw148015 	if (pathlength > 29)
18535673Saw148015 		pathlength = 29;
18545673Saw148015 
18555673Saw148015 	if (first) {
18565673Saw148015 		filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s",
18575673Saw148015 		    "file size",
18585673Saw148015 		    "dir width",
18595673Saw148015 		    "entries");
18605673Saw148015 	}
18615673Saw148015 
18625673Saw148015 	if (fileset->fs_attrs & FILESET_IS_FILE) {
18635673Saw148015 		if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
18645673Saw148015 			filebench_log(LOG_INFO,
18655673Saw148015 			    "%s/%s%s         (Raw Device)",
18666212Saw148015 			    fileset_path, fileset_name, &pad[pathlength]);
18675673Saw148015 		} else {
18685673Saw148015 			filebench_log(LOG_INFO,
18696286Saw148015 			    "%s/%s%s%9llu     (Single File)",
18706212Saw148015 			    fileset_path, fileset_name, &pad[pathlength],
18716286Saw148015 			    (u_longlong_t)avd_get_int(fileset->fs_size));
18725673Saw148015 		}
18735673Saw148015 	} else {
18746286Saw148015 		filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu",
18756212Saw148015 		    fileset_path, fileset_name,
18765673Saw148015 		    &pad[pathlength],
18776286Saw148015 		    (u_longlong_t)avd_get_int(fileset->fs_size),
18786286Saw148015 		    (u_longlong_t)avd_get_int(fileset->fs_dirwidth),
18796286Saw148015 		    (u_longlong_t)fileset->fs_constentries);
18805673Saw148015 	}
18817556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
18825673Saw148015 }
18837946SAndrew.W.Wilson@sun.com 
18845673Saw148015 /*
18855673Saw148015  * checks to see if the path/name pair points to a raw device. If
18865673Saw148015  * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1.
18875673Saw148015  * If RAW is not defined, or it is not a raw device, it clears the
18885673Saw148015  * raw device flag and returns 0.
18895673Saw148015  */
18905673Saw148015 int
18915673Saw148015 fileset_checkraw(fileset_t *fileset)
18925673Saw148015 {
18935673Saw148015 	char path[MAXPATHLEN];
18945673Saw148015 	struct stat64 sb;
18956305Saw148015 	char *pathname;
18966305Saw148015 	char *setname;
18975673Saw148015 
18985673Saw148015 	fileset->fs_attrs &= (~FILESET_IS_RAW_DEV);
18995673Saw148015 
19005673Saw148015 #ifdef HAVE_RAW_SUPPORT
19015673Saw148015 	/* check for raw device */
19026305Saw148015 	if ((pathname = avd_get_str(fileset->fs_path)) == NULL)
19037556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
19046305Saw148015 
19056305Saw148015 	if ((setname = avd_get_str(fileset->fs_name)) == NULL)
19067556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
19076305Saw148015 
19087946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, pathname, MAXPATHLEN);
19097946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
19107946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, setname, MAXPATHLEN);
19115673Saw148015 	if ((stat64(path, &sb) == 0) &&
19125673Saw148015 	    ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) {
19135673Saw148015 		fileset->fs_attrs |= FILESET_IS_RAW_DEV;
19146305Saw148015 		if (!(fileset->fs_attrs & FILESET_IS_FILE)) {
19156305Saw148015 			filebench_log(LOG_ERROR,
19166305Saw148015 			    "WARNING Fileset %s/%s Cannot be RAW device",
19176305Saw148015 			    avd_get_str(fileset->fs_path),
19186305Saw148015 			    avd_get_str(fileset->fs_name));
19196305Saw148015 			filebench_shutdown(1);
19206305Saw148015 		}
19216305Saw148015 
19225673Saw148015 		return (1);
19235673Saw148015 	}
19245673Saw148015 #endif /* HAVE_RAW_SUPPORT */
19255673Saw148015 
19267556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
19275673Saw148015 }
1928