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