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 /*
228615SAndrew.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"
408615SAndrew.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 *
fileset_entity_name(fileset_t * fileset)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 *
trunc_dirname(char * dir)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
fileset_usage(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 *
fileset_resolvepath(filesetentry_t * entry)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
fileset_mkdir(char * path,int mode)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--) {
2018615SAndrew.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
fileset_create_subdirs(fileset_t * fileset,char * filesetpath)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
fileset_move_entry(avl_tree_t * src_tree,avl_tree_t * dst_tree,filesetentry_t * entry)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
fileset_alloc_leafdir(filesetentry_t * entry)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 */
2838615SAndrew.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
fileset_alloc_file(filesetentry_t * entry)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;
3108615SAndrew.W.Wilson@sun.com fb_fdesc_t fdesc;
3119326SAndrew.W.Wilson@sun.com int trust_tree;
3125673Saw148015
3137946SAndrew.W.Wilson@sun.com fileset = entry->fse_fileset;
3147946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
3157946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
3167946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
3175673Saw148015 pathtmp = fileset_resolvepath(entry);
3187946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
3197946SAndrew.W.Wilson@sun.com free(pathtmp);
3205673Saw148015
3215673Saw148015 filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
3225673Saw148015
3235673Saw148015 /* see if reusing and this file exists */
3249326SAndrew.W.Wilson@sun.com trust_tree = avd_get_bool(fileset->fs_trust_tree);
3259326SAndrew.W.Wilson@sun.com if ((entry->fse_flags & FSE_REUSING) && (trust_tree ||
3269326SAndrew.W.Wilson@sun.com (FB_STAT(path, &sb) == 0))) {
3278615SAndrew.W.Wilson@sun.com if (FB_OPEN(&fdesc, path, O_RDWR, 0) == FILEBENCH_ERROR) {
3285673Saw148015 filebench_log(LOG_INFO,
3295673Saw148015 "Attempted but failed to Re-use file %s",
3305673Saw148015 path);
3318404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, FALSE, 0);
3327556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
3335673Saw148015 }
3345673Saw148015
3359326SAndrew.W.Wilson@sun.com if (trust_tree || (sb.st_size == (off64_t)entry->fse_size)) {
3367556SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL,
3375673Saw148015 "Re-using file %s", path);
3385673Saw148015
3397946SAndrew.W.Wilson@sun.com if (!avd_get_bool(fileset->fs_cached))
3408615SAndrew.W.Wilson@sun.com (void) FB_FREEMEM(&fdesc, entry->fse_size);
3415673Saw148015
3428615SAndrew.W.Wilson@sun.com (void) FB_CLOSE(&fdesc);
3436701Saw148015
3448404SAndrew.W.Wilson@sun.com /* unbusy the allocated entry */
3458404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, TRUE, 0);
3467556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
3475673Saw148015
3485673Saw148015 } else if (sb.st_size > (off64_t)entry->fse_size) {
3495673Saw148015 /* reuse, but too large */
3508404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL,
3515673Saw148015 "Truncating & re-using file %s", path);
3525673Saw148015
3538615SAndrew.W.Wilson@sun.com (void) FB_FTRUNC(&fdesc, (off64_t)entry->fse_size);
3545673Saw148015
3557946SAndrew.W.Wilson@sun.com if (!avd_get_bool(fileset->fs_cached))
3568615SAndrew.W.Wilson@sun.com (void) FB_FREEMEM(&fdesc, entry->fse_size);
3575673Saw148015
3588615SAndrew.W.Wilson@sun.com (void) FB_CLOSE(&fdesc);
3596701Saw148015
3608404SAndrew.W.Wilson@sun.com /* unbusy the allocated entry */
3618404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, TRUE, 0);
3627556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
3635673Saw148015 }
3645673Saw148015 } else {
3655673Saw148015
3665673Saw148015 /* No file or not reusing, so create */
3678615SAndrew.W.Wilson@sun.com if (FB_OPEN(&fdesc, path, O_RDWR | O_CREAT, 0644) ==
3688615SAndrew.W.Wilson@sun.com FILEBENCH_ERROR) {
3695673Saw148015 filebench_log(LOG_ERROR,
3705673Saw148015 "Failed to pre-allocate file %s: %s",
3715673Saw148015 path, strerror(errno));
3725673Saw148015
3738404SAndrew.W.Wilson@sun.com /* unbusy the unallocated entry */
3748404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, FALSE, 0);
3757556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
3765673Saw148015 }
3775673Saw148015 }
3785673Saw148015
3798404SAndrew.W.Wilson@sun.com if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) {
3808404SAndrew.W.Wilson@sun.com /* unbusy the unallocated entry */
3818404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, FALSE, 0);
3827556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
3838404SAndrew.W.Wilson@sun.com }
3846701Saw148015
3855673Saw148015 for (seek = 0; seek < entry->fse_size; ) {
3865673Saw148015 off64_t wsize;
3875673Saw148015 int ret = 0;
3885673Saw148015
3895673Saw148015 /*
3905673Saw148015 * Write FILE_ALLOC_BLOCK's worth,
3915673Saw148015 * except on last write
3925673Saw148015 */
3935673Saw148015 wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK);
3945673Saw148015
3958615SAndrew.W.Wilson@sun.com ret = FB_WRITE(&fdesc, buf, wsize);
3965673Saw148015 if (ret != wsize) {
3975673Saw148015 filebench_log(LOG_ERROR,
3985673Saw148015 "Failed to pre-allocate file %s: %s",
3995673Saw148015 path, strerror(errno));
4008615SAndrew.W.Wilson@sun.com (void) FB_CLOSE(&fdesc);
4015673Saw148015 free(buf);
4028404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, FALSE, 0);
4037556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
4045673Saw148015 }
4055673Saw148015 seek += wsize;
4065673Saw148015 }
4075673Saw148015
4087946SAndrew.W.Wilson@sun.com if (!avd_get_bool(fileset->fs_cached))
4098615SAndrew.W.Wilson@sun.com (void) FB_FREEMEM(&fdesc, entry->fse_size);
4105673Saw148015
4118615SAndrew.W.Wilson@sun.com (void) FB_CLOSE(&fdesc);
4125673Saw148015
4135673Saw148015 free(buf);
4145673Saw148015
4158404SAndrew.W.Wilson@sun.com /* unbusy the allocated entry */
4168404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, TRUE, 0);
4178404SAndrew.W.Wilson@sun.com
4185673Saw148015 filebench_log(LOG_DEBUG_IMPL,
4196286Saw148015 "Pre-allocated file %s size %llu",
4206286Saw148015 path, (u_longlong_t)entry->fse_size);
4215673Saw148015
4227556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
4235673Saw148015 }
4245673Saw148015
4255673Saw148015 /*
4265673Saw148015 * given a fileset entry, determines if the associated file
4275673Saw148015 * needs to be allocated or not, and if so does the allocation.
4287556SAndrew.W.Wilson@sun.com * Sets shm_fsparalloc_count to -1 on error.
4295673Saw148015 */
4305673Saw148015 static void *
fileset_alloc_thread(filesetentry_t * entry)4315673Saw148015 fileset_alloc_thread(filesetentry_t *entry)
4325673Saw148015 {
4337556SAndrew.W.Wilson@sun.com if (fileset_alloc_file(entry) == FILEBENCH_ERROR) {
4347556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
4357556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count = -1;
4365673Saw148015 } else {
4377556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
4387556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count--;
4395673Saw148015 }
4405673Saw148015
4417556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv);
4427556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
4435673Saw148015
4445673Saw148015 pthread_exit(NULL);
4455673Saw148015 return (NULL);
4465673Saw148015 }
4475673Saw148015
4485184Sek110237
4495184Sek110237 /*
4505184Sek110237 * First creates the parent directories of the file using
4515184Sek110237 * fileset_mkdir(). Then Optionally sets the O_DSYNC flag
4525184Sek110237 * and opens the file with open64(). It unlocks the fileset
4535184Sek110237 * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags
4545184Sek110237 * as requested, and returns the file descriptor integer
4558615SAndrew.W.Wilson@sun.com * for the opened file in the supplied filebench file descriptor.
4568615SAndrew.W.Wilson@sun.com * Returns FILEBENCH_ERROR on error, and FILEBENCH_OK on success.
4575184Sek110237 */
4585184Sek110237 int
fileset_openfile(fb_fdesc_t * fdesc,fileset_t * fileset,filesetentry_t * entry,int flag,int filemode,int attrs)4598615SAndrew.W.Wilson@sun.com fileset_openfile(fb_fdesc_t *fdesc, fileset_t *fileset,
4607736SAndrew.W.Wilson@sun.com filesetentry_t *entry, int flag, int filemode, int attrs)
4615184Sek110237 {
4625184Sek110237 char path[MAXPATHLEN];
4635184Sek110237 char dir[MAXPATHLEN];
4645184Sek110237 char *pathtmp;
4655184Sek110237 struct stat64 sb;
4665184Sek110237 int open_attrs = 0;
4675184Sek110237
4687946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
4697946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
4707946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
4715184Sek110237 pathtmp = fileset_resolvepath(entry);
4727946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
4737946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(dir, path, MAXPATHLEN);
4745184Sek110237 free(pathtmp);
4755184Sek110237 (void) trunc_dirname(dir);
4765184Sek110237
4775184Sek110237 /* If we are going to create a file, create the parent dirs */
4785184Sek110237 if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) {
4797556SAndrew.W.Wilson@sun.com if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR)
4807556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
4816701Saw148015 }
4826701Saw148015
4835184Sek110237 if (attrs & FLOW_ATTR_DSYNC) {
4845184Sek110237 #ifdef sun
4855184Sek110237 open_attrs |= O_DSYNC;
4865184Sek110237 #else
4875184Sek110237 open_attrs |= O_FSYNC;
4885184Sek110237 #endif
4895184Sek110237 }
4905184Sek110237
4918615SAndrew.W.Wilson@sun.com if (FB_OPEN(fdesc, path, flag | open_attrs, filemode)
4928615SAndrew.W.Wilson@sun.com == FILEBENCH_ERROR) {
4935184Sek110237 filebench_log(LOG_ERROR,
4948404SAndrew.W.Wilson@sun.com "Failed to open file %d, %s, with status %x: %s",
4958404SAndrew.W.Wilson@sun.com entry->fse_index, path, entry->fse_flags, strerror(errno));
4967556SAndrew.W.Wilson@sun.com
4978404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE, 0);
4987556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
4995184Sek110237 }
5007556SAndrew.W.Wilson@sun.com
5017556SAndrew.W.Wilson@sun.com if (flag & O_CREAT)
5028404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, TRUE, 1);
5037556SAndrew.W.Wilson@sun.com else
5048404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, FALSE, FALSE, 1);
5055184Sek110237
5065184Sek110237 #ifdef sun
5075184Sek110237 if (attrs & FLOW_ATTR_DIRECTIO)
5088615SAndrew.W.Wilson@sun.com (void) directio(fdesc->fd_num, DIRECTIO_ON);
5095184Sek110237 else
5108615SAndrew.W.Wilson@sun.com (void) directio(fdesc->fd_num, DIRECTIO_OFF);
5115184Sek110237 #endif
5125184Sek110237
5138615SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
5145184Sek110237 }
5155184Sek110237
5168404SAndrew.W.Wilson@sun.com /*
5178404SAndrew.W.Wilson@sun.com * removes all filesetentries from their respective btrees, and puts them
5188404SAndrew.W.Wilson@sun.com * on the free list. The supplied argument indicates which free list to
5198404SAndrew.W.Wilson@sun.com * use.
5208404SAndrew.W.Wilson@sun.com */
5218404SAndrew.W.Wilson@sun.com static void
fileset_pickreset(fileset_t * fileset,int entry_type)5228404SAndrew.W.Wilson@sun.com fileset_pickreset(fileset_t *fileset, int entry_type)
5238404SAndrew.W.Wilson@sun.com {
5248404SAndrew.W.Wilson@sun.com filesetentry_t *entry;
5258404SAndrew.W.Wilson@sun.com
5268404SAndrew.W.Wilson@sun.com switch (entry_type & FILESET_PICKMASK) {
5278404SAndrew.W.Wilson@sun.com case FILESET_PICKFILE:
5288404SAndrew.W.Wilson@sun.com entry = (filesetentry_t *)avl_first(&fileset->fs_noex_files);
5298404SAndrew.W.Wilson@sun.com
5308404SAndrew.W.Wilson@sun.com /* make sure non-existing files are marked free */
5318404SAndrew.W.Wilson@sun.com while (entry) {
5328404SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE;
5338404SAndrew.W.Wilson@sun.com entry->fse_open_cnt = 0;
5348404SAndrew.W.Wilson@sun.com fileset_move_entry(&fileset->fs_noex_files,
5358404SAndrew.W.Wilson@sun.com &fileset->fs_free_files, entry);
5368404SAndrew.W.Wilson@sun.com entry = AVL_NEXT(&fileset->fs_noex_files, entry);
5378404SAndrew.W.Wilson@sun.com }
5388404SAndrew.W.Wilson@sun.com
5398404SAndrew.W.Wilson@sun.com /* free up any existing files */
5408404SAndrew.W.Wilson@sun.com entry = (filesetentry_t *)avl_first(&fileset->fs_exist_files);
5418404SAndrew.W.Wilson@sun.com
5428404SAndrew.W.Wilson@sun.com while (entry) {
5438404SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE;
5448404SAndrew.W.Wilson@sun.com entry->fse_open_cnt = 0;
5458404SAndrew.W.Wilson@sun.com fileset_move_entry(&fileset->fs_exist_files,
5468404SAndrew.W.Wilson@sun.com &fileset->fs_free_files, entry);
5478404SAndrew.W.Wilson@sun.com
5488404SAndrew.W.Wilson@sun.com entry = AVL_NEXT(&fileset->fs_exist_files, entry);
5498404SAndrew.W.Wilson@sun.com }
5508404SAndrew.W.Wilson@sun.com
5518404SAndrew.W.Wilson@sun.com break;
5528404SAndrew.W.Wilson@sun.com
5538404SAndrew.W.Wilson@sun.com case FILESET_PICKDIR:
5548404SAndrew.W.Wilson@sun.com /* nothing to reset, as all (sub)dirs always exist */
5558404SAndrew.W.Wilson@sun.com break;
5568404SAndrew.W.Wilson@sun.com
5578404SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR:
5588404SAndrew.W.Wilson@sun.com entry = (filesetentry_t *)
5598404SAndrew.W.Wilson@sun.com avl_first(&fileset->fs_noex_leaf_dirs);
5608404SAndrew.W.Wilson@sun.com
5618404SAndrew.W.Wilson@sun.com /* make sure non-existing leaf dirs are marked free */
5628404SAndrew.W.Wilson@sun.com while (entry) {
5638404SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE;
5648404SAndrew.W.Wilson@sun.com entry->fse_open_cnt = 0;
5658404SAndrew.W.Wilson@sun.com fileset_move_entry(&fileset->fs_noex_leaf_dirs,
5668404SAndrew.W.Wilson@sun.com &fileset->fs_free_leaf_dirs, entry);
5678404SAndrew.W.Wilson@sun.com entry = AVL_NEXT(&fileset->fs_noex_leaf_dirs, entry);
5688404SAndrew.W.Wilson@sun.com }
5698404SAndrew.W.Wilson@sun.com
5708404SAndrew.W.Wilson@sun.com /* free up any existing leaf dirs */
5718404SAndrew.W.Wilson@sun.com entry = (filesetentry_t *)
5728404SAndrew.W.Wilson@sun.com avl_first(&fileset->fs_exist_leaf_dirs);
5738404SAndrew.W.Wilson@sun.com
5748404SAndrew.W.Wilson@sun.com while (entry) {
5758404SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_FREE;
5768404SAndrew.W.Wilson@sun.com entry->fse_open_cnt = 0;
5778404SAndrew.W.Wilson@sun.com fileset_move_entry(&fileset->fs_exist_leaf_dirs,
5788404SAndrew.W.Wilson@sun.com &fileset->fs_free_leaf_dirs, entry);
5798404SAndrew.W.Wilson@sun.com
5808404SAndrew.W.Wilson@sun.com entry = AVL_NEXT(&fileset->fs_exist_leaf_dirs, entry);
5818404SAndrew.W.Wilson@sun.com }
5828404SAndrew.W.Wilson@sun.com
5838404SAndrew.W.Wilson@sun.com break;
5848404SAndrew.W.Wilson@sun.com }
5858404SAndrew.W.Wilson@sun.com }
5868404SAndrew.W.Wilson@sun.com
5878404SAndrew.W.Wilson@sun.com /*
5888404SAndrew.W.Wilson@sun.com * find a filesetentry from the fileset using the supplied index
5898404SAndrew.W.Wilson@sun.com */
5908404SAndrew.W.Wilson@sun.com static filesetentry_t *
fileset_find_entry(avl_tree_t * atp,uint_t index)5918404SAndrew.W.Wilson@sun.com fileset_find_entry(avl_tree_t *atp, uint_t index)
5928404SAndrew.W.Wilson@sun.com {
5938404SAndrew.W.Wilson@sun.com avl_index_t found_loc;
5948404SAndrew.W.Wilson@sun.com filesetentry_t desired_fse, *found_fse;
5958404SAndrew.W.Wilson@sun.com
5968404SAndrew.W.Wilson@sun.com /* find the file with the desired index, if it is in the tree */
5978404SAndrew.W.Wilson@sun.com desired_fse.fse_index = index;
5988404SAndrew.W.Wilson@sun.com found_fse = avl_find(atp, (void *)(&desired_fse), &found_loc);
5998404SAndrew.W.Wilson@sun.com if (found_fse != NULL)
6008404SAndrew.W.Wilson@sun.com return (found_fse);
6018404SAndrew.W.Wilson@sun.com
6028404SAndrew.W.Wilson@sun.com /* if requested node not found, find next higher node */
6038404SAndrew.W.Wilson@sun.com found_fse = avl_nearest(atp, found_loc, AVL_AFTER);
6048404SAndrew.W.Wilson@sun.com if (found_fse != NULL)
6058404SAndrew.W.Wilson@sun.com return (found_fse);
6068404SAndrew.W.Wilson@sun.com
6078404SAndrew.W.Wilson@sun.com /* might have hit the end, return lowest available index node */
6088404SAndrew.W.Wilson@sun.com found_fse = avl_first(atp);
6098404SAndrew.W.Wilson@sun.com return (found_fse);
6108404SAndrew.W.Wilson@sun.com }
6115184Sek110237
6125184Sek110237 /*
6135184Sek110237 * Selects a fileset entry from a fileset. If the
6147946SAndrew.W.Wilson@sun.com * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry,
6157946SAndrew.W.Wilson@sun.com * if the FILESET_PICKDIR flag is set it will pick a non leaf directory
6168404SAndrew.W.Wilson@sun.com * entry, otherwise a file entry. The FILESET_PICKUNIQUE
6175184Sek110237 * flag will take an entry off of one of the free (unused)
6185184Sek110237 * lists (file or directory), otherwise the entry will be
6195184Sek110237 * picked off of one of the rotor lists (file or directory).
6205184Sek110237 * The FILESET_PICKEXISTS will insure that only extant
6215184Sek110237 * (FSE_EXISTS) state files are selected, while
6225184Sek110237 * FILESET_PICKNOEXIST insures that only non extant
6235184Sek110237 * (not FSE_EXISTS) state files are selected.
6246391Saw148015 * Note that the selected fileset entry (file) is returned
6257556SAndrew.W.Wilson@sun.com * with its FSE_BUSY flag (in fse_flags) set.
6265184Sek110237 */
6275184Sek110237 filesetentry_t *
fileset_pick(fileset_t * fileset,int flags,int tid,int index)6288404SAndrew.W.Wilson@sun.com fileset_pick(fileset_t *fileset, int flags, int tid, int index)
6295184Sek110237 {
6305184Sek110237 filesetentry_t *entry = NULL;
6318404SAndrew.W.Wilson@sun.com filesetentry_t *start_point;
6328404SAndrew.W.Wilson@sun.com avl_tree_t *atp;
6338404SAndrew.W.Wilson@sun.com fbint_t max_entries;
6345184Sek110237
6357556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
6367556SAndrew.W.Wilson@sun.com
6377556SAndrew.W.Wilson@sun.com /* see if we have to wait for available files or directories */
6387946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) {
6397946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE:
6407946SAndrew.W.Wilson@sun.com if (fileset->fs_filelist == NULL)
6417946SAndrew.W.Wilson@sun.com goto empty;
6428404SAndrew.W.Wilson@sun.com
6437556SAndrew.W.Wilson@sun.com while (fileset->fs_idle_files == 0) {
6447556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_files_cv,
6457556SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock);
6467556SAndrew.W.Wilson@sun.com }
6478404SAndrew.W.Wilson@sun.com
6488404SAndrew.W.Wilson@sun.com max_entries = fileset->fs_constentries;
6498404SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKUNIQUE) {
6508404SAndrew.W.Wilson@sun.com atp = &fileset->fs_free_files;
6518404SAndrew.W.Wilson@sun.com } else if (flags & FILESET_PICKNOEXIST) {
6528404SAndrew.W.Wilson@sun.com atp = &fileset->fs_noex_files;
6538404SAndrew.W.Wilson@sun.com } else {
6548404SAndrew.W.Wilson@sun.com atp = &fileset->fs_exist_files;
6558404SAndrew.W.Wilson@sun.com }
6567946SAndrew.W.Wilson@sun.com break;
6578404SAndrew.W.Wilson@sun.com
6587946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR:
6597946SAndrew.W.Wilson@sun.com if (fileset->fs_dirlist == NULL)
6607946SAndrew.W.Wilson@sun.com goto empty;
6618404SAndrew.W.Wilson@sun.com
6627946SAndrew.W.Wilson@sun.com while (fileset->fs_idle_dirs == 0) {
6637946SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv,
6647946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock);
6657946SAndrew.W.Wilson@sun.com }
6668404SAndrew.W.Wilson@sun.com
6678404SAndrew.W.Wilson@sun.com max_entries = 1;
6688404SAndrew.W.Wilson@sun.com atp = &fileset->fs_dirs;
6697946SAndrew.W.Wilson@sun.com break;
6708404SAndrew.W.Wilson@sun.com
6717946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR:
6727946SAndrew.W.Wilson@sun.com if (fileset->fs_leafdirlist == NULL)
6737946SAndrew.W.Wilson@sun.com goto empty;
6748404SAndrew.W.Wilson@sun.com
6757946SAndrew.W.Wilson@sun.com while (fileset->fs_idle_leafdirs == 0) {
6767946SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv,
6777946SAndrew.W.Wilson@sun.com &fileset->fs_pick_lock);
6787946SAndrew.W.Wilson@sun.com }
6798404SAndrew.W.Wilson@sun.com
6808404SAndrew.W.Wilson@sun.com max_entries = fileset->fs_constleafdirs;
6818404SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKUNIQUE) {
6828404SAndrew.W.Wilson@sun.com atp = &fileset->fs_free_leaf_dirs;
6838404SAndrew.W.Wilson@sun.com } else if (flags & FILESET_PICKNOEXIST) {
6848404SAndrew.W.Wilson@sun.com atp = &fileset->fs_noex_leaf_dirs;
6858404SAndrew.W.Wilson@sun.com } else {
6868404SAndrew.W.Wilson@sun.com atp = &fileset->fs_exist_leaf_dirs;
6878404SAndrew.W.Wilson@sun.com }
6887946SAndrew.W.Wilson@sun.com break;
6897556SAndrew.W.Wilson@sun.com }
6905184Sek110237
6916701Saw148015 /* see if asking for impossible */
6928404SAndrew.W.Wilson@sun.com if (avl_is_empty(atp))
6938404SAndrew.W.Wilson@sun.com goto empty;
6948404SAndrew.W.Wilson@sun.com
6958404SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKUNIQUE) {
6968404SAndrew.W.Wilson@sun.com uint64_t index64;
6978404SAndrew.W.Wilson@sun.com
6988404SAndrew.W.Wilson@sun.com /*
6998404SAndrew.W.Wilson@sun.com * pick at random from free list in order to
7008404SAndrew.W.Wilson@sun.com * distribute initially allocated files more
7018404SAndrew.W.Wilson@sun.com * randomly on storage media. Use uniform
7028404SAndrew.W.Wilson@sun.com * random number generator to select index
7038404SAndrew.W.Wilson@sun.com * if it is not supplied with pick call.
7048404SAndrew.W.Wilson@sun.com */
7058404SAndrew.W.Wilson@sun.com if (index) {
7068404SAndrew.W.Wilson@sun.com index64 = index;
7078404SAndrew.W.Wilson@sun.com } else {
7088404SAndrew.W.Wilson@sun.com if (filebench_randomno64(&index64, max_entries, 1,
7098404SAndrew.W.Wilson@sun.com NULL) == FILEBENCH_ERROR)
7107946SAndrew.W.Wilson@sun.com return (NULL);
7115184Sek110237 }
7125184Sek110237
7138404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp, (int)index64);
7148404SAndrew.W.Wilson@sun.com
7158404SAndrew.W.Wilson@sun.com if (entry == NULL)
7168404SAndrew.W.Wilson@sun.com goto empty;
7178404SAndrew.W.Wilson@sun.com
7188404SAndrew.W.Wilson@sun.com } else if (flags & FILESET_PICKBYINDEX) {
7198404SAndrew.W.Wilson@sun.com /* pick by supplied index */
7208404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp, index);
7218404SAndrew.W.Wilson@sun.com
7228404SAndrew.W.Wilson@sun.com } else {
7238404SAndrew.W.Wilson@sun.com /* pick in rotation */
7248404SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) {
7258404SAndrew.W.Wilson@sun.com case FILESET_PICKFILE:
7268404SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKNOEXIST) {
7278404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp,
7288404SAndrew.W.Wilson@sun.com fileset->fs_file_nerotor);
7298404SAndrew.W.Wilson@sun.com fileset->fs_file_nerotor =
7308404SAndrew.W.Wilson@sun.com entry->fse_index + 1;
7318404SAndrew.W.Wilson@sun.com } else {
7328404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp,
7338404SAndrew.W.Wilson@sun.com fileset->fs_file_exrotor[tid]);
7348404SAndrew.W.Wilson@sun.com fileset->fs_file_exrotor[tid] =
7358404SAndrew.W.Wilson@sun.com entry->fse_index + 1;
7365184Sek110237 }
7378404SAndrew.W.Wilson@sun.com break;
7388404SAndrew.W.Wilson@sun.com
7398404SAndrew.W.Wilson@sun.com case FILESET_PICKDIR:
7408404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp, fileset->fs_dirrotor);
7418404SAndrew.W.Wilson@sun.com fileset->fs_dirrotor = entry->fse_index + 1;
7428404SAndrew.W.Wilson@sun.com break;
7438404SAndrew.W.Wilson@sun.com
7448404SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR:
7458404SAndrew.W.Wilson@sun.com if (flags & FILESET_PICKNOEXIST) {
7468404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp,
7478404SAndrew.W.Wilson@sun.com fileset->fs_leafdir_nerotor);
7488404SAndrew.W.Wilson@sun.com fileset->fs_leafdir_nerotor =
7498404SAndrew.W.Wilson@sun.com entry->fse_index + 1;
7508404SAndrew.W.Wilson@sun.com } else {
7518404SAndrew.W.Wilson@sun.com entry = fileset_find_entry(atp,
7528404SAndrew.W.Wilson@sun.com fileset->fs_leafdir_exrotor);
7538404SAndrew.W.Wilson@sun.com fileset->fs_leafdir_exrotor =
7548404SAndrew.W.Wilson@sun.com entry->fse_index + 1;
7555184Sek110237 }
7568404SAndrew.W.Wilson@sun.com break;
7578404SAndrew.W.Wilson@sun.com }
7588404SAndrew.W.Wilson@sun.com }
7598404SAndrew.W.Wilson@sun.com
7608404SAndrew.W.Wilson@sun.com if (entry == NULL)
7618404SAndrew.W.Wilson@sun.com goto empty;
7628404SAndrew.W.Wilson@sun.com
7638404SAndrew.W.Wilson@sun.com /* see if entry in use */
7648404SAndrew.W.Wilson@sun.com start_point = entry;
7658404SAndrew.W.Wilson@sun.com while (entry->fse_flags & FSE_BUSY) {
7668404SAndrew.W.Wilson@sun.com
7678404SAndrew.W.Wilson@sun.com /* it is, so try next */
7688404SAndrew.W.Wilson@sun.com entry = AVL_NEXT(atp, entry);
7698404SAndrew.W.Wilson@sun.com if (entry == NULL)
7708404SAndrew.W.Wilson@sun.com entry = avl_first(atp);
7718404SAndrew.W.Wilson@sun.com
7728404SAndrew.W.Wilson@sun.com /* see if we have wrapped around */
7738404SAndrew.W.Wilson@sun.com if ((entry == NULL) || (entry == start_point)) {
7748404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT,
7758404SAndrew.W.Wilson@sun.com "All %d files are busy", avl_numnodes(atp));
7768404SAndrew.W.Wilson@sun.com goto empty;
7775184Sek110237 }
7785184Sek110237
7795184Sek110237 }
7805184Sek110237
7817556SAndrew.W.Wilson@sun.com /* update file or directory idle counts */
7827946SAndrew.W.Wilson@sun.com switch (flags & FILESET_PICKMASK) {
7837946SAndrew.W.Wilson@sun.com case FILESET_PICKFILE:
7847946SAndrew.W.Wilson@sun.com fileset->fs_idle_files--;
7857946SAndrew.W.Wilson@sun.com break;
7867946SAndrew.W.Wilson@sun.com case FILESET_PICKDIR:
7877556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs--;
7887946SAndrew.W.Wilson@sun.com break;
7897946SAndrew.W.Wilson@sun.com case FILESET_PICKLEAFDIR:
7907946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs--;
7917946SAndrew.W.Wilson@sun.com break;
7927946SAndrew.W.Wilson@sun.com }
7937556SAndrew.W.Wilson@sun.com
7947556SAndrew.W.Wilson@sun.com /* Indicate that file or directory is now busy */
7957556SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_BUSY;
7967556SAndrew.W.Wilson@sun.com
7977556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
7985184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path);
7995184Sek110237 return (entry);
8005184Sek110237
8015184Sek110237 empty:
8028404SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_SCRIPT, "No file found");
8037556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
8045184Sek110237 return (NULL);
8055184Sek110237 }
8065184Sek110237
8075184Sek110237 /*
8087556SAndrew.W.Wilson@sun.com * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads
8097556SAndrew.W.Wilson@sun.com * that are waiting for a NOT BUSY filesetentry. Also sets whether it is
8107556SAndrew.W.Wilson@sun.com * existant or not, or leaves that designation alone.
8117556SAndrew.W.Wilson@sun.com */
8127556SAndrew.W.Wilson@sun.com void
fileset_unbusy(filesetentry_t * entry,int update_exist,int new_exist_val,int open_cnt_incr)8138404SAndrew.W.Wilson@sun.com fileset_unbusy(filesetentry_t *entry, int update_exist,
8148404SAndrew.W.Wilson@sun.com int new_exist_val, int open_cnt_incr)
8157556SAndrew.W.Wilson@sun.com {
8167556SAndrew.W.Wilson@sun.com fileset_t *fileset = NULL;
8177556SAndrew.W.Wilson@sun.com
8187556SAndrew.W.Wilson@sun.com if (entry)
8197556SAndrew.W.Wilson@sun.com fileset = entry->fse_fileset;
8207556SAndrew.W.Wilson@sun.com
8217556SAndrew.W.Wilson@sun.com if (fileset == NULL) {
8227556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!");
8237556SAndrew.W.Wilson@sun.com return;
8247556SAndrew.W.Wilson@sun.com }
8257556SAndrew.W.Wilson@sun.com
8267556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
8277556SAndrew.W.Wilson@sun.com
8288404SAndrew.W.Wilson@sun.com /* modify FSE_EXIST flag and actual dirs/files count, if requested */
8298404SAndrew.W.Wilson@sun.com if (update_exist) {
8308404SAndrew.W.Wilson@sun.com if (new_exist_val == TRUE) {
8318404SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_FREE) {
8328404SAndrew.W.Wilson@sun.com
8338404SAndrew.W.Wilson@sun.com /* asked to set and it was free */
8348404SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS;
8358404SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_FREE);
8368404SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) {
8378404SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE:
8388404SAndrew.W.Wilson@sun.com fileset_move_entry(
8398404SAndrew.W.Wilson@sun.com &fileset->fs_free_files,
8408404SAndrew.W.Wilson@sun.com &fileset->fs_exist_files, entry);
8418404SAndrew.W.Wilson@sun.com break;
8428404SAndrew.W.Wilson@sun.com
8438404SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR:
8448404SAndrew.W.Wilson@sun.com break;
8458404SAndrew.W.Wilson@sun.com
8468404SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR:
8478404SAndrew.W.Wilson@sun.com fileset_move_entry(
8488404SAndrew.W.Wilson@sun.com &fileset->fs_free_leaf_dirs,
8498404SAndrew.W.Wilson@sun.com &fileset->fs_exist_leaf_dirs,
8508404SAndrew.W.Wilson@sun.com entry);
8518404SAndrew.W.Wilson@sun.com break;
8528404SAndrew.W.Wilson@sun.com }
8538404SAndrew.W.Wilson@sun.com
8548404SAndrew.W.Wilson@sun.com } else if (!(entry->fse_flags & FSE_EXISTS)) {
8558404SAndrew.W.Wilson@sun.com
8568404SAndrew.W.Wilson@sun.com /* asked to set, and it was clear */
8578404SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_EXISTS;
8588404SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) {
8598404SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE:
8608404SAndrew.W.Wilson@sun.com fileset_move_entry(
8618404SAndrew.W.Wilson@sun.com &fileset->fs_noex_files,
8628404SAndrew.W.Wilson@sun.com &fileset->fs_exist_files, entry);
8638404SAndrew.W.Wilson@sun.com break;
8648404SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR:
8658404SAndrew.W.Wilson@sun.com break;
8668404SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR:
8678404SAndrew.W.Wilson@sun.com fileset_move_entry(
8688404SAndrew.W.Wilson@sun.com &fileset->fs_noex_leaf_dirs,
8698404SAndrew.W.Wilson@sun.com &fileset->fs_exist_leaf_dirs,
8708404SAndrew.W.Wilson@sun.com entry);
8718404SAndrew.W.Wilson@sun.com break;
8728404SAndrew.W.Wilson@sun.com }
8738404SAndrew.W.Wilson@sun.com }
8748404SAndrew.W.Wilson@sun.com } else {
8758404SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_FREE) {
8768404SAndrew.W.Wilson@sun.com /* asked to clear, and it was free */
8778404SAndrew.W.Wilson@sun.com entry->fse_flags &= (~(FSE_FREE | FSE_EXISTS));
8788404SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) {
8798404SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE:
8808404SAndrew.W.Wilson@sun.com fileset_move_entry(
8818404SAndrew.W.Wilson@sun.com &fileset->fs_free_files,
8828404SAndrew.W.Wilson@sun.com &fileset->fs_noex_files, entry);
8838404SAndrew.W.Wilson@sun.com break;
8848404SAndrew.W.Wilson@sun.com
8858404SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR:
8868404SAndrew.W.Wilson@sun.com break;
8878404SAndrew.W.Wilson@sun.com
8888404SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR:
8898404SAndrew.W.Wilson@sun.com fileset_move_entry(
8908404SAndrew.W.Wilson@sun.com &fileset->fs_free_leaf_dirs,
8918404SAndrew.W.Wilson@sun.com &fileset->fs_noex_leaf_dirs,
8928404SAndrew.W.Wilson@sun.com entry);
8938404SAndrew.W.Wilson@sun.com break;
8948404SAndrew.W.Wilson@sun.com }
8958404SAndrew.W.Wilson@sun.com } else if (entry->fse_flags & FSE_EXISTS) {
8968404SAndrew.W.Wilson@sun.com
8978404SAndrew.W.Wilson@sun.com /* asked to clear, and it was set */
8988404SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_EXISTS);
8998404SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) {
9008404SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE:
9018404SAndrew.W.Wilson@sun.com fileset_move_entry(
9028404SAndrew.W.Wilson@sun.com &fileset->fs_exist_files,
9038404SAndrew.W.Wilson@sun.com &fileset->fs_noex_files, entry);
9048404SAndrew.W.Wilson@sun.com break;
9058404SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR:
9068404SAndrew.W.Wilson@sun.com break;
9078404SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR:
9088404SAndrew.W.Wilson@sun.com fileset_move_entry(
9098404SAndrew.W.Wilson@sun.com &fileset->fs_exist_leaf_dirs,
9108404SAndrew.W.Wilson@sun.com &fileset->fs_noex_leaf_dirs,
9118404SAndrew.W.Wilson@sun.com entry);
9128404SAndrew.W.Wilson@sun.com break;
9138404SAndrew.W.Wilson@sun.com }
9148404SAndrew.W.Wilson@sun.com }
9158404SAndrew.W.Wilson@sun.com }
9168404SAndrew.W.Wilson@sun.com }
9178404SAndrew.W.Wilson@sun.com
9188404SAndrew.W.Wilson@sun.com /* update open count */
9198404SAndrew.W.Wilson@sun.com entry->fse_open_cnt += open_cnt_incr;
9208404SAndrew.W.Wilson@sun.com
9217556SAndrew.W.Wilson@sun.com /* increment idle count, clear FSE_BUSY and signal IF it was busy */
9227556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_BUSY) {
9237556SAndrew.W.Wilson@sun.com
9247556SAndrew.W.Wilson@sun.com /* unbusy it */
9257556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_BUSY);
9267556SAndrew.W.Wilson@sun.com
9277556SAndrew.W.Wilson@sun.com /* release any threads waiting for unbusy */
9287556SAndrew.W.Wilson@sun.com if (entry->fse_flags & FSE_THRD_WAITNG) {
9297556SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_THRD_WAITNG);
9307556SAndrew.W.Wilson@sun.com (void) pthread_cond_broadcast(
9317556SAndrew.W.Wilson@sun.com &fileset->fs_thrd_wait_cv);
9327556SAndrew.W.Wilson@sun.com }
9337556SAndrew.W.Wilson@sun.com
9347556SAndrew.W.Wilson@sun.com /* increment idle count and signal waiting threads */
9357946SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) {
9367946SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE:
9377946SAndrew.W.Wilson@sun.com fileset->fs_idle_files++;
9387946SAndrew.W.Wilson@sun.com if (fileset->fs_idle_files == 1) {
9397946SAndrew.W.Wilson@sun.com (void) pthread_cond_signal(
9407946SAndrew.W.Wilson@sun.com &fileset->fs_idle_files_cv);
9417946SAndrew.W.Wilson@sun.com }
9427946SAndrew.W.Wilson@sun.com break;
9438404SAndrew.W.Wilson@sun.com
9447946SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR:
9457556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs++;
9467556SAndrew.W.Wilson@sun.com if (fileset->fs_idle_dirs == 1) {
9477556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal(
9487556SAndrew.W.Wilson@sun.com &fileset->fs_idle_dirs_cv);
9497556SAndrew.W.Wilson@sun.com }
9507946SAndrew.W.Wilson@sun.com break;
9518404SAndrew.W.Wilson@sun.com
9527946SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR:
9537946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs++;
9547946SAndrew.W.Wilson@sun.com if (fileset->fs_idle_leafdirs == 1) {
9557556SAndrew.W.Wilson@sun.com (void) pthread_cond_signal(
9567946SAndrew.W.Wilson@sun.com &fileset->fs_idle_leafdirs_cv);
9577556SAndrew.W.Wilson@sun.com }
9587946SAndrew.W.Wilson@sun.com break;
9597556SAndrew.W.Wilson@sun.com }
9607556SAndrew.W.Wilson@sun.com }
9617556SAndrew.W.Wilson@sun.com
9627556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
9637556SAndrew.W.Wilson@sun.com }
9647556SAndrew.W.Wilson@sun.com
9657556SAndrew.W.Wilson@sun.com /*
9665184Sek110237 * Given a fileset "fileset", create the associated files as
9675184Sek110237 * specified in the attributes of the fileset. The fileset is
9686212Saw148015 * rooted in a directory whose pathname is in fileset_path. If the
9695184Sek110237 * directory exists, meaning that there is already a fileset,
9706212Saw148015 * and the fileset_reuse attribute is false, then remove it and all
9715184Sek110237 * its contained files and subdirectories. Next, the routine
9725184Sek110237 * creates a root directory for the fileset. All the file type
9735184Sek110237 * filesetentries are cycled through creating as needed
9745184Sek110237 * their containing subdirectory trees in the filesystem and
9756212Saw148015 * creating actual files for fileset_preallocpercent of them. The
9765184Sek110237 * created files are filled with fse_size bytes of unitialized
9777556SAndrew.W.Wilson@sun.com * data. The routine returns FILEBENCH_ERROR on errors,
9787556SAndrew.W.Wilson@sun.com * FILEBENCH_OK on success.
9795184Sek110237 */
9805184Sek110237 static int
fileset_create(fileset_t * fileset)9815184Sek110237 fileset_create(fileset_t *fileset)
9825184Sek110237 {
9835184Sek110237 filesetentry_t *entry;
9845184Sek110237 char path[MAXPATHLEN];
9855184Sek110237 struct stat64 sb;
9865184Sek110237 hrtime_t start = gethrtime();
9876212Saw148015 char *fileset_path;
9886212Saw148015 char *fileset_name;
9896212Saw148015 int randno;
9905184Sek110237 int preallocated = 0;
9917736SAndrew.W.Wilson@sun.com int reusing;
9925184Sek110237
9936212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
9945673Saw148015 filebench_log(LOG_ERROR, "%s path not set",
9955673Saw148015 fileset_entity_name(fileset));
9967556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
9975184Sek110237 }
9985184Sek110237
9996212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
10006212Saw148015 filebench_log(LOG_ERROR, "%s name not set",
10016212Saw148015 fileset_entity_name(fileset));
10027556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
10036212Saw148015 }
10046212Saw148015
10055673Saw148015 #ifdef HAVE_RAW_SUPPORT
10065673Saw148015 /* treat raw device as special case */
10075673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
10087556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
10095673Saw148015 #endif /* HAVE_RAW_SUPPORT */
10105673Saw148015
10115184Sek110237 /* XXX Add check to see if there is enough space */
10125184Sek110237
10137736SAndrew.W.Wilson@sun.com /* set up path to fileset */
10147946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
10157946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
10167946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, fileset_name, MAXPATHLEN);
10177736SAndrew.W.Wilson@sun.com
10189326SAndrew.W.Wilson@sun.com /* if reusing and trusting to exist, just blindly reuse */
10199326SAndrew.W.Wilson@sun.com if (avd_get_bool(fileset->fs_trust_tree)) {
10209326SAndrew.W.Wilson@sun.com reusing = 1;
10219326SAndrew.W.Wilson@sun.com
10227736SAndrew.W.Wilson@sun.com /* if exists and resusing, then don't create new */
10239326SAndrew.W.Wilson@sun.com } else if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) &&
10247736SAndrew.W.Wilson@sun.com (strlen(avd_get_str(fileset->fs_path)) > 2)) &&
10257736SAndrew.W.Wilson@sun.com avd_get_bool(fileset->fs_reuse)) {
10267736SAndrew.W.Wilson@sun.com reusing = 1;
10277736SAndrew.W.Wilson@sun.com } else {
10287736SAndrew.W.Wilson@sun.com reusing = 0;
10297736SAndrew.W.Wilson@sun.com }
10307736SAndrew.W.Wilson@sun.com
10317736SAndrew.W.Wilson@sun.com if (!reusing) {
10327736SAndrew.W.Wilson@sun.com /* Remove existing */
1033*9356SAndrew.W.Wilson@sun.com FB_RECUR_RM(path);
10347736SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE,
10357736SAndrew.W.Wilson@sun.com "Removed any existing %s %s in %llu seconds",
10367736SAndrew.W.Wilson@sun.com fileset_entity_name(fileset), fileset_name,
10377736SAndrew.W.Wilson@sun.com (u_longlong_t)(((gethrtime() - start) /
10387736SAndrew.W.Wilson@sun.com 1000000000) + 1));
10397736SAndrew.W.Wilson@sun.com } else {
10407736SAndrew.W.Wilson@sun.com /* we are re-using */
10417736SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, "Re-using %s %s.",
10427736SAndrew.W.Wilson@sun.com fileset_entity_name(fileset), fileset_name);
10435184Sek110237 }
10447736SAndrew.W.Wilson@sun.com
10457736SAndrew.W.Wilson@sun.com /* make the filesets directory tree unless in reuse mode */
10467736SAndrew.W.Wilson@sun.com if (!reusing && (avd_get_bool(fileset->fs_prealloc))) {
10477946SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE,
10487736SAndrew.W.Wilson@sun.com "making tree for filset %s", path);
10495184Sek110237
10508615SAndrew.W.Wilson@sun.com (void) FB_MKDIR(path, 0755);
10517736SAndrew.W.Wilson@sun.com
10527736SAndrew.W.Wilson@sun.com if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR)
10537736SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
10547736SAndrew.W.Wilson@sun.com }
10555673Saw148015
10565184Sek110237 start = gethrtime();
10575184Sek110237
10585673Saw148015 filebench_log(LOG_VERBOSE, "Creating %s %s...",
10596212Saw148015 fileset_entity_name(fileset), fileset_name);
10605673Saw148015
10616212Saw148015 randno = ((RAND_MAX * (100
10626212Saw148015 - avd_get_int(fileset->fs_preallocpercent))) / 100);
10636212Saw148015
10647946SAndrew.W.Wilson@sun.com /* alloc any files, as required */
10658404SAndrew.W.Wilson@sun.com fileset_pickreset(fileset, FILESET_PICKFILE);
10668404SAndrew.W.Wilson@sun.com while (entry = fileset_pick(fileset,
10678404SAndrew.W.Wilson@sun.com FILESET_PICKFREE | FILESET_PICKFILE, 0, 0)) {
10685673Saw148015 pthread_t tid;
10697736SAndrew.W.Wilson@sun.com int newrand;
10705184Sek110237
10717736SAndrew.W.Wilson@sun.com newrand = rand();
10727736SAndrew.W.Wilson@sun.com
10738404SAndrew.W.Wilson@sun.com if (newrand < randno) {
10748404SAndrew.W.Wilson@sun.com /* unbusy the unallocated entry */
10758404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, FALSE, 0);
10765184Sek110237 continue;
10778404SAndrew.W.Wilson@sun.com }
10785184Sek110237
10795184Sek110237 preallocated++;
10805184Sek110237
10815673Saw148015 if (reusing)
10825673Saw148015 entry->fse_flags |= FSE_REUSING;
10835673Saw148015 else
10845673Saw148015 entry->fse_flags &= (~FSE_REUSING);
10855673Saw148015
10867556SAndrew.W.Wilson@sun.com /* fire off allocation threads for each file if paralloc set */
10876212Saw148015 if (avd_get_bool(fileset->fs_paralloc)) {
10885184Sek110237
10897556SAndrew.W.Wilson@sun.com /* limit total number of simultaneous allocations */
10907556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(
10917556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock);
10927556SAndrew.W.Wilson@sun.com while (filebench_shm->shm_fsparalloc_count
10937556SAndrew.W.Wilson@sun.com >= MAX_PARALLOC_THREADS) {
10945673Saw148015 (void) pthread_cond_wait(
10957556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv,
10967556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock);
10975673Saw148015 }
10985673Saw148015
10998615SAndrew.W.Wilson@sun.com /* quit if any allocation thread reports an error */
11007556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_fsparalloc_count < 0) {
11017556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(
11027556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock);
11037556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
11045184Sek110237 }
11055184Sek110237
11067556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count++;
11077556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(
11087556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock);
11095184Sek110237
11107556SAndrew.W.Wilson@sun.com /*
11117556SAndrew.W.Wilson@sun.com * Fire off a detached allocation thread per file.
11127556SAndrew.W.Wilson@sun.com * The thread will self destruct when it finishes
11137556SAndrew.W.Wilson@sun.com * writing pre-allocation data to the file.
11147556SAndrew.W.Wilson@sun.com */
11155673Saw148015 if (pthread_create(&tid, NULL,
11165673Saw148015 (void *(*)(void*))fileset_alloc_thread,
11177556SAndrew.W.Wilson@sun.com entry) == 0) {
11187556SAndrew.W.Wilson@sun.com /*
11197556SAndrew.W.Wilson@sun.com * A thread was created; detach it so it can
11207556SAndrew.W.Wilson@sun.com * fully quit when finished.
11217556SAndrew.W.Wilson@sun.com */
11227556SAndrew.W.Wilson@sun.com (void) pthread_detach(tid);
11237556SAndrew.W.Wilson@sun.com } else {
11245184Sek110237 filebench_log(LOG_ERROR,
11255673Saw148015 "File prealloc thread create failed");
11265673Saw148015 filebench_shutdown(1);
11275184Sek110237 }
11285184Sek110237
11295673Saw148015 } else {
11307556SAndrew.W.Wilson@sun.com if (fileset_alloc_file(entry) == FILEBENCH_ERROR)
11317556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
11325673Saw148015 }
11335673Saw148015 }
11345184Sek110237
11357946SAndrew.W.Wilson@sun.com /* alloc any leaf directories, as required */
11368404SAndrew.W.Wilson@sun.com fileset_pickreset(fileset, FILESET_PICKLEAFDIR);
11378404SAndrew.W.Wilson@sun.com while (entry = fileset_pick(fileset,
11388404SAndrew.W.Wilson@sun.com FILESET_PICKFREE | FILESET_PICKLEAFDIR, 0, 0)) {
11397946SAndrew.W.Wilson@sun.com
11408404SAndrew.W.Wilson@sun.com if (rand() < randno) {
11418404SAndrew.W.Wilson@sun.com /* unbusy the unallocated entry */
11428404SAndrew.W.Wilson@sun.com fileset_unbusy(entry, TRUE, FALSE, 0);
11437946SAndrew.W.Wilson@sun.com continue;
11448404SAndrew.W.Wilson@sun.com }
11457946SAndrew.W.Wilson@sun.com
11467946SAndrew.W.Wilson@sun.com preallocated++;
11477946SAndrew.W.Wilson@sun.com
11487946SAndrew.W.Wilson@sun.com if (reusing)
11497946SAndrew.W.Wilson@sun.com entry->fse_flags |= FSE_REUSING;
11507946SAndrew.W.Wilson@sun.com else
11517946SAndrew.W.Wilson@sun.com entry->fse_flags &= (~FSE_REUSING);
11527946SAndrew.W.Wilson@sun.com
11537946SAndrew.W.Wilson@sun.com if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR)
11547946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
11557946SAndrew.W.Wilson@sun.com }
11567946SAndrew.W.Wilson@sun.com
11575673Saw148015 exit:
11585184Sek110237 filebench_log(LOG_VERBOSE,
11596286Saw148015 "Preallocated %d of %llu of %s %s in %llu seconds",
11605184Sek110237 preallocated,
11616286Saw148015 (u_longlong_t)fileset->fs_constentries,
11626212Saw148015 fileset_entity_name(fileset), fileset_name,
11636286Saw148015 (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1));
11645184Sek110237
11657556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
11665184Sek110237 }
11675184Sek110237
11685184Sek110237 /*
1169*9356SAndrew.W.Wilson@sun.com * Removes all files and directories associated with a fileset
1170*9356SAndrew.W.Wilson@sun.com * from the storage subsystem.
1171*9356SAndrew.W.Wilson@sun.com */
1172*9356SAndrew.W.Wilson@sun.com static void
fileset_delete_storage(fileset_t * fileset)1173*9356SAndrew.W.Wilson@sun.com fileset_delete_storage(fileset_t *fileset)
1174*9356SAndrew.W.Wilson@sun.com {
1175*9356SAndrew.W.Wilson@sun.com char path[MAXPATHLEN];
1176*9356SAndrew.W.Wilson@sun.com char *fileset_path;
1177*9356SAndrew.W.Wilson@sun.com char *fileset_name;
1178*9356SAndrew.W.Wilson@sun.com
1179*9356SAndrew.W.Wilson@sun.com if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL)
1180*9356SAndrew.W.Wilson@sun.com return;
1181*9356SAndrew.W.Wilson@sun.com
1182*9356SAndrew.W.Wilson@sun.com if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL)
1183*9356SAndrew.W.Wilson@sun.com return;
1184*9356SAndrew.W.Wilson@sun.com
1185*9356SAndrew.W.Wilson@sun.com #ifdef HAVE_RAW_SUPPORT
1186*9356SAndrew.W.Wilson@sun.com /* treat raw device as special case */
1187*9356SAndrew.W.Wilson@sun.com if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
1188*9356SAndrew.W.Wilson@sun.com return;
1189*9356SAndrew.W.Wilson@sun.com #endif /* HAVE_RAW_SUPPORT */
1190*9356SAndrew.W.Wilson@sun.com
1191*9356SAndrew.W.Wilson@sun.com /* set up path to file */
1192*9356SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
1193*9356SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
1194*9356SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, fileset_name, MAXPATHLEN);
1195*9356SAndrew.W.Wilson@sun.com
1196*9356SAndrew.W.Wilson@sun.com /* now delete any files and directories on the disk */
1197*9356SAndrew.W.Wilson@sun.com FB_RECUR_RM(path);
1198*9356SAndrew.W.Wilson@sun.com }
1199*9356SAndrew.W.Wilson@sun.com
1200*9356SAndrew.W.Wilson@sun.com /*
1201*9356SAndrew.W.Wilson@sun.com * Removes the fileset entity and all of its filesetentry entities.
1202*9356SAndrew.W.Wilson@sun.com */
1203*9356SAndrew.W.Wilson@sun.com static void
fileset_delete_fileset(fileset_t * fileset)1204*9356SAndrew.W.Wilson@sun.com fileset_delete_fileset(fileset_t *fileset)
1205*9356SAndrew.W.Wilson@sun.com {
1206*9356SAndrew.W.Wilson@sun.com filesetentry_t *entry, *next_entry;
1207*9356SAndrew.W.Wilson@sun.com
1208*9356SAndrew.W.Wilson@sun.com /* run down the file list, removing and freeing each filesetentry */
1209*9356SAndrew.W.Wilson@sun.com for (entry = fileset->fs_filelist; entry; entry = next_entry) {
1210*9356SAndrew.W.Wilson@sun.com
1211*9356SAndrew.W.Wilson@sun.com /* free the entry */
1212*9356SAndrew.W.Wilson@sun.com next_entry = entry->fse_next;
1213*9356SAndrew.W.Wilson@sun.com
1214*9356SAndrew.W.Wilson@sun.com /* return it to the pool */
1215*9356SAndrew.W.Wilson@sun.com switch (entry->fse_flags & FSE_TYPE_MASK) {
1216*9356SAndrew.W.Wilson@sun.com case FSE_TYPE_FILE:
1217*9356SAndrew.W.Wilson@sun.com case FSE_TYPE_LEAFDIR:
1218*9356SAndrew.W.Wilson@sun.com case FSE_TYPE_DIR:
1219*9356SAndrew.W.Wilson@sun.com ipc_free(FILEBENCH_FILESETENTRY, (void *)entry);
1220*9356SAndrew.W.Wilson@sun.com break;
1221*9356SAndrew.W.Wilson@sun.com default:
1222*9356SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
1223*9356SAndrew.W.Wilson@sun.com "Unallocated filesetentry found on list");
1224*9356SAndrew.W.Wilson@sun.com break;
1225*9356SAndrew.W.Wilson@sun.com }
1226*9356SAndrew.W.Wilson@sun.com }
1227*9356SAndrew.W.Wilson@sun.com
1228*9356SAndrew.W.Wilson@sun.com ipc_free(FILEBENCH_FILESET, (void *)fileset);
1229*9356SAndrew.W.Wilson@sun.com }
1230*9356SAndrew.W.Wilson@sun.com
1231*9356SAndrew.W.Wilson@sun.com void
fileset_delete_all_filesets(void)1232*9356SAndrew.W.Wilson@sun.com fileset_delete_all_filesets(void)
1233*9356SAndrew.W.Wilson@sun.com {
1234*9356SAndrew.W.Wilson@sun.com fileset_t *fileset, *next_fileset;
1235*9356SAndrew.W.Wilson@sun.com
1236*9356SAndrew.W.Wilson@sun.com for (fileset = filebench_shm->shm_filesetlist;
1237*9356SAndrew.W.Wilson@sun.com fileset; fileset = next_fileset) {
1238*9356SAndrew.W.Wilson@sun.com next_fileset = fileset->fs_next;
1239*9356SAndrew.W.Wilson@sun.com fileset_delete_storage(fileset);
1240*9356SAndrew.W.Wilson@sun.com fileset_delete_fileset(fileset);
1241*9356SAndrew.W.Wilson@sun.com }
1242*9356SAndrew.W.Wilson@sun.com
1243*9356SAndrew.W.Wilson@sun.com filebench_shm->shm_filesetlist = NULL;
1244*9356SAndrew.W.Wilson@sun.com }
1245*9356SAndrew.W.Wilson@sun.com /*
12465184Sek110237 * Adds an entry to the fileset's file list. Single threaded so
12475184Sek110237 * no locking needed.
12485184Sek110237 */
12495184Sek110237 static void
fileset_insfilelist(fileset_t * fileset,filesetentry_t * entry)12505184Sek110237 fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry)
12515184Sek110237 {
12528404SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_TYPE_FILE | FSE_FREE;
12538404SAndrew.W.Wilson@sun.com avl_add(&fileset->fs_free_files, entry);
12548404SAndrew.W.Wilson@sun.com
12555184Sek110237 if (fileset->fs_filelist == NULL) {
12565184Sek110237 fileset->fs_filelist = entry;
12578404SAndrew.W.Wilson@sun.com entry->fse_nextoftype = NULL;
12585184Sek110237 } else {
12598404SAndrew.W.Wilson@sun.com entry->fse_nextoftype = fileset->fs_filelist;
12605184Sek110237 fileset->fs_filelist = entry;
12615184Sek110237 }
12625184Sek110237 }
12635184Sek110237
12645184Sek110237 /*
12655184Sek110237 * Adds an entry to the fileset's directory list. Single
12665184Sek110237 * threaded so no locking needed.
12675184Sek110237 */
12685184Sek110237 static void
fileset_insdirlist(fileset_t * fileset,filesetentry_t * entry)12695184Sek110237 fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry)
12705184Sek110237 {
12718404SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_TYPE_DIR | FSE_EXISTS;
12728404SAndrew.W.Wilson@sun.com avl_add(&fileset->fs_dirs, entry);
12738404SAndrew.W.Wilson@sun.com
12745184Sek110237 if (fileset->fs_dirlist == NULL) {
12755184Sek110237 fileset->fs_dirlist = entry;
12768404SAndrew.W.Wilson@sun.com entry->fse_nextoftype = NULL;
12775184Sek110237 } else {
12788404SAndrew.W.Wilson@sun.com entry->fse_nextoftype = fileset->fs_dirlist;
12795184Sek110237 fileset->fs_dirlist = entry;
12805184Sek110237 }
12815184Sek110237 }
12825184Sek110237
12835184Sek110237 /*
12847946SAndrew.W.Wilson@sun.com * Adds an entry to the fileset's leaf directory list. Single
12857946SAndrew.W.Wilson@sun.com * threaded so no locking needed.
12867946SAndrew.W.Wilson@sun.com */
12877946SAndrew.W.Wilson@sun.com static void
fileset_insleafdirlist(fileset_t * fileset,filesetentry_t * entry)12887946SAndrew.W.Wilson@sun.com fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry)
12897946SAndrew.W.Wilson@sun.com {
12908404SAndrew.W.Wilson@sun.com entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE;
12918404SAndrew.W.Wilson@sun.com avl_add(&fileset->fs_free_leaf_dirs, entry);
12928404SAndrew.W.Wilson@sun.com
12937946SAndrew.W.Wilson@sun.com if (fileset->fs_leafdirlist == NULL) {
12947946SAndrew.W.Wilson@sun.com fileset->fs_leafdirlist = entry;
12958404SAndrew.W.Wilson@sun.com entry->fse_nextoftype = NULL;
12967946SAndrew.W.Wilson@sun.com } else {
12978404SAndrew.W.Wilson@sun.com entry->fse_nextoftype = fileset->fs_leafdirlist;
12987946SAndrew.W.Wilson@sun.com fileset->fs_leafdirlist = entry;
12997946SAndrew.W.Wilson@sun.com }
13007946SAndrew.W.Wilson@sun.com }
13017946SAndrew.W.Wilson@sun.com
13027946SAndrew.W.Wilson@sun.com /*
13038404SAndrew.W.Wilson@sun.com * Compares two fileset entries to determine their relative order
13048404SAndrew.W.Wilson@sun.com */
13058404SAndrew.W.Wilson@sun.com static int
fileset_entry_compare(const void * node_1,const void * node_2)13068404SAndrew.W.Wilson@sun.com fileset_entry_compare(const void *node_1, const void *node_2)
13078404SAndrew.W.Wilson@sun.com {
13088404SAndrew.W.Wilson@sun.com if (((filesetentry_t *)node_1)->fse_index <
13098404SAndrew.W.Wilson@sun.com ((filesetentry_t *)node_2)->fse_index)
13108404SAndrew.W.Wilson@sun.com return (-1);
13118404SAndrew.W.Wilson@sun.com
13128404SAndrew.W.Wilson@sun.com if (((filesetentry_t *)node_1)->fse_index ==
13138404SAndrew.W.Wilson@sun.com ((filesetentry_t *)node_2)->fse_index)
13148404SAndrew.W.Wilson@sun.com return (0);
13158404SAndrew.W.Wilson@sun.com
13168404SAndrew.W.Wilson@sun.com return (1);
13178404SAndrew.W.Wilson@sun.com }
13188404SAndrew.W.Wilson@sun.com
13198404SAndrew.W.Wilson@sun.com /*
13207946SAndrew.W.Wilson@sun.com * Obtains a filesetentry entity for a file to be placed in a
13215184Sek110237 * (sub)directory of a fileset. The size of the file may be
13226212Saw148015 * specified by fileset_meansize, or calculated from a gamma
13236212Saw148015 * distribution of parameter fileset_sizegamma and of mean size
13246212Saw148015 * fileset_meansize. The filesetentry entity is placed on the file
13255184Sek110237 * list in the specified parent filesetentry entity, which may
13265184Sek110237 * be a directory filesetentry, or the root filesetentry in the
13275184Sek110237 * fileset. It is also placed on the fileset's list of all
13287556SAndrew.W.Wilson@sun.com * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR
13297556SAndrew.W.Wilson@sun.com * if ipc memory for the path string cannot be allocated.
13305184Sek110237 */
13315184Sek110237 static int
fileset_populate_file(fileset_t * fileset,filesetentry_t * parent,int serial)13325184Sek110237 fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
13335184Sek110237 {
13345184Sek110237 char tmpname[16];
13355184Sek110237 filesetentry_t *entry;
13365184Sek110237 double drand;
13378404SAndrew.W.Wilson@sun.com uint_t index;
13385184Sek110237
13395184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
13405184Sek110237 == NULL) {
13415184Sek110237 filebench_log(LOG_ERROR,
13425184Sek110237 "fileset_populate_file: Can't malloc filesetentry");
13437556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
13445184Sek110237 }
13455184Sek110237
13467556SAndrew.W.Wilson@sun.com /* Another currently idle file */
13477556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
13488404SAndrew.W.Wilson@sun.com index = fileset->fs_idle_files++;
13497556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
13507556SAndrew.W.Wilson@sun.com
13518404SAndrew.W.Wilson@sun.com entry->fse_index = index;
13525184Sek110237 entry->fse_parent = parent;
13535184Sek110237 entry->fse_fileset = fileset;
13545184Sek110237 fileset_insfilelist(fileset, entry);
13555184Sek110237
13565184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
13575184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
13585184Sek110237 filebench_log(LOG_ERROR,
13595184Sek110237 "fileset_populate_file: Can't alloc path string");
13607556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
13615184Sek110237 }
13625184Sek110237
13636212Saw148015 /* see if random variable was supplied for file size */
13646212Saw148015 if (fileset->fs_meansize == -1) {
13656212Saw148015 entry->fse_size = (off64_t)avd_get_int(fileset->fs_size);
13666212Saw148015 } else {
13676212Saw148015 double gamma;
13685184Sek110237
13696212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0;
13706212Saw148015 if (gamma > 0) {
13716212Saw148015 drand = gamma_dist_knuth(gamma,
13726212Saw148015 fileset->fs_meansize / gamma);
13736212Saw148015 entry->fse_size = (off64_t)drand;
13746212Saw148015 } else {
13756212Saw148015 entry->fse_size = (off64_t)fileset->fs_meansize;
13766212Saw148015 }
13775184Sek110237 }
13785184Sek110237
13795184Sek110237 fileset->fs_bytes += entry->fse_size;
13805184Sek110237
13815184Sek110237 fileset->fs_realfiles++;
13827556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
13835184Sek110237 }
13845184Sek110237
13855184Sek110237 /*
13867946SAndrew.W.Wilson@sun.com * Obtaines a filesetentry entity for a leaf directory to be placed in a
13877946SAndrew.W.Wilson@sun.com * (sub)directory of a fileset. The leaf directory will always be empty so
13887946SAndrew.W.Wilson@sun.com * it can be created and deleted (mkdir, rmdir) at will. The filesetentry
13897946SAndrew.W.Wilson@sun.com * entity is placed on the leaf directory list in the specified parent
13907946SAndrew.W.Wilson@sun.com * filesetentry entity, which may be a (sub) directory filesetentry, or
13917946SAndrew.W.Wilson@sun.com * the root filesetentry in the fileset. It is also placed on the fileset's
13927946SAndrew.W.Wilson@sun.com * list of all contained leaf directories. Returns FILEBENCH_OK if successful
13937946SAndrew.W.Wilson@sun.com * or FILEBENCH_ERROR if ipc memory cannot be allocated.
13947946SAndrew.W.Wilson@sun.com */
13957946SAndrew.W.Wilson@sun.com static int
fileset_populate_leafdir(fileset_t * fileset,filesetentry_t * parent,int serial)13967946SAndrew.W.Wilson@sun.com fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial)
13977946SAndrew.W.Wilson@sun.com {
13987946SAndrew.W.Wilson@sun.com char tmpname[16];
13997946SAndrew.W.Wilson@sun.com filesetentry_t *entry;
14008404SAndrew.W.Wilson@sun.com uint_t index;
14017946SAndrew.W.Wilson@sun.com
14027946SAndrew.W.Wilson@sun.com if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
14037946SAndrew.W.Wilson@sun.com == NULL) {
14047946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
14057946SAndrew.W.Wilson@sun.com "fileset_populate_file: Can't malloc filesetentry");
14067946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
14077946SAndrew.W.Wilson@sun.com }
14087946SAndrew.W.Wilson@sun.com
14097946SAndrew.W.Wilson@sun.com /* Another currently idle leaf directory */
14107946SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
14118404SAndrew.W.Wilson@sun.com index = fileset->fs_idle_leafdirs++;
14127946SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
14137946SAndrew.W.Wilson@sun.com
14148404SAndrew.W.Wilson@sun.com entry->fse_index = index;
14157946SAndrew.W.Wilson@sun.com entry->fse_parent = parent;
14167946SAndrew.W.Wilson@sun.com entry->fse_fileset = fileset;
14177946SAndrew.W.Wilson@sun.com fileset_insleafdirlist(fileset, entry);
14187946SAndrew.W.Wilson@sun.com
14197946SAndrew.W.Wilson@sun.com (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
14207946SAndrew.W.Wilson@sun.com if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
14217946SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
14227946SAndrew.W.Wilson@sun.com "fileset_populate_file: Can't alloc path string");
14237946SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
14247946SAndrew.W.Wilson@sun.com }
14257946SAndrew.W.Wilson@sun.com
14267946SAndrew.W.Wilson@sun.com fileset->fs_realleafdirs++;
14277946SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
14287946SAndrew.W.Wilson@sun.com }
14297946SAndrew.W.Wilson@sun.com
14307946SAndrew.W.Wilson@sun.com /*
14315184Sek110237 * Creates a directory node in a fileset, by obtaining a
14325184Sek110237 * filesetentry entity for the node and initializing it
14335184Sek110237 * according to parameters of the fileset. It determines a
14345184Sek110237 * directory tree depth and directory width, optionally using
14355184Sek110237 * a gamma distribution. If its calculated depth is less then
14365184Sek110237 * its actual depth in the directory tree, it becomes a leaf
14375184Sek110237 * node and files itself with "width" number of file type
14385184Sek110237 * filesetentries, otherwise it files itself with "width"
14395184Sek110237 * number of directory type filesetentries, using recursive
14405184Sek110237 * calls to fileset_populate_subdir. The end result of the
14415184Sek110237 * initial call to this routine is a tree of directories of
14425184Sek110237 * random width and varying depth with sufficient leaf
14435184Sek110237 * directories to contain all required files.
14447556SAndrew.W.Wilson@sun.com * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path
14457556SAndrew.W.Wilson@sun.com * string memory cannot be allocated and returns the error code (currently
14467556SAndrew.W.Wilson@sun.com * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive
14475184Sek110237 * calls to fileset_populate_subdir.
14485184Sek110237 */
14495184Sek110237 static int
fileset_populate_subdir(fileset_t * fileset,filesetentry_t * parent,int serial,double depth)14505184Sek110237 fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
14515184Sek110237 int serial, double depth)
14525184Sek110237 {
14536212Saw148015 double randepth, drand, ranwidth;
14545184Sek110237 int isleaf = 0;
14555184Sek110237 char tmpname[16];
14565184Sek110237 filesetentry_t *entry;
14575184Sek110237 int i;
14588404SAndrew.W.Wilson@sun.com uint_t index;
14595184Sek110237
14605184Sek110237 depth += 1;
14615184Sek110237
14625184Sek110237 /* Create dir node */
14635184Sek110237 if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
14645184Sek110237 == NULL) {
14655184Sek110237 filebench_log(LOG_ERROR,
14665184Sek110237 "fileset_populate_subdir: Can't malloc filesetentry");
14677556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
14685184Sek110237 }
14695184Sek110237
14707556SAndrew.W.Wilson@sun.com /* another idle directory */
14717556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&fileset->fs_pick_lock);
14728404SAndrew.W.Wilson@sun.com index = fileset->fs_idle_dirs++;
14737556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
14745184Sek110237
14755184Sek110237 (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
14765184Sek110237 if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) {
14775184Sek110237 filebench_log(LOG_ERROR,
14785184Sek110237 "fileset_populate_subdir: Can't alloc path string");
14797556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
14805184Sek110237 }
14815184Sek110237
14828404SAndrew.W.Wilson@sun.com entry->fse_index = index;
14835184Sek110237 entry->fse_parent = parent;
14847946SAndrew.W.Wilson@sun.com entry->fse_fileset = fileset;
14855184Sek110237 fileset_insdirlist(fileset, entry);
14865184Sek110237
14876212Saw148015 if (fileset->fs_dirdepthrv) {
14886212Saw148015 randepth = (int)avd_get_int(fileset->fs_dirdepthrv);
14895184Sek110237 } else {
14906212Saw148015 double gamma;
14916212Saw148015
14926212Saw148015 gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0;
14936212Saw148015 if (gamma > 0) {
14946212Saw148015 drand = gamma_dist_knuth(gamma,
14956212Saw148015 fileset->fs_meandepth / gamma);
14966212Saw148015 randepth = (int)drand;
14976212Saw148015 } else {
14986212Saw148015 randepth = (int)fileset->fs_meandepth;
14996212Saw148015 }
15005184Sek110237 }
15015184Sek110237
15026212Saw148015 if (fileset->fs_meanwidth == -1) {
15036212Saw148015 ranwidth = avd_get_dbl(fileset->fs_dirwidth);
15046212Saw148015 } else {
15056212Saw148015 double gamma;
15065184Sek110237
15076212Saw148015 gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0;
15086212Saw148015 if (gamma > 0) {
15096212Saw148015 drand = gamma_dist_knuth(gamma,
15106212Saw148015 fileset->fs_meanwidth / gamma);
15116212Saw148015 ranwidth = drand;
15126212Saw148015 } else {
15136212Saw148015 ranwidth = fileset->fs_meanwidth;
15146212Saw148015 }
15155184Sek110237 }
15165184Sek110237
15175184Sek110237 if (randepth == 0)
15185184Sek110237 randepth = 1;
15195184Sek110237 if (ranwidth == 0)
15205184Sek110237 ranwidth = 1;
15215184Sek110237 if (depth >= randepth)
15225184Sek110237 isleaf = 1;
15235184Sek110237
15245184Sek110237 /*
15257946SAndrew.W.Wilson@sun.com * Create directory of random width filled with files according
15267946SAndrew.W.Wilson@sun.com * to distribution, or if root directory, continue until #files required
15275184Sek110237 */
15286212Saw148015 for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
15296212Saw148015 (fileset->fs_realfiles < fileset->fs_constentries);
15306212Saw148015 i++) {
15315184Sek110237 int ret = 0;
15325184Sek110237
15335184Sek110237 if (parent && isleaf)
15345184Sek110237 ret = fileset_populate_file(fileset, entry, i);
15355184Sek110237 else
15365184Sek110237 ret = fileset_populate_subdir(fileset, entry, i, depth);
15375184Sek110237
15385184Sek110237 if (ret != 0)
15395184Sek110237 return (ret);
15405184Sek110237 }
15417946SAndrew.W.Wilson@sun.com
15427946SAndrew.W.Wilson@sun.com /*
15437946SAndrew.W.Wilson@sun.com * Create directory of random width filled with leaf directories
15447946SAndrew.W.Wilson@sun.com * according to distribution, or if root directory, continue until
15457946SAndrew.W.Wilson@sun.com * the number of leaf directories required has been generated.
15467946SAndrew.W.Wilson@sun.com */
15477946SAndrew.W.Wilson@sun.com for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
15487946SAndrew.W.Wilson@sun.com (fileset->fs_realleafdirs < fileset->fs_constleafdirs);
15497946SAndrew.W.Wilson@sun.com i++) {
15507946SAndrew.W.Wilson@sun.com int ret = 0;
15517946SAndrew.W.Wilson@sun.com
15527946SAndrew.W.Wilson@sun.com if (parent && isleaf)
15537946SAndrew.W.Wilson@sun.com ret = fileset_populate_leafdir(fileset, entry, i);
15547946SAndrew.W.Wilson@sun.com else
15557946SAndrew.W.Wilson@sun.com ret = fileset_populate_subdir(fileset, entry, i, depth);
15567946SAndrew.W.Wilson@sun.com
15577946SAndrew.W.Wilson@sun.com if (ret != 0)
15587946SAndrew.W.Wilson@sun.com return (ret);
15597946SAndrew.W.Wilson@sun.com }
15607946SAndrew.W.Wilson@sun.com
15617556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
15625184Sek110237 }
15635184Sek110237
15645184Sek110237 /*
15655184Sek110237 * Populates a fileset with files and subdirectory entries. Uses
15666212Saw148015 * the supplied fileset_dirwidth and fileset_entries (number of files) to
15676212Saw148015 * calculate the required fileset_meandepth (of subdirectories) and
15686212Saw148015 * initialize the fileset_meanwidth and fileset_meansize variables. Then
15695184Sek110237 * calls fileset_populate_subdir() to do the recursive
15705184Sek110237 * subdirectory entry creation and leaf file entry creation. All
15715184Sek110237 * of the above is skipped if the fileset has already been
15725184Sek110237 * populated. Returns 0 on success, or an error code from the
15735184Sek110237 * call to fileset_populate_subdir if that call fails.
15745184Sek110237 */
15755184Sek110237 static int
fileset_populate(fileset_t * fileset)15765184Sek110237 fileset_populate(fileset_t *fileset)
15775184Sek110237 {
15788404SAndrew.W.Wilson@sun.com fbint_t entries = avd_get_int(fileset->fs_entries);
15798404SAndrew.W.Wilson@sun.com fbint_t leafdirs = avd_get_int(fileset->fs_leafdirs);
15806212Saw148015 int meandirwidth;
15815184Sek110237 int ret;
15825184Sek110237
15835184Sek110237 /* Skip if already populated */
15845184Sek110237 if (fileset->fs_bytes > 0)
15855184Sek110237 goto exists;
15865184Sek110237
15875673Saw148015 #ifdef HAVE_RAW_SUPPORT
15885673Saw148015 /* check for raw device */
15895673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV)
15907556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
15915673Saw148015 #endif /* HAVE_RAW_SUPPORT */
15925673Saw148015
15937946SAndrew.W.Wilson@sun.com /*
15947946SAndrew.W.Wilson@sun.com * save value of entries and leaf dirs obtained for later
15957946SAndrew.W.Wilson@sun.com * in case it was random
15967946SAndrew.W.Wilson@sun.com */
15976212Saw148015 fileset->fs_constentries = entries;
15987946SAndrew.W.Wilson@sun.com fileset->fs_constleafdirs = leafdirs;
15996212Saw148015
16007556SAndrew.W.Wilson@sun.com /* initialize idle files and directories condition variables */
16017946SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr());
16027556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr());
16037946SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr());
16047556SAndrew.W.Wilson@sun.com
16057556SAndrew.W.Wilson@sun.com /* no files or dirs idle (or busy) yet */
16067556SAndrew.W.Wilson@sun.com fileset->fs_idle_files = 0;
16077556SAndrew.W.Wilson@sun.com fileset->fs_idle_dirs = 0;
16087946SAndrew.W.Wilson@sun.com fileset->fs_idle_leafdirs = 0;
16097556SAndrew.W.Wilson@sun.com
16107556SAndrew.W.Wilson@sun.com /* initialize locks and other condition variables */
16117556SAndrew.W.Wilson@sun.com (void) pthread_mutex_init(&fileset->fs_pick_lock,
16127556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
16138404SAndrew.W.Wilson@sun.com (void) pthread_mutex_init(&fileset->fs_histo_lock,
16148404SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
16157556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr());
16167556SAndrew.W.Wilson@sun.com
16178404SAndrew.W.Wilson@sun.com /* Initialize avl btrees */
16188404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_free_files), fileset_entry_compare,
16198404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16208404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_noex_files), fileset_entry_compare,
16218404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16228404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_exist_files), fileset_entry_compare,
16238404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16248404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_free_leaf_dirs), fileset_entry_compare,
16258404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16268404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_noex_leaf_dirs), fileset_entry_compare,
16278404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16288404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_exist_leaf_dirs), fileset_entry_compare,
16298404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16308404SAndrew.W.Wilson@sun.com avl_create(&(fileset->fs_dirs), fileset_entry_compare,
16318404SAndrew.W.Wilson@sun.com sizeof (filesetentry_t), FSE_OFFSETOF(fse_link));
16328404SAndrew.W.Wilson@sun.com
16336212Saw148015 /* is dirwidth a random variable? */
16346212Saw148015 if (AVD_IS_RANDOM(fileset->fs_dirwidth)) {
16356212Saw148015 meandirwidth =
16366212Saw148015 (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean;
16376212Saw148015 fileset->fs_meanwidth = -1;
16386212Saw148015 } else {
16396212Saw148015 meandirwidth = (int)avd_get_int(fileset->fs_dirwidth);
16406212Saw148015 fileset->fs_meanwidth = (double)meandirwidth;
16416212Saw148015 }
16426212Saw148015
16435184Sek110237 /*
16445184Sek110237 * Input params are:
16455184Sek110237 * # of files
16465184Sek110237 * ave # of files per dir
16475184Sek110237 * max size of dir
16485184Sek110237 * # ave size of file
16495184Sek110237 * max size of file
16505184Sek110237 */
16517946SAndrew.W.Wilson@sun.com fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth);
16526212Saw148015
16536212Saw148015 /* Has a random variable been supplied for dirdepth? */
16546212Saw148015 if (fileset->fs_dirdepthrv) {
16556212Saw148015 /* yes, so set the random variable's mean value to meandepth */
16566212Saw148015 fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean =
16576212Saw148015 fileset->fs_meandepth;
16586212Saw148015 }
16596212Saw148015
16606212Saw148015 /* test for random size variable */
16616212Saw148015 if (AVD_IS_RANDOM(fileset->fs_size))
16626212Saw148015 fileset->fs_meansize = -1;
16636212Saw148015 else
16646212Saw148015 fileset->fs_meansize = avd_get_int(fileset->fs_size);
16655184Sek110237
16665184Sek110237 if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0)
16675184Sek110237 return (ret);
16685184Sek110237
16695184Sek110237
16705184Sek110237 exists:
16715673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) {
16726286Saw148015 filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu",
16736212Saw148015 avd_get_str(fileset->fs_name),
16746286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
16755673Saw148015 } else {
16767946SAndrew.W.Wilson@sun.com filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs "
16776286Saw148015 "avg dir = %d, avg depth = %.1lf, mbytes=%llu",
16787946SAndrew.W.Wilson@sun.com avd_get_str(fileset->fs_name), entries, leafdirs,
16796212Saw148015 meandirwidth,
16805673Saw148015 fileset->fs_meandepth,
16816286Saw148015 (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
16825673Saw148015 }
16836701Saw148015
16847556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
16855184Sek110237 }
16865184Sek110237
16875184Sek110237 /*
16886212Saw148015 * Allocates a fileset instance, initializes fileset_dirgamma and
16896212Saw148015 * fileset_sizegamma default values, and sets the fileset name to the
16905184Sek110237 * supplied name string. Puts the allocated fileset on the
16915184Sek110237 * master fileset list and returns a pointer to it.
16926701Saw148015 *
16936701Saw148015 * This routine implements the 'define fileset' calls found in a .f
16946701Saw148015 * workload, such as in the following example:
16956701Saw148015 * define fileset name=drew4ever, entries=$nfiles
16965184Sek110237 */
16975184Sek110237 fileset_t *
fileset_define(avd_t name)16986212Saw148015 fileset_define(avd_t name)
16995184Sek110237 {
17005184Sek110237 fileset_t *fileset;
17015184Sek110237
17025184Sek110237 if (name == NULL)
17035184Sek110237 return (NULL);
17045184Sek110237
17055184Sek110237 if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) {
17065184Sek110237 filebench_log(LOG_ERROR,
17075184Sek110237 "fileset_define: Can't malloc fileset");
17085184Sek110237 return (NULL);
17095184Sek110237 }
17105184Sek110237
17116212Saw148015 filebench_log(LOG_DEBUG_IMPL,
17126212Saw148015 "Defining file %s", avd_get_str(name));
17135184Sek110237
17146391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
17155184Sek110237
17166212Saw148015 fileset->fs_dirgamma = avd_int_alloc(1500);
17176212Saw148015 fileset->fs_sizegamma = avd_int_alloc(1500);
17188404SAndrew.W.Wilson@sun.com fileset->fs_histo_id = -1;
17195184Sek110237
17205184Sek110237 /* Add fileset to global list */
17216391Saw148015 if (filebench_shm->shm_filesetlist == NULL) {
17226391Saw148015 filebench_shm->shm_filesetlist = fileset;
17235184Sek110237 fileset->fs_next = NULL;
17245184Sek110237 } else {
17256391Saw148015 fileset->fs_next = filebench_shm->shm_filesetlist;
17266391Saw148015 filebench_shm->shm_filesetlist = fileset;
17275184Sek110237 }
17285184Sek110237
17296391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
17305184Sek110237
17316212Saw148015 fileset->fs_name = name;
17325184Sek110237
17335184Sek110237 return (fileset);
17345184Sek110237 }
17355184Sek110237
17365184Sek110237 /*
17375184Sek110237 * If supplied with a pointer to a fileset and the fileset's
17386212Saw148015 * fileset_prealloc flag is set, calls fileset_populate() to populate
17395184Sek110237 * the fileset with filesetentries, then calls fileset_create()
17405184Sek110237 * to make actual directories and files for the filesetentries.
17415184Sek110237 * Otherwise, it applies fileset_populate() and fileset_create()
17425184Sek110237 * to all the filesets on the master fileset list. It always
17435184Sek110237 * returns zero (0) if one fileset is populated / created,
17445184Sek110237 * otherwise it returns the sum of returned values from
17455184Sek110237 * fileset_create() and fileset_populate(), which
17465184Sek110237 * will be a negative one (-1) times the number of
17475184Sek110237 * fileset_create() calls which failed.
17485184Sek110237 */
17495184Sek110237 int
fileset_createset(fileset_t * fileset)17505184Sek110237 fileset_createset(fileset_t *fileset)
17515184Sek110237 {
17525184Sek110237 fileset_t *list;
17535184Sek110237 int ret = 0;
17545184Sek110237
17555673Saw148015 /* set up for possible parallel allocate */
17567556SAndrew.W.Wilson@sun.com filebench_shm->shm_fsparalloc_count = 0;
17577556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(
17587556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv,
17597556SAndrew.W.Wilson@sun.com ipc_condattr());
17605673Saw148015
17616212Saw148015 if (fileset && avd_get_bool(fileset->fs_prealloc)) {
17625673Saw148015
17636305Saw148015 /* check for raw files */
17646305Saw148015 if (fileset_checkraw(fileset)) {
17656305Saw148015 filebench_log(LOG_INFO,
17666305Saw148015 "file %s/%s is a RAW device",
17676305Saw148015 avd_get_str(fileset->fs_path),
17686305Saw148015 avd_get_str(fileset->fs_name));
17697556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
17706305Saw148015 }
17716305Saw148015
17725673Saw148015 filebench_log(LOG_INFO,
17735673Saw148015 "creating/pre-allocating %s %s",
17746212Saw148015 fileset_entity_name(fileset),
17756212Saw148015 avd_get_str(fileset->fs_name));
17765673Saw148015
17777556SAndrew.W.Wilson@sun.com if ((ret = fileset_populate(fileset)) != FILEBENCH_OK)
17785184Sek110237 return (ret);
17795673Saw148015
17807556SAndrew.W.Wilson@sun.com if ((ret = fileset_create(fileset)) != FILEBENCH_OK)
17815673Saw148015 return (ret);
17825673Saw148015 } else {
17835673Saw148015
17845673Saw148015 filebench_log(LOG_INFO,
17855673Saw148015 "Creating/pre-allocating files and filesets");
17865673Saw148015
17876391Saw148015 list = filebench_shm->shm_filesetlist;
17885673Saw148015 while (list) {
17896305Saw148015 /* check for raw files */
17906305Saw148015 if (fileset_checkraw(list)) {
17916305Saw148015 filebench_log(LOG_INFO,
17926305Saw148015 "file %s/%s is a RAW device",
17936305Saw148015 avd_get_str(list->fs_path),
17946305Saw148015 avd_get_str(list->fs_name));
17956305Saw148015 list = list->fs_next;
17966305Saw148015 continue;
17976305Saw148015 }
17986305Saw148015
17997556SAndrew.W.Wilson@sun.com if ((ret = fileset_populate(list)) != FILEBENCH_OK)
18005673Saw148015 return (ret);
18017556SAndrew.W.Wilson@sun.com
18027556SAndrew.W.Wilson@sun.com if ((ret = fileset_create(list)) != FILEBENCH_OK)
18035673Saw148015 return (ret);
18047556SAndrew.W.Wilson@sun.com
18055673Saw148015 list = list->fs_next;
18065673Saw148015 }
18075184Sek110237 }
18085184Sek110237
18095673Saw148015 /* wait for allocation threads to finish */
18105673Saw148015 filebench_log(LOG_INFO,
18115673Saw148015 "waiting for fileset pre-allocation to finish");
18125184Sek110237
18137556SAndrew.W.Wilson@sun.com (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock);
18147556SAndrew.W.Wilson@sun.com while (filebench_shm->shm_fsparalloc_count > 0)
18157556SAndrew.W.Wilson@sun.com (void) pthread_cond_wait(
18167556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_cv,
18177556SAndrew.W.Wilson@sun.com &filebench_shm->shm_fsparalloc_lock);
18187556SAndrew.W.Wilson@sun.com (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock);
18195673Saw148015
18207556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_fsparalloc_count < 0)
18217556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
18225673Saw148015
18237556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
18245184Sek110237 }
18255184Sek110237
18265184Sek110237 /*
18275184Sek110237 * Searches through the master fileset list for the named fileset.
18285184Sek110237 * If found, returns pointer to same, otherwise returns NULL.
18295184Sek110237 */
18305184Sek110237 fileset_t *
fileset_find(char * name)18315184Sek110237 fileset_find(char *name)
18325184Sek110237 {
18336391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist;
18345184Sek110237
18356391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
18365184Sek110237
18375184Sek110237 while (fileset) {
18386212Saw148015 if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) {
18396391Saw148015 (void) ipc_mutex_unlock(
18406391Saw148015 &filebench_shm->shm_fileset_lock);
18415184Sek110237 return (fileset);
18425184Sek110237 }
18435184Sek110237 fileset = fileset->fs_next;
18445184Sek110237 }
18456391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
18465184Sek110237
18475184Sek110237 return (NULL);
18485184Sek110237 }
18495673Saw148015
18505673Saw148015 /*
18515673Saw148015 * Iterates over all the file sets in the filesetlist,
18525673Saw148015 * executing the supplied command "*cmd()" on them. Also
18535673Saw148015 * indicates to the executed command if it is the first
18545673Saw148015 * time the command has been executed since the current
18555673Saw148015 * call to fileset_iter.
18565673Saw148015 */
18578404SAndrew.W.Wilson@sun.com int
fileset_iter(int (* cmd)(fileset_t * fileset,int first))18585673Saw148015 fileset_iter(int (*cmd)(fileset_t *fileset, int first))
18595673Saw148015 {
18606391Saw148015 fileset_t *fileset = filebench_shm->shm_filesetlist;
18615673Saw148015 int count = 0;
18625673Saw148015
18636391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock);
18645673Saw148015
18655673Saw148015 while (fileset) {
18668404SAndrew.W.Wilson@sun.com if (cmd(fileset, count == 0) == FILEBENCH_ERROR) {
18678404SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(
18688404SAndrew.W.Wilson@sun.com &filebench_shm->shm_fileset_lock);
18698404SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
18708404SAndrew.W.Wilson@sun.com }
18715673Saw148015 fileset = fileset->fs_next;
18725673Saw148015 count++;
18735673Saw148015 }
18745673Saw148015
18756391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock);
18768404SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
18775673Saw148015 }
18785673Saw148015
18795673Saw148015 /*
18805673Saw148015 * Prints information to the filebench log about the file
18815673Saw148015 * object. Also prints a header on the first call.
18825673Saw148015 */
18835673Saw148015 int
fileset_print(fileset_t * fileset,int first)18845673Saw148015 fileset_print(fileset_t *fileset, int first)
18855673Saw148015 {
18866212Saw148015 int pathlength;
18876212Saw148015 char *fileset_path;
18886212Saw148015 char *fileset_name;
18896212Saw148015 static char pad[] = " "; /* 30 spaces */
18906212Saw148015
18916212Saw148015 if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) {
18926212Saw148015 filebench_log(LOG_ERROR, "%s path not set",
18936212Saw148015 fileset_entity_name(fileset));
18947556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
18956212Saw148015 }
18966212Saw148015
18976212Saw148015 if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) {
18986212Saw148015 filebench_log(LOG_ERROR, "%s name not set",
18996212Saw148015 fileset_entity_name(fileset));
19007556SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR);
19016212Saw148015 }
19026212Saw148015
19036212Saw148015 pathlength = strlen(fileset_path) + strlen(fileset_name);
19045673Saw148015
19055673Saw148015 if (pathlength > 29)
19065673Saw148015 pathlength = 29;
19075673Saw148015
19085673Saw148015 if (first) {
19095673Saw148015 filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s",
19105673Saw148015 "file size",
19115673Saw148015 "dir width",
19125673Saw148015 "entries");
19135673Saw148015 }
19145673Saw148015
19155673Saw148015 if (fileset->fs_attrs & FILESET_IS_FILE) {
19165673Saw148015 if (fileset->fs_attrs & FILESET_IS_RAW_DEV) {
19175673Saw148015 filebench_log(LOG_INFO,
19185673Saw148015 "%s/%s%s (Raw Device)",
19196212Saw148015 fileset_path, fileset_name, &pad[pathlength]);
19205673Saw148015 } else {
19215673Saw148015 filebench_log(LOG_INFO,
19226286Saw148015 "%s/%s%s%9llu (Single File)",
19236212Saw148015 fileset_path, fileset_name, &pad[pathlength],
19246286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size));
19255673Saw148015 }
19265673Saw148015 } else {
19276286Saw148015 filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu",
19286212Saw148015 fileset_path, fileset_name,
19295673Saw148015 &pad[pathlength],
19306286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_size),
19316286Saw148015 (u_longlong_t)avd_get_int(fileset->fs_dirwidth),
19326286Saw148015 (u_longlong_t)fileset->fs_constentries);
19335673Saw148015 }
19347556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
19355673Saw148015 }
19367946SAndrew.W.Wilson@sun.com
19375673Saw148015 /*
19385673Saw148015 * checks to see if the path/name pair points to a raw device. If
19395673Saw148015 * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1.
19405673Saw148015 * If RAW is not defined, or it is not a raw device, it clears the
19415673Saw148015 * raw device flag and returns 0.
19425673Saw148015 */
19435673Saw148015 int
fileset_checkraw(fileset_t * fileset)19445673Saw148015 fileset_checkraw(fileset_t *fileset)
19455673Saw148015 {
19465673Saw148015 char path[MAXPATHLEN];
19475673Saw148015 struct stat64 sb;
19486305Saw148015 char *pathname;
19496305Saw148015 char *setname;
19505673Saw148015
19515673Saw148015 fileset->fs_attrs &= (~FILESET_IS_RAW_DEV);
19525673Saw148015
19535673Saw148015 #ifdef HAVE_RAW_SUPPORT
19545673Saw148015 /* check for raw device */
19556305Saw148015 if ((pathname = avd_get_str(fileset->fs_path)) == NULL)
19567556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
19576305Saw148015
19586305Saw148015 if ((setname = avd_get_str(fileset->fs_name)) == NULL)
19597556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
19606305Saw148015
19617946SAndrew.W.Wilson@sun.com (void) fb_strlcpy(path, pathname, MAXPATHLEN);
19627946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, "/", MAXPATHLEN);
19637946SAndrew.W.Wilson@sun.com (void) fb_strlcat(path, setname, MAXPATHLEN);
19645673Saw148015 if ((stat64(path, &sb) == 0) &&
19655673Saw148015 ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) {
19665673Saw148015 fileset->fs_attrs |= FILESET_IS_RAW_DEV;
19676305Saw148015 if (!(fileset->fs_attrs & FILESET_IS_FILE)) {
19686305Saw148015 filebench_log(LOG_ERROR,
19696305Saw148015 "WARNING Fileset %s/%s Cannot be RAW device",
19706305Saw148015 avd_get_str(fileset->fs_path),
19716305Saw148015 avd_get_str(fileset->fs_name));
19726305Saw148015 filebench_shutdown(1);
19736305Saw148015 }
19746305Saw148015
19755673Saw148015 return (1);
19765673Saw148015 }
19775673Saw148015 #endif /* HAVE_RAW_SUPPORT */
19785673Saw148015
19797556SAndrew.W.Wilson@sun.com return (FILEBENCH_OK);
19805673Saw148015 }
1981