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 /*
22*8615SAndrew.W.Wilson@sun.com  * Copyright 2009 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>
348404SAndrew.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"
40*8615SAndrew.W.Wilson@sun.com #include "fsplug.h"
415184Sek110237 
425184Sek110237 /*
435184Sek110237  * File sets, of type fileset_t, are entities which contain
445184Sek110237  * information about collections of files and subdirectories in Filebench.
455184Sek110237  * The fileset, once populated, consists of a tree of fileset entries of
465184Sek110237  * type filesetentry_t which specify files and directories.  The fileset
476212Saw148015  * is rooted in a directory specified by fileset_path, and once the populated
485184Sek110237  * fileset has been created, has a tree of directories and files
495184Sek110237  * corresponding to the fileset's filesetentry tree.
506701Saw148015  *
517556SAndrew.W.Wilson@sun.com  * Fileset entities are allocated by fileset_define() which is called from
527556SAndrew.W.Wilson@sun.com  * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding
537556SAndrew.W.Wilson@sun.com  * to the eventual directory and file tree to be instantiated on the storage
547946SAndrew.W.Wilson@sun.com  * medium is built by fileset_populate(), which is This routine is called
557946SAndrew.W.Wilson@sun.com  * from fileset_createset(), which is in turn called by fileset_createset().
567946SAndrew.W.Wilson@sun.com  * After calling fileset_populate(), fileset_createset() will call
577946SAndrew.W.Wilson@sun.com  * fileset_create() to pre-allocate designated files and directories.
587556SAndrew.W.Wilson@sun.com  *
597556SAndrew.W.Wilson@sun.com  * Fileset_createset() is called from parser_gram.y: parser_create_fileset()
607556SAndrew.W.Wilson@sun.com  * when a "create fileset" or "run" command is encountered. When the
617556SAndrew.W.Wilson@sun.com  * "create fileset" command is used, it is generally paired with
626701Saw148015  * a "create processes" command, and must appear first, in order to
636701Saw148015  * instantiate all the files in the fileset before trying to use them.
645184Sek110237  */
655184Sek110237 
666305Saw148015 static int fileset_checkraw(fileset_t *fileset);
676305Saw148015 
687556SAndrew.W.Wilson@sun.com /* maximum parallel allocation control */
695673Saw148015 #define	MAX_PARALLOC_THREADS 32
705673Saw148015 
715673Saw148015 /*
725673Saw148015  * returns pointer to file or fileset
735673Saw148015  * string, as appropriate
745673Saw148015  */
755673Saw148015 static char *
765673Saw148015 fileset_entity_name(fileset_t *fileset)
775673Saw148015 {
785673Saw148015 	if (fileset->fs_attrs & FILESET_IS_FILE)
795673Saw148015 		return ("file");
805673Saw148015 	else
815673Saw148015 		return ("fileset");
825673Saw148015 }
835673Saw148015 
845184Sek110237 /*
855184Sek110237  * Removes the last file or directory name from a pathname.
865184Sek110237  * Basically removes characters from the end of the path by
875184Sek110237  * setting them to \0 until a forward slash '/' is
885184Sek110237  * encountered. It also removes the forward slash.
895184Sek110237  */
905184Sek110237 static char *
915184Sek110237 trunc_dirname(char *dir)
925184Sek110237 {
935184Sek110237 	char *s = dir + strlen(dir);
945184Sek110237 
955184Sek110237 	while (s != dir) {
965184Sek110237 		int c = *s;
975184Sek110237 
985184Sek110237 		*s = 0;
995184Sek110237 		if (c == '/')
1005184Sek110237 			break;
1015184Sek110237 		s--;
1025184Sek110237 	}
1035184Sek110237 	return (dir);
1045184Sek110237 }
1055184Sek110237 
1065184Sek110237 /*
1075184Sek110237  * Prints a list of allowed options and how to specify them.
1085184Sek110237  */
1095184Sek110237 void
1105184Sek110237 fileset_usage(void)
1115184Sek110237 {
1125673Saw148015 	(void) fprintf(stderr,
1135673Saw148015 	    "define [file name=<name> | fileset name=<name>],path=<pathname>,"
1145673Saw148015 	    ",entries=<number>\n");
1155673Saw148015 	(void) fprintf(stderr,
1166212Saw148015 	    "		        [,filesize=[size]]\n");
1176212Saw148015 	(void) fprintf(stderr,
1185673Saw148015 	    "		        [,dirwidth=[width]]\n");
1195673Saw148015 	(void) fprintf(stderr,
1206212Saw148015 	    "		        [,dirdepthrv=$random_variable_name]\n");
1216212Saw148015 	(void) fprintf(stderr,
1225673Saw148015 	    "		        [,dirgamma=[100-10000]] "
1235184Sek110237 	    "(Gamma * 1000)\n");
1245184Sek110237 	(void) fprintf(stderr,
1255673Saw148015 	    "		        [,sizegamma=[100-10000]] (Gamma * 1000)\n");
1265184Sek110237 	(void) fprintf(stderr,
1275184Sek110237 	    "		        [,prealloc=[percent]]\n");
1285673Saw148015 	(void) fprintf(stderr, "		        [,paralloc]\n");
1295184Sek110237 	(void) fprintf(stderr, "		        [,reuse]\n");
1305184Sek110237 	(void) fprintf(stderr, "\n");
1315184Sek110237 }
1325184Sek110237 
1335184Sek110237 /*
1345184Sek110237  * Creates a path string from the filesetentry_t "*entry"
1355184Sek110237  * and all of its parent's path names. The resulting path
1365184Sek110237  * is a concatination of all the individual parent paths.
1375184Sek110237  * Allocates memory for the path string and returns a
1385184Sek110237  * pointer to it.
1395184Sek110237  */
1405184Sek110237 char *
1415184Sek110237 fileset_resolvepath(filesetentry_t *entry)
1425184Sek110237 {
1435184Sek110237 	filesetentry_t *fsep = entry;
1445184Sek110237 	char path[MAXPATHLEN];
1455184Sek110237 	char pathtmp[MAXPATHLEN];
1465184Sek110237 	char *s;
1475184Sek110237 
1487946SAndrew.W.Wilson@sun.com 	path[0] = '\0';
1495184Sek110237 	while (fsep->fse_parent) {
1505184Sek110237 		(void) strcpy(pathtmp, "/");
1517946SAndrew.W.Wilson@sun.com 		(void) fb_strlcat(pathtmp, fsep->fse_path, MAXPATHLEN);
1527946SAndrew.W.Wilson@sun.com 		(void) fb_strlcat(pathtmp, path, MAXPATHLEN);
1537946SAndrew.W.Wilson@sun.com 		(void) fb_strlcpy(path, pathtmp, MAXPATHLEN);
1545184Sek110237 		fsep = fsep->fse_parent;
1555184Sek110237 	}
1565184Sek110237 
1575184Sek110237 	s = malloc(strlen(path) + 1);
1587946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(s, path, MAXPATHLEN);
1595184Sek110237 	return (s);
1605184Sek110237 }
1615184Sek110237 
1625184Sek110237 /*
1635184Sek110237  * Creates multiple nested directories as required by the
1645184Sek110237  * supplied path. Starts at the end of the path, creating
1655184Sek110237  * a list of directories to mkdir, up to the root of the
1665184Sek110237  * path, then mkdirs them one at a time from the root on down.
1675184Sek110237  */
1685184Sek110237 static int
1695184Sek110237 fileset_mkdir(char *path, int mode)
1705184Sek110237 {
1715184Sek110237 	char *p;
1725184Sek110237 	char *dirs[65536];
1735184Sek110237 	int i = 0;
1745184Sek110237 
1755184Sek110237 	if ((p = strdup(path)) == NULL)
1765184Sek110237 		goto null_str;
1775184Sek110237 
1785184Sek110237 	/*
1795184Sek110237 	 * Fill an array of subdirectory path names until either we
1805184Sek110237 	 * reach the root or encounter an already existing subdirectory
1815184Sek110237 	 */
1825184Sek110237 	/* CONSTCOND */
1835184Sek110237 	while (1) {
1845184Sek110237 		struct stat64 sb;
1855184Sek110237 
1865184Sek110237 		if (stat64(p, &sb) == 0)
1875184Sek110237 			break;
1885184Sek110237 		if (strlen(p) < 3)
1895184Sek110237 			break;
1905184Sek110237 		if ((dirs[i] = strdup(p)) == NULL) {
1915184Sek110237 			free(p);
1925184Sek110237 			goto null_str;
1935184Sek110237 		}
1945184Sek110237 
1955184Sek110237 		(void) trunc_dirname(p);
1965184Sek110237 		i++;
1975184Sek110237 	}
1985184Sek110237 
1995184Sek110237 	/* Make the directories, from closest to root downwards. */
2005184Sek110237 	for (--i; i >= 0; i--) {
201*8615SAndrew.W.Wilson@sun.com 		(void) FB_MKDIR(dirs[i], mode);
2025184Sek110237 		free(dirs[i]);
2035184Sek110237 	}
2045184Sek110237 
2055184Sek110237 	free(p);
2067556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
2075184Sek110237 
2085184Sek110237 null_str:
2095184Sek110237 	/* clean up */
2105184Sek110237 	for (--i; i >= 0; i--)
2115184Sek110237 		free(dirs[i]);
2125184Sek110237 
2135184Sek110237 	filebench_log(LOG_ERROR,
2145184Sek110237 	    "Failed to create directory path %s: Out of memory", path);
2157556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_ERROR);
2165184Sek110237 }
2175184Sek110237 
2185673Saw148015 /*
2195673Saw148015  * creates the subdirectory tree for a fileset.
2205673Saw148015  */
2215673Saw148015 static int
2225673Saw148015 fileset_create_subdirs(fileset_t *fileset, char *filesetpath)
2235673Saw148015 {
2245673Saw148015 	filesetentry_t *direntry;
2255673Saw148015 	char full_path[MAXPATHLEN];
2265673Saw148015 	char *part_path;
2275673Saw148015 
2285673Saw148015 	/* walk the subdirectory list, enstanciating subdirs */
2295673Saw148015 	direntry = fileset->fs_dirlist;
2305673Saw148015 	while (direntry) {
2317946SAndrew.W.Wilson@sun.com 		(void) fb_strlcpy(full_path, filesetpath, MAXPATHLEN);
2325673Saw148015 		part_path = fileset_resolvepath(direntry);
2337946SAndrew.W.Wilson@sun.com 		(void) fb_strlcat(full_path, part_path, MAXPATHLEN);
2345673Saw148015 		free(part_path);
2355673Saw148015 
2365673Saw148015 		/* now create this portion of the subdirectory tree */
2377556SAndrew.W.Wilson@sun.com 		if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR)
2387556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
2395673Saw148015 
2408404SAndrew.W.Wilson@sun.com 		direntry = direntry->fse_nextoftype;
2415673Saw148015 	}
2427556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
2435673Saw148015 }
2445673Saw148015 
2455673Saw148015 /*
2468404SAndrew.W.Wilson@sun.com  * move filesetentry between exist tree and non-exist tree, source_tree
2478404SAndrew.W.Wilson@sun.com  * to destination tree.
2488404SAndrew.W.Wilson@sun.com  */
2498404SAndrew.W.Wilson@sun.com static void
2508404SAndrew.W.Wilson@sun.com fileset_move_entry(avl_tree_t *src_tree, avl_tree_t *dst_tree,
2518404SAndrew.W.Wilson@sun.com     filesetentry_t *entry)
2528404SAndrew.W.Wilson@sun.com {
2538404SAndrew.W.Wilson@sun.com 	avl_remove(src_tree, entry);
2548404SAndrew.W.Wilson@sun.com 	avl_add(dst_tree, entry);
2558404SAndrew.W.Wilson@sun.com }
2568404SAndrew.W.Wilson@sun.com 
2578404SAndrew.W.Wilson@sun.com /*
2587946SAndrew.W.Wilson@sun.com  * given a fileset entry, determines if the associated leaf directory
2597946SAndrew.W.Wilson@sun.com  * needs to be made or not, and if so does the mkdir.
2607946SAndrew.W.Wilson@sun.com  */
2617946SAndrew.W.Wilson@sun.com static int
2627946SAndrew.W.Wilson@sun.com fileset_alloc_leafdir(filesetentry_t *entry)
2637946SAndrew.W.Wilson@sun.com {
2647946SAndrew.W.Wilson@sun.com 	fileset_t *fileset;
2657946SAndrew.W.Wilson@sun.com 	char path[MAXPATHLEN];
2667946SAndrew.W.Wilson@sun.com 	struct stat64 sb;
2677946SAndrew.W.Wilson@sun.com 	char *pathtmp;
2687946SAndrew.W.Wilson@sun.com 
2697946SAndrew.W.Wilson@sun.com 	fileset = entry->fse_fileset;
2707946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
2717946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
2727946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
2737946SAndrew.W.Wilson@sun.com 	pathtmp = fileset_resolvepath(entry);
2747946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
2757946SAndrew.W.Wilson@sun.com 	free(pathtmp);
2767946SAndrew.W.Wilson@sun.com 
2777946SAndrew.W.Wilson@sun.com 	filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
2787946SAndrew.W.Wilson@sun.com 
2797946SAndrew.W.Wilson@sun.com 	/* see if not reusing and this directory does not exist */
2807946SAndrew.W.Wilson@sun.com 	if (!((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0))) {
2817946SAndrew.W.Wilson@sun.com 
2827946SAndrew.W.Wilson@sun.com 		/* No file or not reusing, so create */
283*8615SAndrew.W.Wilson@sun.com 		if (FB_MKDIR(path, 0755) < 0) {
2847946SAndrew.W.Wilson@sun.com 			filebench_log(LOG_ERROR,
2857946SAndrew.W.Wilson@sun.com 			    "Failed to pre-allocate leaf directory %s: %s",
2867946SAndrew.W.Wilson@sun.com 			    path, strerror(errno));
2878404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
2887946SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
2897946SAndrew.W.Wilson@sun.com 		}
2907946SAndrew.W.Wilson@sun.com 	}
2917946SAndrew.W.Wilson@sun.com 
2928404SAndrew.W.Wilson@sun.com 	/* unbusy the allocated entry */
2938404SAndrew.W.Wilson@sun.com 	fileset_unbusy(entry, TRUE, TRUE, 0);
2947946SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
2957946SAndrew.W.Wilson@sun.com }
2967946SAndrew.W.Wilson@sun.com 
2977946SAndrew.W.Wilson@sun.com /*
2985673Saw148015  * given a fileset entry, determines if the associated file
2995673Saw148015  * needs to be allocated or not, and if so does the allocation.
3005673Saw148015  */
3015673Saw148015 static int
3025673Saw148015 fileset_alloc_file(filesetentry_t *entry)
3035673Saw148015 {
3047946SAndrew.W.Wilson@sun.com 	fileset_t *fileset;
3055673Saw148015 	char path[MAXPATHLEN];
3065673Saw148015 	char *buf;
3075673Saw148015 	struct stat64 sb;
3085673Saw148015 	char *pathtmp;
3095673Saw148015 	off64_t seek;
310*8615SAndrew.W.Wilson@sun.com 	fb_fdesc_t fdesc;
3115673Saw148015 
3127946SAndrew.W.Wilson@sun.com 	fileset = entry->fse_fileset;
3137946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
3147946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
3157946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
3165673Saw148015 	pathtmp = fileset_resolvepath(entry);
3177946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
3187946SAndrew.W.Wilson@sun.com 	free(pathtmp);
3195673Saw148015 
3205673Saw148015 	filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
3215673Saw148015 
3225673Saw148015 	/* see if reusing and this file exists */
323*8615SAndrew.W.Wilson@sun.com 	if ((entry->fse_flags & FSE_REUSING) && (FB_STAT(path, &sb) == 0)) {
324*8615SAndrew.W.Wilson@sun.com 		if (FB_OPEN(&fdesc, path, O_RDWR, 0) == FILEBENCH_ERROR) {
3255673Saw148015 			filebench_log(LOG_INFO,
3265673Saw148015 			    "Attempted but failed to Re-use file %s",
3275673Saw148015 			    path);
3288404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
3297556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
3305673Saw148015 		}
3315673Saw148015 
3325673Saw148015 		if (sb.st_size == (off64_t)entry->fse_size) {
3337556SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
3345673Saw148015 			    "Re-using file %s", path);
3355673Saw148015 
3367946SAndrew.W.Wilson@sun.com 			if (!avd_get_bool(fileset->fs_cached))
337*8615SAndrew.W.Wilson@sun.com 				(void) FB_FREEMEM(&fdesc, entry->fse_size);
3385673Saw148015 
339*8615SAndrew.W.Wilson@sun.com 			(void) FB_CLOSE(&fdesc);
3406701Saw148015 
3418404SAndrew.W.Wilson@sun.com 			/* unbusy the allocated entry */
3428404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, TRUE, 0);
3437556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_OK);
3445673Saw148015 
3455673Saw148015 		} else if (sb.st_size > (off64_t)entry->fse_size) {
3465673Saw148015 			/* reuse, but too large */
3478404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
3485673Saw148015 			    "Truncating & re-using file %s", path);
3495673Saw148015 
350*8615SAndrew.W.Wilson@sun.com 			(void) FB_FTRUNC(&fdesc, (off64_t)entry->fse_size);
3515673Saw148015 
3527946SAndrew.W.Wilson@sun.com 			if (!avd_get_bool(fileset->fs_cached))
353*8615SAndrew.W.Wilson@sun.com 				(void) FB_FREEMEM(&fdesc, entry->fse_size);
3545673Saw148015 
355*8615SAndrew.W.Wilson@sun.com 			(void) FB_CLOSE(&fdesc);
3566701Saw148015 
3578404SAndrew.W.Wilson@sun.com 			/* unbusy the allocated entry */
3588404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, TRUE, 0);
3597556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_OK);
3605673Saw148015 		}
3615673Saw148015 	} else {
3625673Saw148015 
3635673Saw148015 		/* No file or not reusing, so create */
364*8615SAndrew.W.Wilson@sun.com 		if (FB_OPEN(&fdesc, path, O_RDWR | O_CREAT, 0644) ==
365*8615SAndrew.W.Wilson@sun.com 		    FILEBENCH_ERROR) {
3665673Saw148015 			filebench_log(LOG_ERROR,
3675673Saw148015 			    "Failed to pre-allocate file %s: %s",
3685673Saw148015 			    path, strerror(errno));
3695673Saw148015 
3708404SAndrew.W.Wilson@sun.com 			/* unbusy the unallocated entry */
3718404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
3727556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
3735673Saw148015 		}
3745673Saw148015 	}
3755673Saw148015 
3768404SAndrew.W.Wilson@sun.com 	if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) {
3778404SAndrew.W.Wilson@sun.com 		/* unbusy the unallocated entry */
3788404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, TRUE, FALSE, 0);
3797556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
3808404SAndrew.W.Wilson@sun.com 	}
3816701Saw148015 
3825673Saw148015 	for (seek = 0; seek < entry->fse_size; ) {
3835673Saw148015 		off64_t wsize;
3845673Saw148015 		int ret = 0;
3855673Saw148015 
3865673Saw148015 		/*
3875673Saw148015 		 * Write FILE_ALLOC_BLOCK's worth,
3885673Saw148015 		 * except on last write
3895673Saw148015 		 */
3905673Saw148015 		wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK);
3915673Saw148015 
392*8615SAndrew.W.Wilson@sun.com 		ret = FB_WRITE(&fdesc, buf, wsize);
3935673Saw148015 		if (ret != wsize) {
3945673Saw148015 			filebench_log(LOG_ERROR,
3955673Saw148015 			    "Failed to pre-allocate file %s: %s",
3965673Saw148015 			    path, strerror(errno));
397*8615SAndrew.W.Wilson@sun.com 			(void) FB_CLOSE(&fdesc);
3985673Saw148015 			free(buf);
3998404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
4007556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
4015673Saw148015 		}
4025673Saw148015 		seek += wsize;
4035673Saw148015 	}
4045673Saw148015 
4057946SAndrew.W.Wilson@sun.com 	if (!avd_get_bool(fileset->fs_cached))
406*8615SAndrew.W.Wilson@sun.com 		(void) FB_FREEMEM(&fdesc, entry->fse_size);
4075673Saw148015 
408*8615SAndrew.W.Wilson@sun.com 	(void) FB_CLOSE(&fdesc);
4095673Saw148015 
4105673Saw148015 	free(buf);
4115673Saw148015 
4128404SAndrew.W.Wilson@sun.com 	/* unbusy the allocated entry */
4138404SAndrew.W.Wilson@sun.com 	fileset_unbusy(entry, TRUE, TRUE, 0);
4148404SAndrew.W.Wilson@sun.com 
4155673Saw148015 	filebench_log(LOG_DEBUG_IMPL,
4166286Saw148015 	    "Pre-allocated file %s size %llu",
4176286Saw148015 	    path, (u_longlong_t)entry->fse_size);
4185673Saw148015 
4197556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
4205673Saw148015 }
4215673Saw148015 
4225673Saw148015 /*
4235673Saw148015  * given a fileset entry, determines if the associated file
4245673Saw148015  * needs to be allocated or not, and if so does the allocation.
4257556SAndrew.W.Wilson@sun.com  * Sets shm_fsparalloc_count to -1 on error.
4265673Saw148015  */
4275673Saw148015 static void *
4285673Saw148015 fileset_alloc_thread(filesetentry_t *entry)
4295673Saw148015 {
4307556SAndrew.W.Wilson@sun.com 	if (fileset_alloc_file(entry) == FILEBENCH_ERROR) {
4317556SAndrew.W.Wilson@sun.com 		(void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
4327556SAndrew.W.Wilson@sun.com 		filebench_shm->shm_fsparalloc_count = -1;
4335673Saw148015 	} else {
4347556SAndrew.W.Wilson@sun.com 		(void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
4357556SAndrew.W.Wilson@sun.com 		filebench_shm->shm_fsparalloc_count--;
4365673Saw148015 	}
4375673Saw148015 
4387556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv);
4397556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
4405673Saw148015 
4415673Saw148015 	pthread_exit(NULL);
4425673Saw148015 	return (NULL);
4435673Saw148015 }
4445673Saw148015 
4455184Sek110237 
4465184Sek110237 /*
4475184Sek110237  * First creates the parent directories of the file using
4485184Sek110237  * fileset_mkdir(). Then Optionally sets the O_DSYNC flag
4495184Sek110237  * and opens the file with open64(). It unlocks the fileset
4505184Sek110237  * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags
4515184Sek110237  * as requested, and returns the file descriptor integer
452*8615SAndrew.W.Wilson@sun.com  * for the opened file in the supplied filebench file descriptor.
453*8615SAndrew.W.Wilson@sun.com  * Returns FILEBENCH_ERROR on error, and FILEBENCH_OK on success.
4545184Sek110237  */
4555184Sek110237 int
456*8615SAndrew.W.Wilson@sun.com fileset_openfile(fb_fdesc_t *fdesc, fileset_t *fileset,
4577736SAndrew.W.Wilson@sun.com     filesetentry_t *entry, int flag, int filemode, int attrs)
4585184Sek110237 {
4595184Sek110237 	char path[MAXPATHLEN];
4605184Sek110237 	char dir[MAXPATHLEN];
4615184Sek110237 	char *pathtmp;
4625184Sek110237 	struct stat64 sb;
4635184Sek110237 	int open_attrs = 0;
4645184Sek110237 
4657946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
4667946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
4677946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
4685184Sek110237 	pathtmp = fileset_resolvepath(entry);
4697946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, pathtmp, MAXPATHLEN);
4707946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(dir, path, MAXPATHLEN);
4715184Sek110237 	free(pathtmp);
4725184Sek110237 	(void) trunc_dirname(dir);
4735184Sek110237 
4745184Sek110237 	/* If we are going to create a file, create the parent dirs */
4755184Sek110237 	if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) {
4767556SAndrew.W.Wilson@sun.com 		if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR)
4777556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
4786701Saw148015 	}
4796701Saw148015 
4805184Sek110237 	if (attrs & FLOW_ATTR_DSYNC) {
4815184Sek110237 #ifdef sun
4825184Sek110237 		open_attrs |= O_DSYNC;
4835184Sek110237 #else
4845184Sek110237 		open_attrs |= O_FSYNC;
4855184Sek110237 #endif
4865184Sek110237 	}
4875184Sek110237 
488*8615SAndrew.W.Wilson@sun.com 	if (FB_OPEN(fdesc, path, flag | open_attrs, filemode)
489*8615SAndrew.W.Wilson@sun.com 	    == FILEBENCH_ERROR) {
4905184Sek110237 		filebench_log(LOG_ERROR,
4918404SAndrew.W.Wilson@sun.com 		    "Failed to open file %d, %s, with status %x: %s",
4928404SAndrew.W.Wilson@sun.com 		    entry->fse_index, path, entry->fse_flags, strerror(errno));
4937556SAndrew.W.Wilson@sun.com 
4948404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, FALSE, FALSE, 0);
4957556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
4965184Sek110237 	}
4977556SAndrew.W.Wilson@sun.com 
4987556SAndrew.W.Wilson@sun.com 	if (flag & O_CREAT)
4998404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, TRUE, TRUE, 1);
5007556SAndrew.W.Wilson@sun.com 	else
5018404SAndrew.W.Wilson@sun.com 		fileset_unbusy(entry, FALSE, FALSE, 1);
5025184Sek110237 
5035184Sek110237 #ifdef sun
5045184Sek110237 	if (attrs & FLOW_ATTR_DIRECTIO)
505*8615SAndrew.W.Wilson@sun.com 		(void) directio(fdesc->fd_num, DIRECTIO_ON);
5065184Sek110237 	else
507*8615SAndrew.W.Wilson@sun.com 		(void) directio(fdesc->fd_num, DIRECTIO_OFF);
5085184Sek110237 #endif
5095184Sek110237 
510*8615SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
5115184Sek110237 }
5125184Sek110237 
5138404SAndrew.W.Wilson@sun.com /*
5148404SAndrew.W.Wilson@sun.com  * removes all filesetentries from their respective btrees, and puts them
5158404SAndrew.W.Wilson@sun.com  * on the free list. The supplied argument indicates which free list to
5168404SAndrew.W.Wilson@sun.com  * use.
5178404SAndrew.W.Wilson@sun.com  */
5188404SAndrew.W.Wilson@sun.com static void
5198404SAndrew.W.Wilson@sun.com fileset_pickreset(fileset_t *fileset, int entry_type)
5208404SAndrew.W.Wilson@sun.com {
5218404SAndrew.W.Wilson@sun.com 	filesetentry_t	*entry;
5228404SAndrew.W.Wilson@sun.com 
5238404SAndrew.W.Wilson@sun.com 	switch (entry_type & FILESET_PICKMASK) {
5248404SAndrew.W.Wilson@sun.com 	case FILESET_PICKFILE:
5258404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)avl_first(&fileset->fs_noex_files);
5268404SAndrew.W.Wilson@sun.com 
5278404SAndrew.W.Wilson@sun.com 		/* make sure non-existing files are marked free */
5288404SAndrew.W.Wilson@sun.com 		while (entry) {
5298404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
5308404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
5318404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_noex_files,
5328404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_files, entry);
5338404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_noex_files, entry);
5348404SAndrew.W.Wilson@sun.com 		}
5358404SAndrew.W.Wilson@sun.com 
5368404SAndrew.W.Wilson@sun.com 		/* free up any existing files */
5378404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)avl_first(&fileset->fs_exist_files);
5388404SAndrew.W.Wilson@sun.com 
5398404SAndrew.W.Wilson@sun.com 		while (entry) {
5408404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
5418404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
5428404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_exist_files,
5438404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_files, entry);
5448404SAndrew.W.Wilson@sun.com 
5458404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_exist_files, entry);
5468404SAndrew.W.Wilson@sun.com 		}
5478404SAndrew.W.Wilson@sun.com 
5488404SAndrew.W.Wilson@sun.com 		break;
5498404SAndrew.W.Wilson@sun.com 
5508404SAndrew.W.Wilson@sun.com 	case FILESET_PICKDIR:
5518404SAndrew.W.Wilson@sun.com 		/* nothing to reset, as all (sub)dirs always exist */
5528404SAndrew.W.Wilson@sun.com 		break;
5538404SAndrew.W.Wilson@sun.com 
5548404SAndrew.W.Wilson@sun.com 	case FILESET_PICKLEAFDIR:
5558404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)
5568404SAndrew.W.Wilson@sun.com 		    avl_first(&fileset->fs_noex_leaf_dirs);
5578404SAndrew.W.Wilson@sun.com 
5588404SAndrew.W.Wilson@sun.com 		/* make sure non-existing leaf dirs are marked free */
5598404SAndrew.W.Wilson@sun.com 		while (entry) {
5608404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
5618404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
5628404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_noex_leaf_dirs,
5638404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_leaf_dirs, entry);
5648404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_noex_leaf_dirs, entry);
5658404SAndrew.W.Wilson@sun.com 		}
5668404SAndrew.W.Wilson@sun.com 
5678404SAndrew.W.Wilson@sun.com 		/* free up any existing leaf dirs */
5688404SAndrew.W.Wilson@sun.com 		entry = (filesetentry_t *)
5698404SAndrew.W.Wilson@sun.com 		    avl_first(&fileset->fs_exist_leaf_dirs);
5708404SAndrew.W.Wilson@sun.com 
5718404SAndrew.W.Wilson@sun.com 		while (entry) {
5728404SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_FREE;
5738404SAndrew.W.Wilson@sun.com 			entry->fse_open_cnt = 0;
5748404SAndrew.W.Wilson@sun.com 			fileset_move_entry(&fileset->fs_exist_leaf_dirs,
5758404SAndrew.W.Wilson@sun.com 			    &fileset->fs_free_leaf_dirs, entry);
5768404SAndrew.W.Wilson@sun.com 
5778404SAndrew.W.Wilson@sun.com 			entry =  AVL_NEXT(&fileset->fs_exist_leaf_dirs, entry);
5788404SAndrew.W.Wilson@sun.com 		}
5798404SAndrew.W.Wilson@sun.com 
5808404SAndrew.W.Wilson@sun.com 		break;
5818404SAndrew.W.Wilson@sun.com 	}
5828404SAndrew.W.Wilson@sun.com }
5838404SAndrew.W.Wilson@sun.com 
5848404SAndrew.W.Wilson@sun.com /*
5858404SAndrew.W.Wilson@sun.com  * find a filesetentry from the fileset using the supplied index
5868404SAndrew.W.Wilson@sun.com  */
5878404SAndrew.W.Wilson@sun.com static filesetentry_t *
5888404SAndrew.W.Wilson@sun.com fileset_find_entry(avl_tree_t *atp, uint_t index)
5898404SAndrew.W.Wilson@sun.com {
5908404SAndrew.W.Wilson@sun.com 	avl_index_t	found_loc;
5918404SAndrew.W.Wilson@sun.com 	filesetentry_t	desired_fse, *found_fse;
5928404SAndrew.W.Wilson@sun.com 
5938404SAndrew.W.Wilson@sun.com 	/* find the file with the desired index, if it is in the tree */
5948404SAndrew.W.Wilson@sun.com 	desired_fse.fse_index = index;
5958404SAndrew.W.Wilson@sun.com 	found_fse = avl_find(atp, (void *)(&desired_fse), &found_loc);
5968404SAndrew.W.Wilson@sun.com 	if (found_fse != NULL)
5978404SAndrew.W.Wilson@sun.com 		return (found_fse);
5988404SAndrew.W.Wilson@sun.com 
5998404SAndrew.W.Wilson@sun.com 	/* if requested node not found, find next higher node */
6008404SAndrew.W.Wilson@sun.com 	found_fse = avl_nearest(atp, found_loc, AVL_AFTER);
6018404SAndrew.W.Wilson@sun.com 	if (found_fse != NULL)
6028404SAndrew.W.Wilson@sun.com 		return (found_fse);
6038404SAndrew.W.Wilson@sun.com 
6048404SAndrew.W.Wilson@sun.com 	/* might have hit the end, return lowest available index node */
6058404SAndrew.W.Wilson@sun.com 	found_fse = avl_first(atp);
6068404SAndrew.W.Wilson@sun.com 	return (found_fse);
6078404SAndrew.W.Wilson@sun.com }
6085184Sek110237 
6095184Sek110237 /*
6105184Sek110237  * Selects a fileset entry from a fileset. If the
6117946SAndrew.W.Wilson@sun.com  * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry,
6127946SAndrew.W.Wilson@sun.com  * if the FILESET_PICKDIR flag is set it will pick a non leaf directory
6138404SAndrew.W.Wilson@sun.com  * entry, otherwise a file entry. The FILESET_PICKUNIQUE
6145184Sek110237  * flag will take an entry off of one of the free (unused)
6155184Sek110237  * lists (file or directory), otherwise the entry will be
6165184Sek110237  * picked off of one of the rotor lists (file or directory).
6175184Sek110237  * The FILESET_PICKEXISTS will insure that only extant
6185184Sek110237  * (FSE_EXISTS) state files are selected, while
6195184Sek110237  * FILESET_PICKNOEXIST insures that only non extant
6205184Sek110237  * (not FSE_EXISTS) state files are selected.
6216391Saw148015  * Note that the selected fileset entry (file) is returned
6227556SAndrew.W.Wilson@sun.com  * with its FSE_BUSY flag (in fse_flags) set.
6235184Sek110237  */
6245184Sek110237 filesetentry_t *
6258404SAndrew.W.Wilson@sun.com fileset_pick(fileset_t *fileset, int flags, int tid, int index)
6265184Sek110237 {
6275184Sek110237 	filesetentry_t *entry = NULL;
6288404SAndrew.W.Wilson@sun.com 	filesetentry_t *start_point;
6298404SAndrew.W.Wilson@sun.com 	avl_tree_t *atp;
6308404SAndrew.W.Wilson@sun.com 	fbint_t max_entries;
6315184Sek110237 
6327556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
6337556SAndrew.W.Wilson@sun.com 
6347556SAndrew.W.Wilson@sun.com 	/* see if we have to wait for available files or directories */
6357946SAndrew.W.Wilson@sun.com 	switch (flags & FILESET_PICKMASK) {
6367946SAndrew.W.Wilson@sun.com 	case FILESET_PICKFILE:
6377946SAndrew.W.Wilson@sun.com 		if (fileset->fs_filelist == NULL)
6387946SAndrew.W.Wilson@sun.com 			goto empty;
6398404SAndrew.W.Wilson@sun.com 
6407556SAndrew.W.Wilson@sun.com 		while (fileset->fs_idle_files == 0) {
6417556SAndrew.W.Wilson@sun.com 			(void) pthread_cond_wait(&fileset->fs_idle_files_cv,
6427556SAndrew.W.Wilson@sun.com 			    &fileset->fs_pick_lock);
6437556SAndrew.W.Wilson@sun.com 		}
6448404SAndrew.W.Wilson@sun.com 
6458404SAndrew.W.Wilson@sun.com 		max_entries = fileset->fs_constentries;
6468404SAndrew.W.Wilson@sun.com 		if (flags & FILESET_PICKUNIQUE) {
6478404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_free_files;
6488404SAndrew.W.Wilson@sun.com 		} else if (flags & FILESET_PICKNOEXIST) {
6498404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_noex_files;
6508404SAndrew.W.Wilson@sun.com 		} else {
6518404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_exist_files;
6528404SAndrew.W.Wilson@sun.com 		}
6537946SAndrew.W.Wilson@sun.com 		break;
6548404SAndrew.W.Wilson@sun.com 
6557946SAndrew.W.Wilson@sun.com 	case FILESET_PICKDIR:
6567946SAndrew.W.Wilson@sun.com 		if (fileset->fs_dirlist == NULL)
6577946SAndrew.W.Wilson@sun.com 			goto empty;
6588404SAndrew.W.Wilson@sun.com 
6597946SAndrew.W.Wilson@sun.com 		while (fileset->fs_idle_dirs == 0) {
6607946SAndrew.W.Wilson@sun.com 			(void) pthread_cond_wait(&fileset->fs_idle_dirs_cv,
6617946SAndrew.W.Wilson@sun.com 			    &fileset->fs_pick_lock);
6627946SAndrew.W.Wilson@sun.com 		}
6638404SAndrew.W.Wilson@sun.com 
6648404SAndrew.W.Wilson@sun.com 		max_entries = 1;
6658404SAndrew.W.Wilson@sun.com 		atp = &fileset->fs_dirs;
6667946SAndrew.W.Wilson@sun.com 		break;
6678404SAndrew.W.Wilson@sun.com 
6687946SAndrew.W.Wilson@sun.com 	case FILESET_PICKLEAFDIR:
6697946SAndrew.W.Wilson@sun.com 		if (fileset->fs_leafdirlist == NULL)
6707946SAndrew.W.Wilson@sun.com 			goto empty;
6718404SAndrew.W.Wilson@sun.com 
6727946SAndrew.W.Wilson@sun.com 		while (fileset->fs_idle_leafdirs == 0) {
6737946SAndrew.W.Wilson@sun.com 			(void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv,
6747946SAndrew.W.Wilson@sun.com 			    &fileset->fs_pick_lock);
6757946SAndrew.W.Wilson@sun.com 		}
6768404SAndrew.W.Wilson@sun.com 
6778404SAndrew.W.Wilson@sun.com 		max_entries = fileset->fs_constleafdirs;
6788404SAndrew.W.Wilson@sun.com 		if (flags & FILESET_PICKUNIQUE) {
6798404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_free_leaf_dirs;
6808404SAndrew.W.Wilson@sun.com 		} else if (flags & FILESET_PICKNOEXIST) {
6818404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_noex_leaf_dirs;
6828404SAndrew.W.Wilson@sun.com 		} else {
6838404SAndrew.W.Wilson@sun.com 			atp = &fileset->fs_exist_leaf_dirs;
6848404SAndrew.W.Wilson@sun.com 		}
6857946SAndrew.W.Wilson@sun.com 		break;
6867556SAndrew.W.Wilson@sun.com 	}
6875184Sek110237 
6886701Saw148015 	/* see if asking for impossible */
6898404SAndrew.W.Wilson@sun.com 	if (avl_is_empty(atp))
6908404SAndrew.W.Wilson@sun.com 		goto empty;
6918404SAndrew.W.Wilson@sun.com 
6928404SAndrew.W.Wilson@sun.com 	if (flags & FILESET_PICKUNIQUE) {
6938404SAndrew.W.Wilson@sun.com 		uint64_t  index64;
6948404SAndrew.W.Wilson@sun.com 
6958404SAndrew.W.Wilson@sun.com 		/*
6968404SAndrew.W.Wilson@sun.com 		 * pick at random from free list in order to
6978404SAndrew.W.Wilson@sun.com 		 * distribute initially allocated files more
6988404SAndrew.W.Wilson@sun.com 		 * randomly on storage media. Use uniform
6998404SAndrew.W.Wilson@sun.com 		 * random number generator to select index
7008404SAndrew.W.Wilson@sun.com 		 * if it is not supplied with pick call.
7018404SAndrew.W.Wilson@sun.com 		 */
7028404SAndrew.W.Wilson@sun.com 		if (index) {
7038404SAndrew.W.Wilson@sun.com 			index64 = index;
7048404SAndrew.W.Wilson@sun.com 		} else {
7058404SAndrew.W.Wilson@sun.com 			if (filebench_randomno64(&index64, max_entries, 1,
7068404SAndrew.W.Wilson@sun.com 			    NULL) == FILEBENCH_ERROR)
7077946SAndrew.W.Wilson@sun.com 				return (NULL);
7085184Sek110237 		}
7095184Sek110237 
7108404SAndrew.W.Wilson@sun.com 		entry = fileset_find_entry(atp, (int)index64);
7118404SAndrew.W.Wilson@sun.com 
7128404SAndrew.W.Wilson@sun.com 		if (entry == NULL)
7138404SAndrew.W.Wilson@sun.com 			goto empty;
7148404SAndrew.W.Wilson@sun.com 
7158404SAndrew.W.Wilson@sun.com 	} else if (flags & FILESET_PICKBYINDEX) {
7168404SAndrew.W.Wilson@sun.com 		/* pick by supplied index */
7178404SAndrew.W.Wilson@sun.com 		entry = fileset_find_entry(atp, index);
7188404SAndrew.W.Wilson@sun.com 
7198404SAndrew.W.Wilson@sun.com 	} else {
7208404SAndrew.W.Wilson@sun.com 		/* pick in rotation */
7218404SAndrew.W.Wilson@sun.com 		switch (flags & FILESET_PICKMASK) {
7228404SAndrew.W.Wilson@sun.com 		case FILESET_PICKFILE:
7238404SAndrew.W.Wilson@sun.com 			if (flags & FILESET_PICKNOEXIST) {
7248404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
7258404SAndrew.W.Wilson@sun.com 				    fileset->fs_file_nerotor);
7268404SAndrew.W.Wilson@sun.com 				fileset->fs_file_nerotor =
7278404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
7288404SAndrew.W.Wilson@sun.com 			} else {
7298404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
7308404SAndrew.W.Wilson@sun.com 				    fileset->fs_file_exrotor[tid]);
7318404SAndrew.W.Wilson@sun.com 				fileset->fs_file_exrotor[tid] =
7328404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
7335184Sek110237 			}
7348404SAndrew.W.Wilson@sun.com 			break;
7358404SAndrew.W.Wilson@sun.com 
7368404SAndrew.W.Wilson@sun.com 		case FILESET_PICKDIR:
7378404SAndrew.W.Wilson@sun.com 			entry = fileset_find_entry(atp, fileset->fs_dirrotor);
7388404SAndrew.W.Wilson@sun.com 			fileset->fs_dirrotor = entry->fse_index + 1;
7398404SAndrew.W.Wilson@sun.com 			break;
7408404SAndrew.W.Wilson@sun.com 
7418404SAndrew.W.Wilson@sun.com 		case FILESET_PICKLEAFDIR:
7428404SAndrew.W.Wilson@sun.com 			if (flags & FILESET_PICKNOEXIST) {
7438404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
7448404SAndrew.W.Wilson@sun.com 				    fileset->fs_leafdir_nerotor);
7458404SAndrew.W.Wilson@sun.com 				fileset->fs_leafdir_nerotor =
7468404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
7478404SAndrew.W.Wilson@sun.com 			} else {
7488404SAndrew.W.Wilson@sun.com 				entry = fileset_find_entry(atp,
7498404SAndrew.W.Wilson@sun.com 				    fileset->fs_leafdir_exrotor);
7508404SAndrew.W.Wilson@sun.com 				fileset->fs_leafdir_exrotor =
7518404SAndrew.W.Wilson@sun.com 				    entry->fse_index + 1;
7525184Sek110237 			}
7538404SAndrew.W.Wilson@sun.com 			break;
7548404SAndrew.W.Wilson@sun.com 		}
7558404SAndrew.W.Wilson@sun.com 	}
7568404SAndrew.W.Wilson@sun.com 
7578404SAndrew.W.Wilson@sun.com 	if (entry == NULL)
7588404SAndrew.W.Wilson@sun.com 		goto empty;
7598404SAndrew.W.Wilson@sun.com 
7608404SAndrew.W.Wilson@sun.com 	/* see if entry in use */
7618404SAndrew.W.Wilson@sun.com 	start_point = entry;
7628404SAndrew.W.Wilson@sun.com 	while (entry->fse_flags & FSE_BUSY) {
7638404SAndrew.W.Wilson@sun.com 
7648404SAndrew.W.Wilson@sun.com 		/* it is, so try next */
7658404SAndrew.W.Wilson@sun.com 		entry = AVL_NEXT(atp, entry);
7668404SAndrew.W.Wilson@sun.com 		if (entry == NULL)
7678404SAndrew.W.Wilson@sun.com 			entry = avl_first(atp);
7688404SAndrew.W.Wilson@sun.com 
7698404SAndrew.W.Wilson@sun.com 		/* see if we have wrapped around */
7708404SAndrew.W.Wilson@sun.com 		if ((entry == NULL) || (entry == start_point)) {
7718404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_SCRIPT,
7728404SAndrew.W.Wilson@sun.com 			    "All %d files are busy", avl_numnodes(atp));
7738404SAndrew.W.Wilson@sun.com 			goto empty;
7745184Sek110237 		}
7755184Sek110237 
7765184Sek110237 	}
7775184Sek110237 
7787556SAndrew.W.Wilson@sun.com 	/* update file or directory idle counts */
7797946SAndrew.W.Wilson@sun.com 	switch (flags & FILESET_PICKMASK) {
7807946SAndrew.W.Wilson@sun.com 	case FILESET_PICKFILE:
7817946SAndrew.W.Wilson@sun.com 		fileset->fs_idle_files--;
7827946SAndrew.W.Wilson@sun.com 		break;
7837946SAndrew.W.Wilson@sun.com 	case FILESET_PICKDIR:
7847556SAndrew.W.Wilson@sun.com 		fileset->fs_idle_dirs--;
7857946SAndrew.W.Wilson@sun.com 		break;
7867946SAndrew.W.Wilson@sun.com 	case FILESET_PICKLEAFDIR:
7877946SAndrew.W.Wilson@sun.com 		fileset->fs_idle_leafdirs--;
7887946SAndrew.W.Wilson@sun.com 		break;
7897946SAndrew.W.Wilson@sun.com 	}
7907556SAndrew.W.Wilson@sun.com 
7917556SAndrew.W.Wilson@sun.com 	/* Indicate that file or directory is now busy */
7927556SAndrew.W.Wilson@sun.com 	entry->fse_flags |= FSE_BUSY;
7937556SAndrew.W.Wilson@sun.com 
7947556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
7955184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path);
7965184Sek110237 	return (entry);
7975184Sek110237 
7985184Sek110237 empty:
7998404SAndrew.W.Wilson@sun.com 	filebench_log(LOG_DEBUG_SCRIPT, "No file found");
8007556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
8015184Sek110237 	return (NULL);
8025184Sek110237 }
8035184Sek110237 
8045184Sek110237 /*
8057556SAndrew.W.Wilson@sun.com  * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads
8067556SAndrew.W.Wilson@sun.com  * that are waiting for a NOT BUSY filesetentry. Also sets whether it is
8077556SAndrew.W.Wilson@sun.com  * existant or not, or leaves that designation alone.
8087556SAndrew.W.Wilson@sun.com  */
8097556SAndrew.W.Wilson@sun.com void
8108404SAndrew.W.Wilson@sun.com fileset_unbusy(filesetentry_t *entry, int update_exist,
8118404SAndrew.W.Wilson@sun.com     int new_exist_val, int open_cnt_incr)
8127556SAndrew.W.Wilson@sun.com {
8137556SAndrew.W.Wilson@sun.com 	fileset_t *fileset = NULL;
8147556SAndrew.W.Wilson@sun.com 
8157556SAndrew.W.Wilson@sun.com 	if (entry)
8167556SAndrew.W.Wilson@sun.com 		fileset = entry->fse_fileset;
8177556SAndrew.W.Wilson@sun.com 
8187556SAndrew.W.Wilson@sun.com 	if (fileset == NULL) {
8197556SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!");
8207556SAndrew.W.Wilson@sun.com 		return;
8217556SAndrew.W.Wilson@sun.com 	}
8227556SAndrew.W.Wilson@sun.com 
8237556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
8247556SAndrew.W.Wilson@sun.com 
8258404SAndrew.W.Wilson@sun.com 	/* modify FSE_EXIST flag and actual dirs/files count, if requested */
8268404SAndrew.W.Wilson@sun.com 	if (update_exist) {
8278404SAndrew.W.Wilson@sun.com 		if (new_exist_val == TRUE) {
8288404SAndrew.W.Wilson@sun.com 			if (entry->fse_flags & FSE_FREE) {
8298404SAndrew.W.Wilson@sun.com 
8308404SAndrew.W.Wilson@sun.com 				/* asked to set and it was free */
8318404SAndrew.W.Wilson@sun.com 				entry->fse_flags |= FSE_EXISTS;
8328404SAndrew.W.Wilson@sun.com 				entry->fse_flags &= (~FSE_FREE);
8338404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
8348404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
8358404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8368404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_files,
8378404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_files, entry);
8388404SAndrew.W.Wilson@sun.com 					break;
8398404SAndrew.W.Wilson@sun.com 
8408404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
8418404SAndrew.W.Wilson@sun.com 					break;
8428404SAndrew.W.Wilson@sun.com 
8438404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
8448404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8458404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_leaf_dirs,
8468404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_leaf_dirs,
8478404SAndrew.W.Wilson@sun.com 					    entry);
8488404SAndrew.W.Wilson@sun.com 					break;
8498404SAndrew.W.Wilson@sun.com 				}
8508404SAndrew.W.Wilson@sun.com 
8518404SAndrew.W.Wilson@sun.com 			} else if (!(entry->fse_flags & FSE_EXISTS)) {
8528404SAndrew.W.Wilson@sun.com 
8538404SAndrew.W.Wilson@sun.com 				/* asked to set, and it was clear */
8548404SAndrew.W.Wilson@sun.com 				entry->fse_flags |= FSE_EXISTS;
8558404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
8568404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
8578404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8588404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_files,
8598404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_files, entry);
8608404SAndrew.W.Wilson@sun.com 					break;
8618404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
8628404SAndrew.W.Wilson@sun.com 					break;
8638404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
8648404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8658404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_leaf_dirs,
8668404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_leaf_dirs,
8678404SAndrew.W.Wilson@sun.com 					    entry);
8688404SAndrew.W.Wilson@sun.com 					break;
8698404SAndrew.W.Wilson@sun.com 				}
8708404SAndrew.W.Wilson@sun.com 			}
8718404SAndrew.W.Wilson@sun.com 		} else {
8728404SAndrew.W.Wilson@sun.com 			if (entry->fse_flags & FSE_FREE) {
8738404SAndrew.W.Wilson@sun.com 				/* asked to clear, and it was free */
8748404SAndrew.W.Wilson@sun.com 				entry->fse_flags &= (~(FSE_FREE | FSE_EXISTS));
8758404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
8768404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
8778404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8788404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_files,
8798404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_files, entry);
8808404SAndrew.W.Wilson@sun.com 					break;
8818404SAndrew.W.Wilson@sun.com 
8828404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
8838404SAndrew.W.Wilson@sun.com 					break;
8848404SAndrew.W.Wilson@sun.com 
8858404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
8868404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8878404SAndrew.W.Wilson@sun.com 					    &fileset->fs_free_leaf_dirs,
8888404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_leaf_dirs,
8898404SAndrew.W.Wilson@sun.com 					    entry);
8908404SAndrew.W.Wilson@sun.com 					break;
8918404SAndrew.W.Wilson@sun.com 				}
8928404SAndrew.W.Wilson@sun.com 			} else if (entry->fse_flags & FSE_EXISTS) {
8938404SAndrew.W.Wilson@sun.com 
8948404SAndrew.W.Wilson@sun.com 				/* asked to clear, and it was set */
8958404SAndrew.W.Wilson@sun.com 				entry->fse_flags &= (~FSE_EXISTS);
8968404SAndrew.W.Wilson@sun.com 				switch (entry->fse_flags & FSE_TYPE_MASK) {
8978404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_FILE:
8988404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
8998404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_files,
9008404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_files, entry);
9018404SAndrew.W.Wilson@sun.com 					break;
9028404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_DIR:
9038404SAndrew.W.Wilson@sun.com 					break;
9048404SAndrew.W.Wilson@sun.com 				case FSE_TYPE_LEAFDIR:
9058404SAndrew.W.Wilson@sun.com 					fileset_move_entry(
9068404SAndrew.W.Wilson@sun.com 					    &fileset->fs_exist_leaf_dirs,
9078404SAndrew.W.Wilson@sun.com 					    &fileset->fs_noex_leaf_dirs,
9088404SAndrew.W.Wilson@sun.com 					    entry);
9098404SAndrew.W.Wilson@sun.com 					break;
9108404SAndrew.W.Wilson@sun.com 				}
9118404SAndrew.W.Wilson@sun.com 			}
9128404SAndrew.W.Wilson@sun.com 		}
9138404SAndrew.W.Wilson@sun.com 	}
9148404SAndrew.W.Wilson@sun.com 
9158404SAndrew.W.Wilson@sun.com 	/* update open count */
9168404SAndrew.W.Wilson@sun.com 	entry->fse_open_cnt += open_cnt_incr;
9178404SAndrew.W.Wilson@sun.com 
9187556SAndrew.W.Wilson@sun.com 	/* increment idle count, clear FSE_BUSY and signal IF it was busy */
9197556SAndrew.W.Wilson@sun.com 	if (entry->fse_flags & FSE_BUSY) {
9207556SAndrew.W.Wilson@sun.com 
9217556SAndrew.W.Wilson@sun.com 		/* unbusy it */
9227556SAndrew.W.Wilson@sun.com 		entry->fse_flags &= (~FSE_BUSY);
9237556SAndrew.W.Wilson@sun.com 
9247556SAndrew.W.Wilson@sun.com 		/* release any threads waiting for unbusy */
9257556SAndrew.W.Wilson@sun.com 		if (entry->fse_flags & FSE_THRD_WAITNG) {
9267556SAndrew.W.Wilson@sun.com 			entry->fse_flags &= (~FSE_THRD_WAITNG);
9277556SAndrew.W.Wilson@sun.com 			(void) pthread_cond_broadcast(
9287556SAndrew.W.Wilson@sun.com 			    &fileset->fs_thrd_wait_cv);
9297556SAndrew.W.Wilson@sun.com 		}
9307556SAndrew.W.Wilson@sun.com 
9317556SAndrew.W.Wilson@sun.com 		/* increment idle count and signal waiting threads */
9327946SAndrew.W.Wilson@sun.com 		switch (entry->fse_flags & FSE_TYPE_MASK) {
9337946SAndrew.W.Wilson@sun.com 		case FSE_TYPE_FILE:
9347946SAndrew.W.Wilson@sun.com 			fileset->fs_idle_files++;
9357946SAndrew.W.Wilson@sun.com 			if (fileset->fs_idle_files == 1) {
9367946SAndrew.W.Wilson@sun.com 				(void) pthread_cond_signal(
9377946SAndrew.W.Wilson@sun.com 				    &fileset->fs_idle_files_cv);
9387946SAndrew.W.Wilson@sun.com 			}
9397946SAndrew.W.Wilson@sun.com 			break;
9408404SAndrew.W.Wilson@sun.com 
9417946SAndrew.W.Wilson@sun.com 		case FSE_TYPE_DIR:
9427556SAndrew.W.Wilson@sun.com 			fileset->fs_idle_dirs++;
9437556SAndrew.W.Wilson@sun.com 			if (fileset->fs_idle_dirs == 1) {
9447556SAndrew.W.Wilson@sun.com 				(void) pthread_cond_signal(
9457556SAndrew.W.Wilson@sun.com 				    &fileset->fs_idle_dirs_cv);
9467556SAndrew.W.Wilson@sun.com 			}
9477946SAndrew.W.Wilson@sun.com 			break;
9488404SAndrew.W.Wilson@sun.com 
9497946SAndrew.W.Wilson@sun.com 		case FSE_TYPE_LEAFDIR:
9507946SAndrew.W.Wilson@sun.com 			fileset->fs_idle_leafdirs++;
9517946SAndrew.W.Wilson@sun.com 			if (fileset->fs_idle_leafdirs == 1) {
9527556SAndrew.W.Wilson@sun.com 				(void) pthread_cond_signal(
9537946SAndrew.W.Wilson@sun.com 				    &fileset->fs_idle_leafdirs_cv);
9547556SAndrew.W.Wilson@sun.com 			}
9557946SAndrew.W.Wilson@sun.com 			break;
9567556SAndrew.W.Wilson@sun.com 		}
9577556SAndrew.W.Wilson@sun.com 	}
9587556SAndrew.W.Wilson@sun.com 
9597556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
9607556SAndrew.W.Wilson@sun.com }
9617556SAndrew.W.Wilson@sun.com 
9627556SAndrew.W.Wilson@sun.com /*
9635184Sek110237  * Given a fileset "fileset", create the associated files as
9645184Sek110237  * specified in the attributes of the fileset. The fileset is
9656212Saw148015  * rooted in a directory whose pathname is in fileset_path. If the
9665184Sek110237  * directory exists, meaning that there is already a fileset,
9676212Saw148015  * and the fileset_reuse attribute is false, then remove it and all
9685184Sek110237  * its contained files and subdirectories. Next, the routine
9695184Sek110237  * creates a root directory for the fileset. All the file type
9705184Sek110237  * filesetentries are cycled through creating as needed
9715184Sek110237  * their containing subdirectory trees in the filesystem and
9726212Saw148015  * creating actual files for fileset_preallocpercent of them. The
9735184Sek110237  * created files are filled with fse_size bytes of unitialized
9747556SAndrew.W.Wilson@sun.com  * data. The routine returns FILEBENCH_ERROR on errors,
9757556SAndrew.W.Wilson@sun.com  * FILEBENCH_OK on success.
9765184Sek110237  */
9775184Sek110237 static int
9785184Sek110237 fileset_create(fileset_t *fileset)
9795184Sek110237 {
9805184Sek110237 	filesetentry_t *entry;
9815184Sek110237 	char path[MAXPATHLEN];
9825184Sek110237 	struct stat64 sb;
9835184Sek110237 	hrtime_t start = gethrtime();
9846212Saw148015 	char *fileset_path;
9856212Saw148015 	char *fileset_name;
9866212Saw148015 	int randno;
9875184Sek110237 	int preallocated = 0;
9887736SAndrew.W.Wilson@sun.com 	int reusing;
9895184Sek110237 
9906212Saw148015 	if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
9915673Saw148015 		filebench_log(LOG_ERROR, "%s path not set",
9925673Saw148015 		    fileset_entity_name(fileset));
9937556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
9945184Sek110237 	}
9955184Sek110237 
9966212Saw148015 	if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
9976212Saw148015 		filebench_log(LOG_ERROR, "%s name not set",
9986212Saw148015 		    fileset_entity_name(fileset));
9997556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
10006212Saw148015 	}
10016212Saw148015 
10025673Saw148015 #ifdef HAVE_RAW_SUPPORT
10035673Saw148015 	/* treat raw device as special case */
10045673Saw148015 	if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
10057556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
10065673Saw148015 #endif /* HAVE_RAW_SUPPORT */
10075673Saw148015 
10085184Sek110237 	/* XXX Add check to see if there is enough space */
10095184Sek110237 
10107736SAndrew.W.Wilson@sun.com 	/* set up path to fileset */
10117946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
10127946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
10137946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, fileset_name, MAXPATHLEN);
10147736SAndrew.W.Wilson@sun.com 
10157736SAndrew.W.Wilson@sun.com 	/* if exists and resusing, then don't create new */
10167736SAndrew.W.Wilson@sun.com 	if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) &&
10177736SAndrew.W.Wilson@sun.com 	    (strlen(avd_get_str(fileset->fs_path)) > 2)) &&
10187736SAndrew.W.Wilson@sun.com 	    avd_get_bool(fileset->fs_reuse)) {
10197736SAndrew.W.Wilson@sun.com 		reusing = 1;
10207736SAndrew.W.Wilson@sun.com 	} else {
10217736SAndrew.W.Wilson@sun.com 		reusing = 0;
10227736SAndrew.W.Wilson@sun.com 	}
10237736SAndrew.W.Wilson@sun.com 
10247736SAndrew.W.Wilson@sun.com 	if (!reusing) {
10257736SAndrew.W.Wilson@sun.com 		char cmd[MAXPATHLEN];
10265184Sek110237 
10277736SAndrew.W.Wilson@sun.com 		/* Remove existing */
10287736SAndrew.W.Wilson@sun.com 		(void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path);
10297736SAndrew.W.Wilson@sun.com 		(void) system(cmd);
10307736SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE,
10317736SAndrew.W.Wilson@sun.com 		    "Removed any existing %s %s in %llu seconds",
10327736SAndrew.W.Wilson@sun.com 		    fileset_entity_name(fileset), fileset_name,
10337736SAndrew.W.Wilson@sun.com 		    (u_longlong_t)(((gethrtime() - start) /
10347736SAndrew.W.Wilson@sun.com 		    1000000000) + 1));
10357736SAndrew.W.Wilson@sun.com 	} else {
10367736SAndrew.W.Wilson@sun.com 		/* we are re-using */
10377736SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE, "Re-using %s %s.",
10387736SAndrew.W.Wilson@sun.com 		    fileset_entity_name(fileset), fileset_name);
10395184Sek110237 	}
10407736SAndrew.W.Wilson@sun.com 
10417736SAndrew.W.Wilson@sun.com 	/* make the filesets directory tree unless in reuse mode */
10427736SAndrew.W.Wilson@sun.com 	if (!reusing && (avd_get_bool(fileset->fs_prealloc))) {
10437946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE,
10447736SAndrew.W.Wilson@sun.com 		    "making tree for filset %s", path);
10455184Sek110237 
1046*8615SAndrew.W.Wilson@sun.com 		(void) FB_MKDIR(path, 0755);
10477736SAndrew.W.Wilson@sun.com 
10487736SAndrew.W.Wilson@sun.com 		if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR)
10497736SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
10507736SAndrew.W.Wilson@sun.com 	}
10515673Saw148015 
10525184Sek110237 	start = gethrtime();
10535184Sek110237 
10545673Saw148015 	filebench_log(LOG_VERBOSE, "Creating %s %s...",
10556212Saw148015 	    fileset_entity_name(fileset), fileset_name);
10565673Saw148015 
10576212Saw148015 	randno = ((RAND_MAX * (100
10586212Saw148015 	    - avd_get_int(fileset->fs_preallocpercent))) / 100);
10596212Saw148015 
10607946SAndrew.W.Wilson@sun.com 	/* alloc any files, as required */
10618404SAndrew.W.Wilson@sun.com 	fileset_pickreset(fileset, FILESET_PICKFILE);
10628404SAndrew.W.Wilson@sun.com 	while (entry = fileset_pick(fileset,
10638404SAndrew.W.Wilson@sun.com 	    FILESET_PICKFREE | FILESET_PICKFILE, 0, 0)) {
10645673Saw148015 		pthread_t tid;
10657736SAndrew.W.Wilson@sun.com 		int newrand;
10665184Sek110237 
10677736SAndrew.W.Wilson@sun.com 		newrand = rand();
10687736SAndrew.W.Wilson@sun.com 
10698404SAndrew.W.Wilson@sun.com 		if (newrand < randno) {
10708404SAndrew.W.Wilson@sun.com 			/* unbusy the unallocated entry */
10718404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
10725184Sek110237 			continue;
10738404SAndrew.W.Wilson@sun.com 		}
10745184Sek110237 
10755184Sek110237 		preallocated++;
10765184Sek110237 
10775673Saw148015 		if (reusing)
10785673Saw148015 			entry->fse_flags |= FSE_REUSING;
10795673Saw148015 		else
10805673Saw148015 			entry->fse_flags &= (~FSE_REUSING);
10815673Saw148015 
10827556SAndrew.W.Wilson@sun.com 		/* fire off allocation threads for each file if paralloc set */
10836212Saw148015 		if (avd_get_bool(fileset->fs_paralloc)) {
10845184Sek110237 
10857556SAndrew.W.Wilson@sun.com 			/* limit total number of simultaneous allocations */
10867556SAndrew.W.Wilson@sun.com 			(void) pthread_mutex_lock(
10877556SAndrew.W.Wilson@sun.com 			    &filebench_shm->shm_fsparalloc_lock);
10887556SAndrew.W.Wilson@sun.com 			while (filebench_shm->shm_fsparalloc_count
10897556SAndrew.W.Wilson@sun.com 			    >= MAX_PARALLOC_THREADS) {
10905673Saw148015 				(void) pthread_cond_wait(
10917556SAndrew.W.Wilson@sun.com 				    &filebench_shm->shm_fsparalloc_cv,
10927556SAndrew.W.Wilson@sun.com 				    &filebench_shm->shm_fsparalloc_lock);
10935673Saw148015 			}
10945673Saw148015 
1095*8615SAndrew.W.Wilson@sun.com 			/* quit if any allocation thread reports an error */
10967556SAndrew.W.Wilson@sun.com 			if (filebench_shm->shm_fsparalloc_count < 0) {
10977556SAndrew.W.Wilson@sun.com 				(void) pthread_mutex_unlock(
10987556SAndrew.W.Wilson@sun.com 				    &filebench_shm->shm_fsparalloc_lock);
10997556SAndrew.W.Wilson@sun.com 				return (FILEBENCH_ERROR);
11005184Sek110237 			}
11015184Sek110237 
11027556SAndrew.W.Wilson@sun.com 			filebench_shm->shm_fsparalloc_count++;
11037556SAndrew.W.Wilson@sun.com 			(void) pthread_mutex_unlock(
11047556SAndrew.W.Wilson@sun.com 			    &filebench_shm->shm_fsparalloc_lock);
11055184Sek110237 
11067556SAndrew.W.Wilson@sun.com 			/*
11077556SAndrew.W.Wilson@sun.com 			 * Fire off a detached allocation thread per file.
11087556SAndrew.W.Wilson@sun.com 			 * The thread will self destruct when it finishes
11097556SAndrew.W.Wilson@sun.com 			 * writing pre-allocation data to the file.
11107556SAndrew.W.Wilson@sun.com 			 */
11115673Saw148015 			if (pthread_create(&tid, NULL,
11125673Saw148015 			    (void *(*)(void*))fileset_alloc_thread,
11137556SAndrew.W.Wilson@sun.com 			    entry) == 0) {
11147556SAndrew.W.Wilson@sun.com 				/*
11157556SAndrew.W.Wilson@sun.com 				 * A thread was created; detach it so it can
11167556SAndrew.W.Wilson@sun.com 				 * fully quit when finished.
11177556SAndrew.W.Wilson@sun.com 				 */
11187556SAndrew.W.Wilson@sun.com 				(void) pthread_detach(tid);
11197556SAndrew.W.Wilson@sun.com 			} else {
11205184Sek110237 				filebench_log(LOG_ERROR,
11215673Saw148015 				    "File prealloc thread create failed");
11225673Saw148015 				filebench_shutdown(1);
11235184Sek110237 			}
11245184Sek110237 
11255673Saw148015 		} else {
11267556SAndrew.W.Wilson@sun.com 			if (fileset_alloc_file(entry) == FILEBENCH_ERROR)
11277556SAndrew.W.Wilson@sun.com 				return (FILEBENCH_ERROR);
11285673Saw148015 		}
11295673Saw148015 	}
11305184Sek110237 
11317946SAndrew.W.Wilson@sun.com 	/* alloc any leaf directories, as required */
11328404SAndrew.W.Wilson@sun.com 	fileset_pickreset(fileset, FILESET_PICKLEAFDIR);
11338404SAndrew.W.Wilson@sun.com 	while (entry = fileset_pick(fileset,
11348404SAndrew.W.Wilson@sun.com 	    FILESET_PICKFREE | FILESET_PICKLEAFDIR, 0, 0)) {
11357946SAndrew.W.Wilson@sun.com 
11368404SAndrew.W.Wilson@sun.com 		if (rand() < randno) {
11378404SAndrew.W.Wilson@sun.com 			/* unbusy the unallocated entry */
11388404SAndrew.W.Wilson@sun.com 			fileset_unbusy(entry, TRUE, FALSE, 0);
11397946SAndrew.W.Wilson@sun.com 			continue;
11408404SAndrew.W.Wilson@sun.com 		}
11417946SAndrew.W.Wilson@sun.com 
11427946SAndrew.W.Wilson@sun.com 		preallocated++;
11437946SAndrew.W.Wilson@sun.com 
11447946SAndrew.W.Wilson@sun.com 		if (reusing)
11457946SAndrew.W.Wilson@sun.com 			entry->fse_flags |= FSE_REUSING;
11467946SAndrew.W.Wilson@sun.com 		else
11477946SAndrew.W.Wilson@sun.com 			entry->fse_flags &= (~FSE_REUSING);
11487946SAndrew.W.Wilson@sun.com 
11497946SAndrew.W.Wilson@sun.com 		if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR)
11507946SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
11517946SAndrew.W.Wilson@sun.com 	}
11527946SAndrew.W.Wilson@sun.com 
11535673Saw148015 exit:
11545184Sek110237 	filebench_log(LOG_VERBOSE,
11556286Saw148015 	    "Preallocated %d of %llu of %s %s in %llu seconds",
11565184Sek110237 	    preallocated,
11576286Saw148015 	    (u_longlong_t)fileset->fs_constentries,
11586212Saw148015 	    fileset_entity_name(fileset), fileset_name,
11596286Saw148015 	    (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1));
11605184Sek110237 
11617556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
11625184Sek110237 }
11635184Sek110237 
11645184Sek110237 /*
11655184Sek110237  * Adds an entry to the fileset's file list. Single threaded so
11665184Sek110237  * no locking needed.
11675184Sek110237  */
11685184Sek110237 static void
11695184Sek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry)
11705184Sek110237 {
11718404SAndrew.W.Wilson@sun.com 	entry->fse_flags = FSE_TYPE_FILE | FSE_FREE;
11728404SAndrew.W.Wilson@sun.com 	avl_add(&fileset->fs_free_files, entry);
11738404SAndrew.W.Wilson@sun.com 
11745184Sek110237 	if (fileset->fs_filelist == NULL) {
11755184Sek110237 		fileset->fs_filelist = entry;
11768404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = NULL;
11775184Sek110237 	} else {
11788404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = fileset->fs_filelist;
11795184Sek110237 		fileset->fs_filelist = entry;
11805184Sek110237 	}
11815184Sek110237 }
11825184Sek110237 
11835184Sek110237 /*
11845184Sek110237  * Adds an entry to the fileset's directory list. Single
11855184Sek110237  * threaded so no locking needed.
11865184Sek110237  */
11875184Sek110237 static void
11885184Sek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry)
11895184Sek110237 {
11908404SAndrew.W.Wilson@sun.com 	entry->fse_flags = FSE_TYPE_DIR | FSE_EXISTS;
11918404SAndrew.W.Wilson@sun.com 	avl_add(&fileset->fs_dirs, entry);
11928404SAndrew.W.Wilson@sun.com 
11935184Sek110237 	if (fileset->fs_dirlist == NULL) {
11945184Sek110237 		fileset->fs_dirlist = entry;
11958404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = NULL;
11965184Sek110237 	} else {
11978404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = fileset->fs_dirlist;
11985184Sek110237 		fileset->fs_dirlist = entry;
11995184Sek110237 	}
12005184Sek110237 }
12015184Sek110237 
12025184Sek110237 /*
12037946SAndrew.W.Wilson@sun.com  * Adds an entry to the fileset's leaf directory list. Single
12047946SAndrew.W.Wilson@sun.com  * threaded so no locking needed.
12057946SAndrew.W.Wilson@sun.com  */
12067946SAndrew.W.Wilson@sun.com static void
12077946SAndrew.W.Wilson@sun.com fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry)
12087946SAndrew.W.Wilson@sun.com {
12098404SAndrew.W.Wilson@sun.com 	entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE;
12108404SAndrew.W.Wilson@sun.com 	avl_add(&fileset->fs_free_leaf_dirs, entry);
12118404SAndrew.W.Wilson@sun.com 
12127946SAndrew.W.Wilson@sun.com 	if (fileset->fs_leafdirlist == NULL) {
12137946SAndrew.W.Wilson@sun.com 		fileset->fs_leafdirlist = entry;
12148404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = NULL;
12157946SAndrew.W.Wilson@sun.com 	} else {
12168404SAndrew.W.Wilson@sun.com 		entry->fse_nextoftype = fileset->fs_leafdirlist;
12177946SAndrew.W.Wilson@sun.com 		fileset->fs_leafdirlist = entry;
12187946SAndrew.W.Wilson@sun.com 	}
12197946SAndrew.W.Wilson@sun.com }
12207946SAndrew.W.Wilson@sun.com 
12217946SAndrew.W.Wilson@sun.com /*
12228404SAndrew.W.Wilson@sun.com  * Compares two fileset entries to determine their relative order
12238404SAndrew.W.Wilson@sun.com  */
12248404SAndrew.W.Wilson@sun.com static int
12258404SAndrew.W.Wilson@sun.com fileset_entry_compare(const void *node_1, const void *node_2)
12268404SAndrew.W.Wilson@sun.com {
12278404SAndrew.W.Wilson@sun.com 	if (((filesetentry_t *)node_1)->fse_index <
12288404SAndrew.W.Wilson@sun.com 	    ((filesetentry_t *)node_2)->fse_index)
12298404SAndrew.W.Wilson@sun.com 		return (-1);
12308404SAndrew.W.Wilson@sun.com 
12318404SAndrew.W.Wilson@sun.com 	if (((filesetentry_t *)node_1)->fse_index ==
12328404SAndrew.W.Wilson@sun.com 	    ((filesetentry_t *)node_2)->fse_index)
12338404SAndrew.W.Wilson@sun.com 		return (0);
12348404SAndrew.W.Wilson@sun.com 
12358404SAndrew.W.Wilson@sun.com 	return (1);
12368404SAndrew.W.Wilson@sun.com }
12378404SAndrew.W.Wilson@sun.com 
12388404SAndrew.W.Wilson@sun.com /*
12397946SAndrew.W.Wilson@sun.com  * Obtains a filesetentry entity for a file to be placed in a
12405184Sek110237  * (sub)directory of a fileset. The size of the file may be
12416212Saw148015  * specified by fileset_meansize, or calculated from a gamma
12426212Saw148015  * distribution of parameter fileset_sizegamma and of mean size
12436212Saw148015  * fileset_meansize. The filesetentry entity is placed on the file
12445184Sek110237  * list in the specified parent filesetentry entity, which may
12455184Sek110237  * be a directory filesetentry, or the root filesetentry in the
12465184Sek110237  * fileset. It is also placed on the fileset's list of all
12477556SAndrew.W.Wilson@sun.com  * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR
12487556SAndrew.W.Wilson@sun.com  * if ipc memory for the path string cannot be allocated.
12495184Sek110237  */
12505184Sek110237 static int
12515184Sek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
12525184Sek110237 {
12535184Sek110237 	char tmpname[16];
12545184Sek110237 	filesetentry_t *entry;
12555184Sek110237 	double drand;
12568404SAndrew.W.Wilson@sun.com 	uint_t index;
12575184Sek110237 
12585184Sek110237 	if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
12595184Sek110237 	    == NULL) {
12605184Sek110237 		filebench_log(LOG_ERROR,
12615184Sek110237 		    "fileset_populate_file: Can't malloc filesetentry");
12627556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
12635184Sek110237 	}
12645184Sek110237 
12657556SAndrew.W.Wilson@sun.com 	/* Another currently idle file */
12667556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
12678404SAndrew.W.Wilson@sun.com 	index = fileset->fs_idle_files++;
12687556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
12697556SAndrew.W.Wilson@sun.com 
12708404SAndrew.W.Wilson@sun.com 	entry->fse_index = index;
12715184Sek110237 	entry->fse_parent = parent;
12725184Sek110237 	entry->fse_fileset = fileset;
12735184Sek110237 	fileset_insfilelist(fileset, entry);
12745184Sek110237 
12755184Sek110237 	(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
12765184Sek110237 	if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
12775184Sek110237 		filebench_log(LOG_ERROR,
12785184Sek110237 		    "fileset_populate_file: Can't alloc path string");
12797556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
12805184Sek110237 	}
12815184Sek110237 
12826212Saw148015 	/* see if random variable was supplied for file size */
12836212Saw148015 	if (fileset->fs_meansize == -1) {
12846212Saw148015 		entry->fse_size = (off64_t)avd_get_int(fileset->fs_size);
12856212Saw148015 	} else {
12866212Saw148015 		double gamma;
12875184Sek110237 
12886212Saw148015 		gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0;
12896212Saw148015 		if (gamma > 0) {
12906212Saw148015 			drand = gamma_dist_knuth(gamma,
12916212Saw148015 			    fileset->fs_meansize / gamma);
12926212Saw148015 			entry->fse_size = (off64_t)drand;
12936212Saw148015 		} else {
12946212Saw148015 			entry->fse_size = (off64_t)fileset->fs_meansize;
12956212Saw148015 		}
12965184Sek110237 	}
12975184Sek110237 
12985184Sek110237 	fileset->fs_bytes += entry->fse_size;
12995184Sek110237 
13005184Sek110237 	fileset->fs_realfiles++;
13017556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
13025184Sek110237 }
13035184Sek110237 
13045184Sek110237 /*
13057946SAndrew.W.Wilson@sun.com  * Obtaines a filesetentry entity for a leaf directory to be placed in a
13067946SAndrew.W.Wilson@sun.com  * (sub)directory of a fileset. The leaf directory will always be empty so
13077946SAndrew.W.Wilson@sun.com  * it can be created and deleted (mkdir, rmdir) at will. The filesetentry
13087946SAndrew.W.Wilson@sun.com  * entity is placed on the leaf directory list in the specified parent
13097946SAndrew.W.Wilson@sun.com  * filesetentry entity, which may be a (sub) directory filesetentry, or
13107946SAndrew.W.Wilson@sun.com  * the root filesetentry in the fileset. It is also placed on the fileset's
13117946SAndrew.W.Wilson@sun.com  * list of all contained leaf directories. Returns FILEBENCH_OK if successful
13127946SAndrew.W.Wilson@sun.com  * or FILEBENCH_ERROR if ipc memory cannot be allocated.
13137946SAndrew.W.Wilson@sun.com  */
13147946SAndrew.W.Wilson@sun.com static int
13157946SAndrew.W.Wilson@sun.com fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial)
13167946SAndrew.W.Wilson@sun.com {
13177946SAndrew.W.Wilson@sun.com 	char tmpname[16];
13187946SAndrew.W.Wilson@sun.com 	filesetentry_t *entry;
13198404SAndrew.W.Wilson@sun.com 	uint_t index;
13207946SAndrew.W.Wilson@sun.com 
13217946SAndrew.W.Wilson@sun.com 	if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
13227946SAndrew.W.Wilson@sun.com 	    == NULL) {
13237946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
13247946SAndrew.W.Wilson@sun.com 		    "fileset_populate_file: Can't malloc filesetentry");
13257946SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13267946SAndrew.W.Wilson@sun.com 	}
13277946SAndrew.W.Wilson@sun.com 
13287946SAndrew.W.Wilson@sun.com 	/* Another currently idle leaf directory */
13297946SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
13308404SAndrew.W.Wilson@sun.com 	index = fileset->fs_idle_leafdirs++;
13317946SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
13327946SAndrew.W.Wilson@sun.com 
13338404SAndrew.W.Wilson@sun.com 	entry->fse_index = index;
13347946SAndrew.W.Wilson@sun.com 	entry->fse_parent = parent;
13357946SAndrew.W.Wilson@sun.com 	entry->fse_fileset = fileset;
13367946SAndrew.W.Wilson@sun.com 	fileset_insleafdirlist(fileset, entry);
13377946SAndrew.W.Wilson@sun.com 
13387946SAndrew.W.Wilson@sun.com 	(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
13397946SAndrew.W.Wilson@sun.com 	if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
13407946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
13417946SAndrew.W.Wilson@sun.com 		    "fileset_populate_file: Can't alloc path string");
13427946SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13437946SAndrew.W.Wilson@sun.com 	}
13447946SAndrew.W.Wilson@sun.com 
13457946SAndrew.W.Wilson@sun.com 	fileset->fs_realleafdirs++;
13467946SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
13477946SAndrew.W.Wilson@sun.com }
13487946SAndrew.W.Wilson@sun.com 
13497946SAndrew.W.Wilson@sun.com /*
13505184Sek110237  * Creates a directory node in a fileset, by obtaining a
13515184Sek110237  * filesetentry entity for the node and initializing it
13525184Sek110237  * according to parameters of the fileset. It determines a
13535184Sek110237  * directory tree depth and directory width, optionally using
13545184Sek110237  * a gamma distribution. If its calculated depth is less then
13555184Sek110237  * its actual depth in the directory tree, it becomes a leaf
13565184Sek110237  * node and files itself with "width" number of file type
13575184Sek110237  * filesetentries, otherwise it files itself with "width"
13585184Sek110237  * number of directory type filesetentries, using recursive
13595184Sek110237  * calls to fileset_populate_subdir. The end result of the
13605184Sek110237  * initial call to this routine is a tree of directories of
13615184Sek110237  * random width and varying depth with sufficient leaf
13625184Sek110237  * directories to contain all required files.
13637556SAndrew.W.Wilson@sun.com  * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path
13647556SAndrew.W.Wilson@sun.com  * string memory cannot be allocated and returns the error code (currently
13657556SAndrew.W.Wilson@sun.com  * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive
13665184Sek110237  * calls to fileset_populate_subdir.
13675184Sek110237  */
13685184Sek110237 static int
13695184Sek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
13705184Sek110237     int serial, double depth)
13715184Sek110237 {
13726212Saw148015 	double randepth, drand, ranwidth;
13735184Sek110237 	int isleaf = 0;
13745184Sek110237 	char tmpname[16];
13755184Sek110237 	filesetentry_t *entry;
13765184Sek110237 	int i;
13778404SAndrew.W.Wilson@sun.com 	uint_t index;
13785184Sek110237 
13795184Sek110237 	depth += 1;
13805184Sek110237 
13815184Sek110237 	/* Create dir node */
13825184Sek110237 	if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
13835184Sek110237 	    == NULL) {
13845184Sek110237 		filebench_log(LOG_ERROR,
13855184Sek110237 		    "fileset_populate_subdir: Can't malloc filesetentry");
13867556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13875184Sek110237 	}
13885184Sek110237 
13897556SAndrew.W.Wilson@sun.com 	/* another idle directory */
13907556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&fileset->fs_pick_lock);
13918404SAndrew.W.Wilson@sun.com 	index = fileset->fs_idle_dirs++;
13927556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
13935184Sek110237 
13945184Sek110237 	(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
13955184Sek110237 	if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
13965184Sek110237 		filebench_log(LOG_ERROR,
13975184Sek110237 		    "fileset_populate_subdir: Can't alloc path string");
13987556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
13995184Sek110237 	}
14005184Sek110237 
14018404SAndrew.W.Wilson@sun.com 	entry->fse_index = index;
14025184Sek110237 	entry->fse_parent = parent;
14037946SAndrew.W.Wilson@sun.com 	entry->fse_fileset = fileset;
14045184Sek110237 	fileset_insdirlist(fileset, entry);
14055184Sek110237 
14066212Saw148015 	if (fileset->fs_dirdepthrv) {
14076212Saw148015 		randepth = (int)avd_get_int(fileset->fs_dirdepthrv);
14085184Sek110237 	} else {
14096212Saw148015 		double gamma;
14106212Saw148015 
14116212Saw148015 		gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0;
14126212Saw148015 		if (gamma > 0) {
14136212Saw148015 			drand = gamma_dist_knuth(gamma,
14146212Saw148015 			    fileset->fs_meandepth / gamma);
14156212Saw148015 			randepth = (int)drand;
14166212Saw148015 		} else {
14176212Saw148015 			randepth = (int)fileset->fs_meandepth;
14186212Saw148015 		}
14195184Sek110237 	}
14205184Sek110237 
14216212Saw148015 	if (fileset->fs_meanwidth == -1) {
14226212Saw148015 		ranwidth = avd_get_dbl(fileset->fs_dirwidth);
14236212Saw148015 	} else {
14246212Saw148015 		double gamma;
14255184Sek110237 
14266212Saw148015 		gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0;
14276212Saw148015 		if (gamma > 0) {
14286212Saw148015 			drand = gamma_dist_knuth(gamma,
14296212Saw148015 			    fileset->fs_meanwidth / gamma);
14306212Saw148015 			ranwidth = drand;
14316212Saw148015 		} else {
14326212Saw148015 			ranwidth = fileset->fs_meanwidth;
14336212Saw148015 		}
14345184Sek110237 	}
14355184Sek110237 
14365184Sek110237 	if (randepth == 0)
14375184Sek110237 		randepth = 1;
14385184Sek110237 	if (ranwidth == 0)
14395184Sek110237 		ranwidth = 1;
14405184Sek110237 	if (depth >= randepth)
14415184Sek110237 		isleaf = 1;
14425184Sek110237 
14435184Sek110237 	/*
14447946SAndrew.W.Wilson@sun.com 	 * Create directory of random width filled with files according
14457946SAndrew.W.Wilson@sun.com 	 * to distribution, or if root directory, continue until #files required
14465184Sek110237 	 */
14476212Saw148015 	for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
14486212Saw148015 	    (fileset->fs_realfiles < fileset->fs_constentries);
14496212Saw148015 	    i++) {
14505184Sek110237 		int ret = 0;
14515184Sek110237 
14525184Sek110237 		if (parent && isleaf)
14535184Sek110237 			ret = fileset_populate_file(fileset, entry, i);
14545184Sek110237 		else
14555184Sek110237 			ret = fileset_populate_subdir(fileset, entry, i, depth);
14565184Sek110237 
14575184Sek110237 		if (ret != 0)
14585184Sek110237 			return (ret);
14595184Sek110237 	}
14607946SAndrew.W.Wilson@sun.com 
14617946SAndrew.W.Wilson@sun.com 	/*
14627946SAndrew.W.Wilson@sun.com 	 * Create directory of random width filled with leaf directories
14637946SAndrew.W.Wilson@sun.com 	 * according to distribution, or if root directory, continue until
14647946SAndrew.W.Wilson@sun.com 	 * the number of leaf directories required has been generated.
14657946SAndrew.W.Wilson@sun.com 	 */
14667946SAndrew.W.Wilson@sun.com 	for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
14677946SAndrew.W.Wilson@sun.com 	    (fileset->fs_realleafdirs < fileset->fs_constleafdirs);
14687946SAndrew.W.Wilson@sun.com 	    i++) {
14697946SAndrew.W.Wilson@sun.com 		int ret = 0;
14707946SAndrew.W.Wilson@sun.com 
14717946SAndrew.W.Wilson@sun.com 		if (parent && isleaf)
14727946SAndrew.W.Wilson@sun.com 			ret = fileset_populate_leafdir(fileset, entry, i);
14737946SAndrew.W.Wilson@sun.com 		else
14747946SAndrew.W.Wilson@sun.com 			ret = fileset_populate_subdir(fileset, entry, i, depth);
14757946SAndrew.W.Wilson@sun.com 
14767946SAndrew.W.Wilson@sun.com 		if (ret != 0)
14777946SAndrew.W.Wilson@sun.com 			return (ret);
14787946SAndrew.W.Wilson@sun.com 	}
14797946SAndrew.W.Wilson@sun.com 
14807556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
14815184Sek110237 }
14825184Sek110237 
14835184Sek110237 /*
14845184Sek110237  * Populates a fileset with files and subdirectory entries. Uses
14856212Saw148015  * the supplied fileset_dirwidth and fileset_entries (number of files) to
14866212Saw148015  * calculate the required fileset_meandepth (of subdirectories) and
14876212Saw148015  * initialize the fileset_meanwidth and fileset_meansize variables. Then
14885184Sek110237  * calls fileset_populate_subdir() to do the recursive
14895184Sek110237  * subdirectory entry creation and leaf file entry creation. All
14905184Sek110237  * of the above is skipped if the fileset has already been
14915184Sek110237  * populated. Returns 0 on success, or an error code from the
14925184Sek110237  * call to fileset_populate_subdir if that call fails.
14935184Sek110237  */
14945184Sek110237 static int
14955184Sek110237 fileset_populate(fileset_t *fileset)
14965184Sek110237 {
14978404SAndrew.W.Wilson@sun.com 	fbint_t entries = avd_get_int(fileset->fs_entries);
14988404SAndrew.W.Wilson@sun.com 	fbint_t leafdirs = avd_get_int(fileset->fs_leafdirs);
14996212Saw148015 	int meandirwidth;
15005184Sek110237 	int ret;
15015184Sek110237 
15025184Sek110237 	/* Skip if already populated */
15035184Sek110237 	if (fileset->fs_bytes > 0)
15045184Sek110237 		goto exists;
15055184Sek110237 
15065673Saw148015 #ifdef HAVE_RAW_SUPPORT
15075673Saw148015 	/* check for raw device */
15085673Saw148015 	if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
15097556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
15105673Saw148015 #endif /* HAVE_RAW_SUPPORT */
15115673Saw148015 
15127946SAndrew.W.Wilson@sun.com 	/*
15137946SAndrew.W.Wilson@sun.com 	 * save value of entries and leaf dirs obtained for later
15147946SAndrew.W.Wilson@sun.com 	 * in case it was random
15157946SAndrew.W.Wilson@sun.com 	 */
15166212Saw148015 	fileset->fs_constentries = entries;
15177946SAndrew.W.Wilson@sun.com 	fileset->fs_constleafdirs = leafdirs;
15186212Saw148015 
15197556SAndrew.W.Wilson@sun.com 	/* initialize idle files and directories condition variables */
15207946SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr());
15217556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr());
15227946SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr());
15237556SAndrew.W.Wilson@sun.com 
15247556SAndrew.W.Wilson@sun.com 	/* no files or dirs idle (or busy) yet */
15257556SAndrew.W.Wilson@sun.com 	fileset->fs_idle_files = 0;
15267556SAndrew.W.Wilson@sun.com 	fileset->fs_idle_dirs = 0;
15277946SAndrew.W.Wilson@sun.com 	fileset->fs_idle_leafdirs = 0;
15287556SAndrew.W.Wilson@sun.com 
15297556SAndrew.W.Wilson@sun.com 	/* initialize locks and other condition variables */
15307556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_init(&fileset->fs_pick_lock,
15317556SAndrew.W.Wilson@sun.com 	    ipc_mutexattr(IPC_MUTEX_NORMAL));
15328404SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_init(&fileset->fs_histo_lock,
15338404SAndrew.W.Wilson@sun.com 	    ipc_mutexattr(IPC_MUTEX_NORMAL));
15347556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr());
15357556SAndrew.W.Wilson@sun.com 
15368404SAndrew.W.Wilson@sun.com 	/* Initialize avl btrees */
15378404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_free_files), fileset_entry_compare,
15388404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15398404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_noex_files), fileset_entry_compare,
15408404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15418404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_exist_files), fileset_entry_compare,
15428404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15438404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_free_leaf_dirs), fileset_entry_compare,
15448404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15458404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_noex_leaf_dirs), fileset_entry_compare,
15468404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15478404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_exist_leaf_dirs), fileset_entry_compare,
15488404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15498404SAndrew.W.Wilson@sun.com 	avl_create(&(fileset->fs_dirs), fileset_entry_compare,
15508404SAndrew.W.Wilson@sun.com 	    sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
15518404SAndrew.W.Wilson@sun.com 
15526212Saw148015 	/* is dirwidth a random variable? */
15536212Saw148015 	if (AVD_IS_RANDOM(fileset->fs_dirwidth)) {
15546212Saw148015 		meandirwidth =
15556212Saw148015 		    (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean;
15566212Saw148015 		fileset->fs_meanwidth = -1;
15576212Saw148015 	} else {
15586212Saw148015 		meandirwidth = (int)avd_get_int(fileset->fs_dirwidth);
15596212Saw148015 		fileset->fs_meanwidth = (double)meandirwidth;
15606212Saw148015 	}
15616212Saw148015 
15625184Sek110237 	/*
15635184Sek110237 	 * Input params are:
15645184Sek110237 	 *	# of files
15655184Sek110237 	 *	ave # of files per dir
15665184Sek110237 	 *	max size of dir
15675184Sek110237 	 *	# ave size of file
15685184Sek110237 	 *	max size of file
15695184Sek110237 	 */
15707946SAndrew.W.Wilson@sun.com 	fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth);
15716212Saw148015 
15726212Saw148015 	/* Has a random variable been supplied for dirdepth? */
15736212Saw148015 	if (fileset->fs_dirdepthrv) {
15746212Saw148015 		/* yes, so set the random variable's mean value to meandepth */
15756212Saw148015 		fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean =
15766212Saw148015 		    fileset->fs_meandepth;
15776212Saw148015 	}
15786212Saw148015 
15796212Saw148015 	/* test for random size variable */
15806212Saw148015 	if (AVD_IS_RANDOM(fileset->fs_size))
15816212Saw148015 		fileset->fs_meansize = -1;
15826212Saw148015 	else
15836212Saw148015 		fileset->fs_meansize = avd_get_int(fileset->fs_size);
15845184Sek110237 
15855184Sek110237 	if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0)
15865184Sek110237 		return (ret);
15875184Sek110237 
15885184Sek110237 
15895184Sek110237 exists:
15905673Saw148015 	if (fileset->fs_attrs & FILESET_IS_FILE) {
15916286Saw148015 		filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu",
15926212Saw148015 		    avd_get_str(fileset->fs_name),
15936286Saw148015 		    (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
15945673Saw148015 	} else {
15957946SAndrew.W.Wilson@sun.com 		filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs "
15966286Saw148015 		    "avg dir = %d, avg depth = %.1lf, mbytes=%llu",
15977946SAndrew.W.Wilson@sun.com 		    avd_get_str(fileset->fs_name), entries, leafdirs,
15986212Saw148015 		    meandirwidth,
15995673Saw148015 		    fileset->fs_meandepth,
16006286Saw148015 		    (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
16015673Saw148015 	}
16026701Saw148015 
16037556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
16045184Sek110237 }
16055184Sek110237 
16065184Sek110237 /*
16076212Saw148015  * Allocates a fileset instance, initializes fileset_dirgamma and
16086212Saw148015  * fileset_sizegamma default values, and sets the fileset name to the
16095184Sek110237  * supplied name string. Puts the allocated fileset on the
16105184Sek110237  * master fileset list and returns a pointer to it.
16116701Saw148015  *
16126701Saw148015  * This routine implements the 'define fileset' calls found in a .f
16136701Saw148015  * workload, such as in the following example:
16146701Saw148015  * define fileset name=drew4ever, entries=$nfiles
16155184Sek110237  */
16165184Sek110237 fileset_t *
16176212Saw148015 fileset_define(avd_t name)
16185184Sek110237 {
16195184Sek110237 	fileset_t *fileset;
16205184Sek110237 
16215184Sek110237 	if (name == NULL)
16225184Sek110237 		return (NULL);
16235184Sek110237 
16245184Sek110237 	if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) {
16255184Sek110237 		filebench_log(LOG_ERROR,
16265184Sek110237 		    "fileset_define: Can't malloc fileset");
16275184Sek110237 		return (NULL);
16285184Sek110237 	}
16295184Sek110237 
16306212Saw148015 	filebench_log(LOG_DEBUG_IMPL,
16316212Saw148015 	    "Defining file %s", avd_get_str(name));
16325184Sek110237 
16336391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
16345184Sek110237 
16356212Saw148015 	fileset->fs_dirgamma = avd_int_alloc(1500);
16366212Saw148015 	fileset->fs_sizegamma = avd_int_alloc(1500);
16378404SAndrew.W.Wilson@sun.com 	fileset->fs_histo_id = -1;
16385184Sek110237 
16395184Sek110237 	/* Add fileset to global list */
16406391Saw148015 	if (filebench_shm->shm_filesetlist == NULL) {
16416391Saw148015 		filebench_shm->shm_filesetlist = fileset;
16425184Sek110237 		fileset->fs_next = NULL;
16435184Sek110237 	} else {
16446391Saw148015 		fileset->fs_next = filebench_shm->shm_filesetlist;
16456391Saw148015 		filebench_shm->shm_filesetlist = fileset;
16465184Sek110237 	}
16475184Sek110237 
16486391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
16495184Sek110237 
16506212Saw148015 	fileset->fs_name = name;
16515184Sek110237 
16525184Sek110237 	return (fileset);
16535184Sek110237 }
16545184Sek110237 
16555184Sek110237 /*
16565184Sek110237  * If supplied with a pointer to a fileset and the fileset's
16576212Saw148015  * fileset_prealloc flag is set, calls fileset_populate() to populate
16585184Sek110237  * the fileset with filesetentries, then calls fileset_create()
16595184Sek110237  * to make actual directories and files for the filesetentries.
16605184Sek110237  * Otherwise, it applies fileset_populate() and fileset_create()
16615184Sek110237  * to all the filesets on the master fileset list. It always
16625184Sek110237  * returns zero (0) if one fileset is populated / created,
16635184Sek110237  * otherwise it returns the sum of returned values from
16645184Sek110237  * fileset_create() and fileset_populate(), which
16655184Sek110237  * will be a negative one (-1) times the number of
16665184Sek110237  * fileset_create() calls which failed.
16675184Sek110237  */
16685184Sek110237 int
16695184Sek110237 fileset_createset(fileset_t *fileset)
16705184Sek110237 {
16715184Sek110237 	fileset_t *list;
16725184Sek110237 	int ret = 0;
16735184Sek110237 
16745673Saw148015 	/* set up for possible parallel allocate */
16757556SAndrew.W.Wilson@sun.com 	filebench_shm->shm_fsparalloc_count = 0;
16767556SAndrew.W.Wilson@sun.com 	(void) pthread_cond_init(
16777556SAndrew.W.Wilson@sun.com 	    &filebench_shm->shm_fsparalloc_cv,
16787556SAndrew.W.Wilson@sun.com 	    ipc_condattr());
16795673Saw148015 
16806212Saw148015 	if (fileset && avd_get_bool(fileset->fs_prealloc)) {
16815673Saw148015 
16826305Saw148015 		/* check for raw files */
16836305Saw148015 		if (fileset_checkraw(fileset)) {
16846305Saw148015 			filebench_log(LOG_INFO,
16856305Saw148015 			    "file %s/%s is a RAW device",
16866305Saw148015 			    avd_get_str(fileset->fs_path),
16876305Saw148015 			    avd_get_str(fileset->fs_name));
16887556SAndrew.W.Wilson@sun.com 			return (FILEBENCH_OK);
16896305Saw148015 		}
16906305Saw148015 
16915673Saw148015 		filebench_log(LOG_INFO,
16925673Saw148015 		    "creating/pre-allocating %s %s",
16936212Saw148015 		    fileset_entity_name(fileset),
16946212Saw148015 		    avd_get_str(fileset->fs_name));
16955673Saw148015 
16967556SAndrew.W.Wilson@sun.com 		if ((ret = fileset_populate(fileset)) != FILEBENCH_OK)
16975184Sek110237 			return (ret);
16985673Saw148015 
16997556SAndrew.W.Wilson@sun.com 		if ((ret = fileset_create(fileset)) != FILEBENCH_OK)
17005673Saw148015 			return (ret);
17015673Saw148015 	} else {
17025673Saw148015 
17035673Saw148015 		filebench_log(LOG_INFO,
17045673Saw148015 		    "Creating/pre-allocating files and filesets");
17055673Saw148015 
17066391Saw148015 		list = filebench_shm->shm_filesetlist;
17075673Saw148015 		while (list) {
17086305Saw148015 			/* check for raw files */
17096305Saw148015 			if (fileset_checkraw(list)) {
17106305Saw148015 				filebench_log(LOG_INFO,
17116305Saw148015 				    "file %s/%s is a RAW device",
17126305Saw148015 				    avd_get_str(list->fs_path),
17136305Saw148015 				    avd_get_str(list->fs_name));
17146305Saw148015 				list = list->fs_next;
17156305Saw148015 				continue;
17166305Saw148015 			}
17176305Saw148015 
17187556SAndrew.W.Wilson@sun.com 			if ((ret = fileset_populate(list)) != FILEBENCH_OK)
17195673Saw148015 				return (ret);
17207556SAndrew.W.Wilson@sun.com 
17217556SAndrew.W.Wilson@sun.com 			if ((ret = fileset_create(list)) != FILEBENCH_OK)
17225673Saw148015 				return (ret);
17237556SAndrew.W.Wilson@sun.com 
17245673Saw148015 			list = list->fs_next;
17255673Saw148015 		}
17265184Sek110237 	}
17275184Sek110237 
17285673Saw148015 	/* wait for allocation threads to finish */
17295673Saw148015 	filebench_log(LOG_INFO,
17305673Saw148015 	    "waiting for fileset pre-allocation to finish");
17315184Sek110237 
17327556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
17337556SAndrew.W.Wilson@sun.com 	while (filebench_shm->shm_fsparalloc_count > 0)
17347556SAndrew.W.Wilson@sun.com 		(void) pthread_cond_wait(
17357556SAndrew.W.Wilson@sun.com 		    &filebench_shm->shm_fsparalloc_cv,
17367556SAndrew.W.Wilson@sun.com 		    &filebench_shm->shm_fsparalloc_lock);
17377556SAndrew.W.Wilson@sun.com 	(void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
17385673Saw148015 
17397556SAndrew.W.Wilson@sun.com 	if (filebench_shm->shm_fsparalloc_count < 0)
17407556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
17415673Saw148015 
17427556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
17435184Sek110237 }
17445184Sek110237 
17455184Sek110237 /*
17465184Sek110237  * Searches through the master fileset list for the named fileset.
17475184Sek110237  * If found, returns pointer to same, otherwise returns NULL.
17485184Sek110237  */
17495184Sek110237 fileset_t *
17505184Sek110237 fileset_find(char *name)
17515184Sek110237 {
17526391Saw148015 	fileset_t *fileset = filebench_shm->shm_filesetlist;
17535184Sek110237 
17546391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
17555184Sek110237 
17565184Sek110237 	while (fileset) {
17576212Saw148015 		if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) {
17586391Saw148015 			(void) ipc_mutex_unlock(
17596391Saw148015 			    &filebench_shm->shm_fileset_lock);
17605184Sek110237 			return (fileset);
17615184Sek110237 		}
17625184Sek110237 		fileset = fileset->fs_next;
17635184Sek110237 	}
17646391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
17655184Sek110237 
17665184Sek110237 	return (NULL);
17675184Sek110237 }
17685673Saw148015 
17695673Saw148015 /*
17705673Saw148015  * Iterates over all the file sets in the filesetlist,
17715673Saw148015  * executing the supplied command "*cmd()" on them. Also
17725673Saw148015  * indicates to the executed command if it is the first
17735673Saw148015  * time the command has been executed since the current
17745673Saw148015  * call to fileset_iter.
17755673Saw148015  */
17768404SAndrew.W.Wilson@sun.com int
17775673Saw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first))
17785673Saw148015 {
17796391Saw148015 	fileset_t *fileset = filebench_shm->shm_filesetlist;
17805673Saw148015 	int count = 0;
17815673Saw148015 
17826391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
17835673Saw148015 
17845673Saw148015 	while (fileset) {
17858404SAndrew.W.Wilson@sun.com 		if (cmd(fileset, count == 0) == FILEBENCH_ERROR) {
17868404SAndrew.W.Wilson@sun.com 			(void) ipc_mutex_unlock(
17878404SAndrew.W.Wilson@sun.com 			    &filebench_shm->shm_fileset_lock);
17888404SAndrew.W.Wilson@sun.com 			return (FILEBENCH_ERROR);
17898404SAndrew.W.Wilson@sun.com 		}
17905673Saw148015 		fileset = fileset->fs_next;
17915673Saw148015 		count++;
17925673Saw148015 	}
17935673Saw148015 
17946391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
17958404SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
17965673Saw148015 }
17975673Saw148015 
17985673Saw148015 /*
17995673Saw148015  * Prints information to the filebench log about the file
18005673Saw148015  * object. Also prints a header on the first call.
18015673Saw148015  */
18025673Saw148015 int
18035673Saw148015 fileset_print(fileset_t *fileset, int first)
18045673Saw148015 {
18056212Saw148015 	int pathlength;
18066212Saw148015 	char *fileset_path;
18076212Saw148015 	char *fileset_name;
18086212Saw148015 	static char pad[] = "                              "; /* 30 spaces */
18096212Saw148015 
18106212Saw148015 	if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
18116212Saw148015 		filebench_log(LOG_ERROR, "%s path not set",
18126212Saw148015 		    fileset_entity_name(fileset));
18137556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
18146212Saw148015 	}
18156212Saw148015 
18166212Saw148015 	if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
18176212Saw148015 		filebench_log(LOG_ERROR, "%s name not set",
18186212Saw148015 		    fileset_entity_name(fileset));
18197556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_ERROR);
18206212Saw148015 	}
18216212Saw148015 
18226212Saw148015 	pathlength = strlen(fileset_path) + strlen(fileset_name);
18235673Saw148015 
18245673Saw148015 	if (pathlength > 29)
18255673Saw148015 		pathlength = 29;
18265673Saw148015 
18275673Saw148015 	if (first) {
18285673Saw148015 		filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s",
18295673Saw148015 		    "file size",
18305673Saw148015 		    "dir width",
18315673Saw148015 		    "entries");
18325673Saw148015 	}
18335673Saw148015 
18345673Saw148015 	if (fileset->fs_attrs & FILESET_IS_FILE) {
18355673Saw148015 		if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
18365673Saw148015 			filebench_log(LOG_INFO,
18375673Saw148015 			    "%s/%s%s         (Raw Device)",
18386212Saw148015 			    fileset_path, fileset_name, &pad[pathlength]);
18395673Saw148015 		} else {
18405673Saw148015 			filebench_log(LOG_INFO,
18416286Saw148015 			    "%s/%s%s%9llu     (Single File)",
18426212Saw148015 			    fileset_path, fileset_name, &pad[pathlength],
18436286Saw148015 			    (u_longlong_t)avd_get_int(fileset->fs_size));
18445673Saw148015 		}
18455673Saw148015 	} else {
18466286Saw148015 		filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu",
18476212Saw148015 		    fileset_path, fileset_name,
18485673Saw148015 		    &pad[pathlength],
18496286Saw148015 		    (u_longlong_t)avd_get_int(fileset->fs_size),
18506286Saw148015 		    (u_longlong_t)avd_get_int(fileset->fs_dirwidth),
18516286Saw148015 		    (u_longlong_t)fileset->fs_constentries);
18525673Saw148015 	}
18537556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
18545673Saw148015 }
18557946SAndrew.W.Wilson@sun.com 
18565673Saw148015 /*
18575673Saw148015  * checks to see if the path/name pair points to a raw device. If
18585673Saw148015  * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1.
18595673Saw148015  * If RAW is not defined, or it is not a raw device, it clears the
18605673Saw148015  * raw device flag and returns 0.
18615673Saw148015  */
18625673Saw148015 int
18635673Saw148015 fileset_checkraw(fileset_t *fileset)
18645673Saw148015 {
18655673Saw148015 	char path[MAXPATHLEN];
18665673Saw148015 	struct stat64 sb;
18676305Saw148015 	char *pathname;
18686305Saw148015 	char *setname;
18695673Saw148015 
18705673Saw148015 	fileset->fs_attrs &= (~FILESET_IS_RAW_DEV);
18715673Saw148015 
18725673Saw148015 #ifdef HAVE_RAW_SUPPORT
18735673Saw148015 	/* check for raw device */
18746305Saw148015 	if ((pathname = avd_get_str(fileset->fs_path)) == NULL)
18757556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
18766305Saw148015 
18776305Saw148015 	if ((setname = avd_get_str(fileset->fs_name)) == NULL)
18787556SAndrew.W.Wilson@sun.com 		return (FILEBENCH_OK);
18796305Saw148015 
18807946SAndrew.W.Wilson@sun.com 	(void) fb_strlcpy(path, pathname, MAXPATHLEN);
18817946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, "/", MAXPATHLEN);
18827946SAndrew.W.Wilson@sun.com 	(void) fb_strlcat(path, setname, MAXPATHLEN);
18835673Saw148015 	if ((stat64(path, &sb) == 0) &&
18845673Saw148015 	    ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) {
18855673Saw148015 		fileset->fs_attrs |= FILESET_IS_RAW_DEV;
18866305Saw148015 		if (!(fileset->fs_attrs & FILESET_IS_FILE)) {
18876305Saw148015 			filebench_log(LOG_ERROR,
18886305Saw148015 			    "WARNING Fileset %s/%s Cannot be RAW device",
18896305Saw148015 			    avd_get_str(fileset->fs_path),
18906305Saw148015 			    avd_get_str(fileset->fs_name));
18916305Saw148015 			filebench_shutdown(1);
18926305Saw148015 		}
18936305Saw148015 
18945673Saw148015 		return (1);
18955673Saw148015 	}
18965673Saw148015 #endif /* HAVE_RAW_SUPPORT */
18975673Saw148015 
18987556SAndrew.W.Wilson@sun.com 	return (FILEBENCH_OK);
18995673Saw148015 }
1900