diff options
author | Josef 'Jeff' Sipek <josef.sipek@nexenta.com> | 2014-04-28 16:13:37 -0400 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2014-05-05 07:37:48 -0700 |
commit | d05b42383f649c1384ae2af878515cc2c6674ec6 (patch) | |
tree | bed8341c53c38b7ffa7d9a87f2fae20dba6a8ae5 /usr/src/cmd/filebench/common/fileset.c | |
parent | 5539384561c0efe744226d5e5d331f5546e500e4 (diff) | |
download | illumos-gate-d05b42383f649c1384ae2af878515cc2c6674ec6.tar.gz |
4821 remove filebench
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Richard Elling <richard.elling@gmail.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src/cmd/filebench/common/fileset.c')
-rw-r--r-- | usr/src/cmd/filebench/common/fileset.c | 1980 |
1 files changed, 0 insertions, 1980 deletions
diff --git a/usr/src/cmd/filebench/common/fileset.c b/usr/src/cmd/filebench/common/fileset.c deleted file mode 100644 index 38a075be42..0000000000 --- a/usr/src/cmd/filebench/common/fileset.c +++ /dev/null @@ -1,1980 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * Portions Copyright 2008 Denis Cheng - */ - -#include <fcntl.h> -#include <pthread.h> -#include <errno.h> -#include <math.h> -#include <libgen.h> -#include <sys/mman.h> -#include <sys/shm.h> - -#include "filebench.h" -#include "fileset.h" -#include "gamma_dist.h" -#include "utils.h" -#include "fsplug.h" - -/* - * File sets, of type fileset_t, are entities which contain - * information about collections of files and subdirectories in Filebench. - * The fileset, once populated, consists of a tree of fileset entries of - * type filesetentry_t which specify files and directories. The fileset - * is rooted in a directory specified by fileset_path, and once the populated - * fileset has been created, has a tree of directories and files - * corresponding to the fileset's filesetentry tree. - * - * Fileset entities are allocated by fileset_define() which is called from - * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding - * to the eventual directory and file tree to be instantiated on the storage - * medium is built by fileset_populate(), which is This routine is called - * from fileset_createset(), which is in turn called by fileset_createset(). - * After calling fileset_populate(), fileset_createset() will call - * fileset_create() to pre-allocate designated files and directories. - * - * Fileset_createset() is called from parser_gram.y: parser_create_fileset() - * when a "create fileset" or "run" command is encountered. When the - * "create fileset" command is used, it is generally paired with - * a "create processes" command, and must appear first, in order to - * instantiate all the files in the fileset before trying to use them. - */ - -static int fileset_checkraw(fileset_t *fileset); - -/* maximum parallel allocation control */ -#define MAX_PARALLOC_THREADS 32 - -/* - * returns pointer to file or fileset - * string, as appropriate - */ -static char * -fileset_entity_name(fileset_t *fileset) -{ - if (fileset->fs_attrs & FILESET_IS_FILE) - return ("file"); - else - return ("fileset"); -} - -/* - * Removes the last file or directory name from a pathname. - * Basically removes characters from the end of the path by - * setting them to \0 until a forward slash '/' is - * encountered. It also removes the forward slash. - */ -static char * -trunc_dirname(char *dir) -{ - char *s = dir + strlen(dir); - - while (s != dir) { - int c = *s; - - *s = 0; - if (c == '/') - break; - s--; - } - return (dir); -} - -/* - * Prints a list of allowed options and how to specify them. - */ -void -fileset_usage(void) -{ - (void) fprintf(stderr, - "define [file name=<name> | fileset name=<name>],path=<pathname>," - ",entries=<number>\n"); - (void) fprintf(stderr, - " [,filesize=[size]]\n"); - (void) fprintf(stderr, - " [,dirwidth=[width]]\n"); - (void) fprintf(stderr, - " [,dirdepthrv=$random_variable_name]\n"); - (void) fprintf(stderr, - " [,dirgamma=[100-10000]] " - "(Gamma * 1000)\n"); - (void) fprintf(stderr, - " [,sizegamma=[100-10000]] (Gamma * 1000)\n"); - (void) fprintf(stderr, - " [,prealloc=[percent]]\n"); - (void) fprintf(stderr, " [,paralloc]\n"); - (void) fprintf(stderr, " [,reuse]\n"); - (void) fprintf(stderr, "\n"); -} - -/* - * Creates a path string from the filesetentry_t "*entry" - * and all of its parent's path names. The resulting path - * is a concatination of all the individual parent paths. - * Allocates memory for the path string and returns a - * pointer to it. - */ -char * -fileset_resolvepath(filesetentry_t *entry) -{ - filesetentry_t *fsep = entry; - char path[MAXPATHLEN]; - char pathtmp[MAXPATHLEN]; - char *s; - - path[0] = '\0'; - while (fsep->fse_parent) { - (void) strcpy(pathtmp, "/"); - (void) fb_strlcat(pathtmp, fsep->fse_path, MAXPATHLEN); - (void) fb_strlcat(pathtmp, path, MAXPATHLEN); - (void) fb_strlcpy(path, pathtmp, MAXPATHLEN); - fsep = fsep->fse_parent; - } - - s = malloc(strlen(path) + 1); - (void) fb_strlcpy(s, path, MAXPATHLEN); - return (s); -} - -/* - * Creates multiple nested directories as required by the - * supplied path. Starts at the end of the path, creating - * a list of directories to mkdir, up to the root of the - * path, then mkdirs them one at a time from the root on down. - */ -static int -fileset_mkdir(char *path, int mode) -{ - char *p; - char *dirs[65536]; - int i = 0; - - if ((p = strdup(path)) == NULL) - goto null_str; - - /* - * Fill an array of subdirectory path names until either we - * reach the root or encounter an already existing subdirectory - */ - /* CONSTCOND */ - while (1) { - struct stat64 sb; - - if (stat64(p, &sb) == 0) - break; - if (strlen(p) < 3) - break; - if ((dirs[i] = strdup(p)) == NULL) { - free(p); - goto null_str; - } - - (void) trunc_dirname(p); - i++; - } - - /* Make the directories, from closest to root downwards. */ - for (--i; i >= 0; i--) { - (void) FB_MKDIR(dirs[i], mode); - free(dirs[i]); - } - - free(p); - return (FILEBENCH_OK); - -null_str: - /* clean up */ - for (--i; i >= 0; i--) - free(dirs[i]); - - filebench_log(LOG_ERROR, - "Failed to create directory path %s: Out of memory", path); - return (FILEBENCH_ERROR); -} - -/* - * creates the subdirectory tree for a fileset. - */ -static int -fileset_create_subdirs(fileset_t *fileset, char *filesetpath) -{ - filesetentry_t *direntry; - char full_path[MAXPATHLEN]; - char *part_path; - - /* walk the subdirectory list, enstanciating subdirs */ - direntry = fileset->fs_dirlist; - while (direntry) { - (void) fb_strlcpy(full_path, filesetpath, MAXPATHLEN); - part_path = fileset_resolvepath(direntry); - (void) fb_strlcat(full_path, part_path, MAXPATHLEN); - free(part_path); - - /* now create this portion of the subdirectory tree */ - if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR) - return (FILEBENCH_ERROR); - - direntry = direntry->fse_nextoftype; - } - return (FILEBENCH_OK); -} - -/* - * move filesetentry between exist tree and non-exist tree, source_tree - * to destination tree. - */ -static void -fileset_move_entry(avl_tree_t *src_tree, avl_tree_t *dst_tree, - filesetentry_t *entry) -{ - avl_remove(src_tree, entry); - avl_add(dst_tree, entry); -} - -/* - * given a fileset entry, determines if the associated leaf directory - * needs to be made or not, and if so does the mkdir. - */ -static int -fileset_alloc_leafdir(filesetentry_t *entry) -{ - fileset_t *fileset; - char path[MAXPATHLEN]; - struct stat64 sb; - char *pathtmp; - - fileset = entry->fse_fileset; - (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); - (void) fb_strlcat(path, "/", MAXPATHLEN); - (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); - pathtmp = fileset_resolvepath(entry); - (void) fb_strlcat(path, pathtmp, MAXPATHLEN); - free(pathtmp); - - filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); - - /* see if not reusing and this directory does not exist */ - if (!((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0))) { - - /* No file or not reusing, so create */ - if (FB_MKDIR(path, 0755) < 0) { - filebench_log(LOG_ERROR, - "Failed to pre-allocate leaf directory %s: %s", - path, strerror(errno)); - fileset_unbusy(entry, TRUE, FALSE, 0); - return (FILEBENCH_ERROR); - } - } - - /* unbusy the allocated entry */ - fileset_unbusy(entry, TRUE, TRUE, 0); - return (FILEBENCH_OK); -} - -/* - * given a fileset entry, determines if the associated file - * needs to be allocated or not, and if so does the allocation. - */ -static int -fileset_alloc_file(filesetentry_t *entry) -{ - fileset_t *fileset; - char path[MAXPATHLEN]; - char *buf; - struct stat64 sb; - char *pathtmp; - off64_t seek; - fb_fdesc_t fdesc; - int trust_tree; - - fileset = entry->fse_fileset; - (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); - (void) fb_strlcat(path, "/", MAXPATHLEN); - (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); - pathtmp = fileset_resolvepath(entry); - (void) fb_strlcat(path, pathtmp, MAXPATHLEN); - free(pathtmp); - - filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path); - - /* see if reusing and this file exists */ - trust_tree = avd_get_bool(fileset->fs_trust_tree); - if ((entry->fse_flags & FSE_REUSING) && (trust_tree || - (FB_STAT(path, &sb) == 0))) { - if (FB_OPEN(&fdesc, path, O_RDWR, 0) == FILEBENCH_ERROR) { - filebench_log(LOG_INFO, - "Attempted but failed to Re-use file %s", - path); - fileset_unbusy(entry, TRUE, FALSE, 0); - return (FILEBENCH_ERROR); - } - - if (trust_tree || (sb.st_size == (off64_t)entry->fse_size)) { - filebench_log(LOG_DEBUG_IMPL, - "Re-using file %s", path); - - if (!avd_get_bool(fileset->fs_cached)) - (void) FB_FREEMEM(&fdesc, entry->fse_size); - - (void) FB_CLOSE(&fdesc); - - /* unbusy the allocated entry */ - fileset_unbusy(entry, TRUE, TRUE, 0); - return (FILEBENCH_OK); - - } else if (sb.st_size > (off64_t)entry->fse_size) { - /* reuse, but too large */ - filebench_log(LOG_DEBUG_IMPL, - "Truncating & re-using file %s", path); - - (void) FB_FTRUNC(&fdesc, (off64_t)entry->fse_size); - - if (!avd_get_bool(fileset->fs_cached)) - (void) FB_FREEMEM(&fdesc, entry->fse_size); - - (void) FB_CLOSE(&fdesc); - - /* unbusy the allocated entry */ - fileset_unbusy(entry, TRUE, TRUE, 0); - return (FILEBENCH_OK); - } - } else { - - /* No file or not reusing, so create */ - if (FB_OPEN(&fdesc, path, O_RDWR | O_CREAT, 0644) == - FILEBENCH_ERROR) { - filebench_log(LOG_ERROR, - "Failed to pre-allocate file %s: %s", - path, strerror(errno)); - - /* unbusy the unallocated entry */ - fileset_unbusy(entry, TRUE, FALSE, 0); - return (FILEBENCH_ERROR); - } - } - - if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) { - /* unbusy the unallocated entry */ - fileset_unbusy(entry, TRUE, FALSE, 0); - return (FILEBENCH_ERROR); - } - - for (seek = 0; seek < entry->fse_size; ) { - off64_t wsize; - int ret = 0; - - /* - * Write FILE_ALLOC_BLOCK's worth, - * except on last write - */ - wsize = MIN(entry->fse_size - seek, FILE_ALLOC_BLOCK); - - ret = FB_WRITE(&fdesc, buf, wsize); - if (ret != wsize) { - filebench_log(LOG_ERROR, - "Failed to pre-allocate file %s: %s", - path, strerror(errno)); - (void) FB_CLOSE(&fdesc); - free(buf); - fileset_unbusy(entry, TRUE, FALSE, 0); - return (FILEBENCH_ERROR); - } - seek += wsize; - } - - if (!avd_get_bool(fileset->fs_cached)) - (void) FB_FREEMEM(&fdesc, entry->fse_size); - - (void) FB_CLOSE(&fdesc); - - free(buf); - - /* unbusy the allocated entry */ - fileset_unbusy(entry, TRUE, TRUE, 0); - - filebench_log(LOG_DEBUG_IMPL, - "Pre-allocated file %s size %llu", - path, (u_longlong_t)entry->fse_size); - - return (FILEBENCH_OK); -} - -/* - * given a fileset entry, determines if the associated file - * needs to be allocated or not, and if so does the allocation. - * Sets shm_fsparalloc_count to -1 on error. - */ -static void * -fileset_alloc_thread(filesetentry_t *entry) -{ - if (fileset_alloc_file(entry) == FILEBENCH_ERROR) { - (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); - filebench_shm->shm_fsparalloc_count = -1; - } else { - (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); - filebench_shm->shm_fsparalloc_count--; - } - - (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv); - (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); - - pthread_exit(NULL); - return (NULL); -} - - -/* - * First creates the parent directories of the file using - * fileset_mkdir(). Then Optionally sets the O_DSYNC flag - * and opens the file with open64(). It unlocks the fileset - * entry lock, sets the DIRECTIO_ON or DIRECTIO_OFF flags - * as requested, and returns the file descriptor integer - * for the opened file in the supplied filebench file descriptor. - * Returns FILEBENCH_ERROR on error, and FILEBENCH_OK on success. - */ -int -fileset_openfile(fb_fdesc_t *fdesc, fileset_t *fileset, - filesetentry_t *entry, int flag, int filemode, int attrs) -{ - char path[MAXPATHLEN]; - char dir[MAXPATHLEN]; - char *pathtmp; - struct stat64 sb; - int open_attrs = 0; - - (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN); - (void) fb_strlcat(path, "/", MAXPATHLEN); - (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN); - pathtmp = fileset_resolvepath(entry); - (void) fb_strlcat(path, pathtmp, MAXPATHLEN); - (void) fb_strlcpy(dir, path, MAXPATHLEN); - free(pathtmp); - (void) trunc_dirname(dir); - - /* If we are going to create a file, create the parent dirs */ - if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) { - if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR) - return (FILEBENCH_ERROR); - } - - if (attrs & FLOW_ATTR_DSYNC) { -#ifdef sun - open_attrs |= O_DSYNC; -#else - open_attrs |= O_FSYNC; -#endif - } - - if (FB_OPEN(fdesc, path, flag | open_attrs, filemode) - == FILEBENCH_ERROR) { - filebench_log(LOG_ERROR, - "Failed to open file %d, %s, with status %x: %s", - entry->fse_index, path, entry->fse_flags, strerror(errno)); - - fileset_unbusy(entry, FALSE, FALSE, 0); - return (FILEBENCH_ERROR); - } - - if (flag & O_CREAT) - fileset_unbusy(entry, TRUE, TRUE, 1); - else - fileset_unbusy(entry, FALSE, FALSE, 1); - -#ifdef sun - if (attrs & FLOW_ATTR_DIRECTIO) - (void) directio(fdesc->fd_num, DIRECTIO_ON); - else - (void) directio(fdesc->fd_num, DIRECTIO_OFF); -#endif - - return (FILEBENCH_OK); -} - -/* - * removes all filesetentries from their respective btrees, and puts them - * on the free list. The supplied argument indicates which free list to - * use. - */ -static void -fileset_pickreset(fileset_t *fileset, int entry_type) -{ - filesetentry_t *entry; - - switch (entry_type & FILESET_PICKMASK) { - case FILESET_PICKFILE: - entry = (filesetentry_t *)avl_first(&fileset->fs_noex_files); - - /* make sure non-existing files are marked free */ - while (entry) { - entry->fse_flags |= FSE_FREE; - entry->fse_open_cnt = 0; - fileset_move_entry(&fileset->fs_noex_files, - &fileset->fs_free_files, entry); - entry = AVL_NEXT(&fileset->fs_noex_files, entry); - } - - /* free up any existing files */ - entry = (filesetentry_t *)avl_first(&fileset->fs_exist_files); - - while (entry) { - entry->fse_flags |= FSE_FREE; - entry->fse_open_cnt = 0; - fileset_move_entry(&fileset->fs_exist_files, - &fileset->fs_free_files, entry); - - entry = AVL_NEXT(&fileset->fs_exist_files, entry); - } - - break; - - case FILESET_PICKDIR: - /* nothing to reset, as all (sub)dirs always exist */ - break; - - case FILESET_PICKLEAFDIR: - entry = (filesetentry_t *) - avl_first(&fileset->fs_noex_leaf_dirs); - - /* make sure non-existing leaf dirs are marked free */ - while (entry) { - entry->fse_flags |= FSE_FREE; - entry->fse_open_cnt = 0; - fileset_move_entry(&fileset->fs_noex_leaf_dirs, - &fileset->fs_free_leaf_dirs, entry); - entry = AVL_NEXT(&fileset->fs_noex_leaf_dirs, entry); - } - - /* free up any existing leaf dirs */ - entry = (filesetentry_t *) - avl_first(&fileset->fs_exist_leaf_dirs); - - while (entry) { - entry->fse_flags |= FSE_FREE; - entry->fse_open_cnt = 0; - fileset_move_entry(&fileset->fs_exist_leaf_dirs, - &fileset->fs_free_leaf_dirs, entry); - - entry = AVL_NEXT(&fileset->fs_exist_leaf_dirs, entry); - } - - break; - } -} - -/* - * find a filesetentry from the fileset using the supplied index - */ -static filesetentry_t * -fileset_find_entry(avl_tree_t *atp, uint_t index) -{ - avl_index_t found_loc; - filesetentry_t desired_fse, *found_fse; - - /* find the file with the desired index, if it is in the tree */ - desired_fse.fse_index = index; - found_fse = avl_find(atp, (void *)(&desired_fse), &found_loc); - if (found_fse != NULL) - return (found_fse); - - /* if requested node not found, find next higher node */ - found_fse = avl_nearest(atp, found_loc, AVL_AFTER); - if (found_fse != NULL) - return (found_fse); - - /* might have hit the end, return lowest available index node */ - found_fse = avl_first(atp); - return (found_fse); -} - -/* - * Selects a fileset entry from a fileset. If the - * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry, - * if the FILESET_PICKDIR flag is set it will pick a non leaf directory - * entry, otherwise a file entry. The FILESET_PICKUNIQUE - * flag will take an entry off of one of the free (unused) - * lists (file or directory), otherwise the entry will be - * picked off of one of the rotor lists (file or directory). - * The FILESET_PICKEXISTS will insure that only extant - * (FSE_EXISTS) state files are selected, while - * FILESET_PICKNOEXIST insures that only non extant - * (not FSE_EXISTS) state files are selected. - * Note that the selected fileset entry (file) is returned - * with its FSE_BUSY flag (in fse_flags) set. - */ -filesetentry_t * -fileset_pick(fileset_t *fileset, int flags, int tid, int index) -{ - filesetentry_t *entry = NULL; - filesetentry_t *start_point; - avl_tree_t *atp; - fbint_t max_entries; - - (void) ipc_mutex_lock(&fileset->fs_pick_lock); - - /* see if we have to wait for available files or directories */ - switch (flags & FILESET_PICKMASK) { - case FILESET_PICKFILE: - if (fileset->fs_filelist == NULL) - goto empty; - - while (fileset->fs_idle_files == 0) { - (void) pthread_cond_wait(&fileset->fs_idle_files_cv, - &fileset->fs_pick_lock); - } - - max_entries = fileset->fs_constentries; - if (flags & FILESET_PICKUNIQUE) { - atp = &fileset->fs_free_files; - } else if (flags & FILESET_PICKNOEXIST) { - atp = &fileset->fs_noex_files; - } else { - atp = &fileset->fs_exist_files; - } - break; - - case FILESET_PICKDIR: - if (fileset->fs_dirlist == NULL) - goto empty; - - while (fileset->fs_idle_dirs == 0) { - (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv, - &fileset->fs_pick_lock); - } - - max_entries = 1; - atp = &fileset->fs_dirs; - break; - - case FILESET_PICKLEAFDIR: - if (fileset->fs_leafdirlist == NULL) - goto empty; - - while (fileset->fs_idle_leafdirs == 0) { - (void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv, - &fileset->fs_pick_lock); - } - - max_entries = fileset->fs_constleafdirs; - if (flags & FILESET_PICKUNIQUE) { - atp = &fileset->fs_free_leaf_dirs; - } else if (flags & FILESET_PICKNOEXIST) { - atp = &fileset->fs_noex_leaf_dirs; - } else { - atp = &fileset->fs_exist_leaf_dirs; - } - break; - } - - /* see if asking for impossible */ - if (avl_is_empty(atp)) - goto empty; - - if (flags & FILESET_PICKUNIQUE) { - uint64_t index64; - - /* - * pick at random from free list in order to - * distribute initially allocated files more - * randomly on storage media. Use uniform - * random number generator to select index - * if it is not supplied with pick call. - */ - if (index) { - index64 = index; - } else { - if (filebench_randomno64(&index64, max_entries, 1, - NULL) == FILEBENCH_ERROR) - return (NULL); - } - - entry = fileset_find_entry(atp, (int)index64); - - if (entry == NULL) - goto empty; - - } else if (flags & FILESET_PICKBYINDEX) { - /* pick by supplied index */ - entry = fileset_find_entry(atp, index); - - } else { - /* pick in rotation */ - switch (flags & FILESET_PICKMASK) { - case FILESET_PICKFILE: - if (flags & FILESET_PICKNOEXIST) { - entry = fileset_find_entry(atp, - fileset->fs_file_nerotor); - fileset->fs_file_nerotor = - entry->fse_index + 1; - } else { - entry = fileset_find_entry(atp, - fileset->fs_file_exrotor[tid]); - fileset->fs_file_exrotor[tid] = - entry->fse_index + 1; - } - break; - - case FILESET_PICKDIR: - entry = fileset_find_entry(atp, fileset->fs_dirrotor); - fileset->fs_dirrotor = entry->fse_index + 1; - break; - - case FILESET_PICKLEAFDIR: - if (flags & FILESET_PICKNOEXIST) { - entry = fileset_find_entry(atp, - fileset->fs_leafdir_nerotor); - fileset->fs_leafdir_nerotor = - entry->fse_index + 1; - } else { - entry = fileset_find_entry(atp, - fileset->fs_leafdir_exrotor); - fileset->fs_leafdir_exrotor = - entry->fse_index + 1; - } - break; - } - } - - if (entry == NULL) - goto empty; - - /* see if entry in use */ - start_point = entry; - while (entry->fse_flags & FSE_BUSY) { - - /* it is, so try next */ - entry = AVL_NEXT(atp, entry); - if (entry == NULL) - entry = avl_first(atp); - - /* see if we have wrapped around */ - if ((entry == NULL) || (entry == start_point)) { - filebench_log(LOG_DEBUG_SCRIPT, - "All %d files are busy", avl_numnodes(atp)); - goto empty; - } - - } - - /* update file or directory idle counts */ - switch (flags & FILESET_PICKMASK) { - case FILESET_PICKFILE: - fileset->fs_idle_files--; - break; - case FILESET_PICKDIR: - fileset->fs_idle_dirs--; - break; - case FILESET_PICKLEAFDIR: - fileset->fs_idle_leafdirs--; - break; - } - - /* Indicate that file or directory is now busy */ - entry->fse_flags |= FSE_BUSY; - - (void) ipc_mutex_unlock(&fileset->fs_pick_lock); - filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path); - return (entry); - -empty: - filebench_log(LOG_DEBUG_SCRIPT, "No file found"); - (void) ipc_mutex_unlock(&fileset->fs_pick_lock); - return (NULL); -} - -/* - * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads - * that are waiting for a NOT BUSY filesetentry. Also sets whether it is - * existant or not, or leaves that designation alone. - */ -void -fileset_unbusy(filesetentry_t *entry, int update_exist, - int new_exist_val, int open_cnt_incr) -{ - fileset_t *fileset = NULL; - - if (entry) - fileset = entry->fse_fileset; - - if (fileset == NULL) { - filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!"); - return; - } - - (void) ipc_mutex_lock(&fileset->fs_pick_lock); - - /* modify FSE_EXIST flag and actual dirs/files count, if requested */ - if (update_exist) { - if (new_exist_val == TRUE) { - if (entry->fse_flags & FSE_FREE) { - - /* asked to set and it was free */ - entry->fse_flags |= FSE_EXISTS; - entry->fse_flags &= (~FSE_FREE); - switch (entry->fse_flags & FSE_TYPE_MASK) { - case FSE_TYPE_FILE: - fileset_move_entry( - &fileset->fs_free_files, - &fileset->fs_exist_files, entry); - break; - - case FSE_TYPE_DIR: - break; - - case FSE_TYPE_LEAFDIR: - fileset_move_entry( - &fileset->fs_free_leaf_dirs, - &fileset->fs_exist_leaf_dirs, - entry); - break; - } - - } else if (!(entry->fse_flags & FSE_EXISTS)) { - - /* asked to set, and it was clear */ - entry->fse_flags |= FSE_EXISTS; - switch (entry->fse_flags & FSE_TYPE_MASK) { - case FSE_TYPE_FILE: - fileset_move_entry( - &fileset->fs_noex_files, - &fileset->fs_exist_files, entry); - break; - case FSE_TYPE_DIR: - break; - case FSE_TYPE_LEAFDIR: - fileset_move_entry( - &fileset->fs_noex_leaf_dirs, - &fileset->fs_exist_leaf_dirs, - entry); - break; - } - } - } else { - if (entry->fse_flags & FSE_FREE) { - /* asked to clear, and it was free */ - entry->fse_flags &= (~(FSE_FREE | FSE_EXISTS)); - switch (entry->fse_flags & FSE_TYPE_MASK) { - case FSE_TYPE_FILE: - fileset_move_entry( - &fileset->fs_free_files, - &fileset->fs_noex_files, entry); - break; - - case FSE_TYPE_DIR: - break; - - case FSE_TYPE_LEAFDIR: - fileset_move_entry( - &fileset->fs_free_leaf_dirs, - &fileset->fs_noex_leaf_dirs, - entry); - break; - } - } else if (entry->fse_flags & FSE_EXISTS) { - - /* asked to clear, and it was set */ - entry->fse_flags &= (~FSE_EXISTS); - switch (entry->fse_flags & FSE_TYPE_MASK) { - case FSE_TYPE_FILE: - fileset_move_entry( - &fileset->fs_exist_files, - &fileset->fs_noex_files, entry); - break; - case FSE_TYPE_DIR: - break; - case FSE_TYPE_LEAFDIR: - fileset_move_entry( - &fileset->fs_exist_leaf_dirs, - &fileset->fs_noex_leaf_dirs, - entry); - break; - } - } - } - } - - /* update open count */ - entry->fse_open_cnt += open_cnt_incr; - - /* increment idle count, clear FSE_BUSY and signal IF it was busy */ - if (entry->fse_flags & FSE_BUSY) { - - /* unbusy it */ - entry->fse_flags &= (~FSE_BUSY); - - /* release any threads waiting for unbusy */ - if (entry->fse_flags & FSE_THRD_WAITNG) { - entry->fse_flags &= (~FSE_THRD_WAITNG); - (void) pthread_cond_broadcast( - &fileset->fs_thrd_wait_cv); - } - - /* increment idle count and signal waiting threads */ - switch (entry->fse_flags & FSE_TYPE_MASK) { - case FSE_TYPE_FILE: - fileset->fs_idle_files++; - if (fileset->fs_idle_files == 1) { - (void) pthread_cond_signal( - &fileset->fs_idle_files_cv); - } - break; - - case FSE_TYPE_DIR: - fileset->fs_idle_dirs++; - if (fileset->fs_idle_dirs == 1) { - (void) pthread_cond_signal( - &fileset->fs_idle_dirs_cv); - } - break; - - case FSE_TYPE_LEAFDIR: - fileset->fs_idle_leafdirs++; - if (fileset->fs_idle_leafdirs == 1) { - (void) pthread_cond_signal( - &fileset->fs_idle_leafdirs_cv); - } - break; - } - } - - (void) ipc_mutex_unlock(&fileset->fs_pick_lock); -} - -/* - * Given a fileset "fileset", create the associated files as - * specified in the attributes of the fileset. The fileset is - * rooted in a directory whose pathname is in fileset_path. If the - * directory exists, meaning that there is already a fileset, - * and the fileset_reuse attribute is false, then remove it and all - * its contained files and subdirectories. Next, the routine - * creates a root directory for the fileset. All the file type - * filesetentries are cycled through creating as needed - * their containing subdirectory trees in the filesystem and - * creating actual files for fileset_preallocpercent of them. The - * created files are filled with fse_size bytes of unitialized - * data. The routine returns FILEBENCH_ERROR on errors, - * FILEBENCH_OK on success. - */ -static int -fileset_create(fileset_t *fileset) -{ - filesetentry_t *entry; - char path[MAXPATHLEN]; - struct stat64 sb; - hrtime_t start = gethrtime(); - char *fileset_path; - char *fileset_name; - int randno; - int preallocated = 0; - int reusing; - - if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { - filebench_log(LOG_ERROR, "%s path not set", - fileset_entity_name(fileset)); - return (FILEBENCH_ERROR); - } - - if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { - filebench_log(LOG_ERROR, "%s name not set", - fileset_entity_name(fileset)); - return (FILEBENCH_ERROR); - } - -#ifdef HAVE_RAW_SUPPORT - /* treat raw device as special case */ - if (fileset->fs_attrs & FILESET_IS_RAW_DEV) - return (FILEBENCH_OK); -#endif /* HAVE_RAW_SUPPORT */ - - /* XXX Add check to see if there is enough space */ - - /* set up path to fileset */ - (void) fb_strlcpy(path, fileset_path, MAXPATHLEN); - (void) fb_strlcat(path, "/", MAXPATHLEN); - (void) fb_strlcat(path, fileset_name, MAXPATHLEN); - - /* if reusing and trusting to exist, just blindly reuse */ - if (avd_get_bool(fileset->fs_trust_tree)) { - reusing = 1; - - /* if exists and resusing, then don't create new */ - } else if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) && - (strlen(avd_get_str(fileset->fs_path)) > 2)) && - avd_get_bool(fileset->fs_reuse)) { - reusing = 1; - } else { - reusing = 0; - } - - if (!reusing) { - /* Remove existing */ - FB_RECUR_RM(path); - filebench_log(LOG_VERBOSE, - "Removed any existing %s %s in %llu seconds", - fileset_entity_name(fileset), fileset_name, - (u_longlong_t)(((gethrtime() - start) / - 1000000000) + 1)); - } else { - /* we are re-using */ - filebench_log(LOG_VERBOSE, "Re-using %s %s.", - fileset_entity_name(fileset), fileset_name); - } - - /* make the filesets directory tree unless in reuse mode */ - if (!reusing && (avd_get_bool(fileset->fs_prealloc))) { - filebench_log(LOG_VERBOSE, - "making tree for filset %s", path); - - (void) FB_MKDIR(path, 0755); - - if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR) - return (FILEBENCH_ERROR); - } - - start = gethrtime(); - - filebench_log(LOG_VERBOSE, "Creating %s %s...", - fileset_entity_name(fileset), fileset_name); - - randno = ((RAND_MAX * (100 - - avd_get_int(fileset->fs_preallocpercent))) / 100); - - /* alloc any files, as required */ - fileset_pickreset(fileset, FILESET_PICKFILE); - while (entry = fileset_pick(fileset, - FILESET_PICKFREE | FILESET_PICKFILE, 0, 0)) { - pthread_t tid; - int newrand; - - newrand = rand(); - - if (newrand < randno) { - /* unbusy the unallocated entry */ - fileset_unbusy(entry, TRUE, FALSE, 0); - continue; - } - - preallocated++; - - if (reusing) - entry->fse_flags |= FSE_REUSING; - else - entry->fse_flags &= (~FSE_REUSING); - - /* fire off allocation threads for each file if paralloc set */ - if (avd_get_bool(fileset->fs_paralloc)) { - - /* limit total number of simultaneous allocations */ - (void) pthread_mutex_lock( - &filebench_shm->shm_fsparalloc_lock); - while (filebench_shm->shm_fsparalloc_count - >= MAX_PARALLOC_THREADS) { - (void) pthread_cond_wait( - &filebench_shm->shm_fsparalloc_cv, - &filebench_shm->shm_fsparalloc_lock); - } - - /* quit if any allocation thread reports an error */ - if (filebench_shm->shm_fsparalloc_count < 0) { - (void) pthread_mutex_unlock( - &filebench_shm->shm_fsparalloc_lock); - return (FILEBENCH_ERROR); - } - - filebench_shm->shm_fsparalloc_count++; - (void) pthread_mutex_unlock( - &filebench_shm->shm_fsparalloc_lock); - - /* - * Fire off a detached allocation thread per file. - * The thread will self destruct when it finishes - * writing pre-allocation data to the file. - */ - if (pthread_create(&tid, NULL, - (void *(*)(void*))fileset_alloc_thread, - entry) == 0) { - /* - * A thread was created; detach it so it can - * fully quit when finished. - */ - (void) pthread_detach(tid); - } else { - filebench_log(LOG_ERROR, - "File prealloc thread create failed"); - filebench_shutdown(1); - } - - } else { - if (fileset_alloc_file(entry) == FILEBENCH_ERROR) - return (FILEBENCH_ERROR); - } - } - - /* alloc any leaf directories, as required */ - fileset_pickreset(fileset, FILESET_PICKLEAFDIR); - while (entry = fileset_pick(fileset, - FILESET_PICKFREE | FILESET_PICKLEAFDIR, 0, 0)) { - - if (rand() < randno) { - /* unbusy the unallocated entry */ - fileset_unbusy(entry, TRUE, FALSE, 0); - continue; - } - - preallocated++; - - if (reusing) - entry->fse_flags |= FSE_REUSING; - else - entry->fse_flags &= (~FSE_REUSING); - - if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR) - return (FILEBENCH_ERROR); - } - -exit: - filebench_log(LOG_VERBOSE, - "Preallocated %d of %llu of %s %s in %llu seconds", - preallocated, - (u_longlong_t)fileset->fs_constentries, - fileset_entity_name(fileset), fileset_name, - (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1)); - - return (FILEBENCH_OK); -} - -/* - * Removes all files and directories associated with a fileset - * from the storage subsystem. - */ -static void -fileset_delete_storage(fileset_t *fileset) -{ - char path[MAXPATHLEN]; - char *fileset_path; - char *fileset_name; - - if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) - return; - - if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) - return; - -#ifdef HAVE_RAW_SUPPORT - /* treat raw device as special case */ - if (fileset->fs_attrs & FILESET_IS_RAW_DEV) - return; -#endif /* HAVE_RAW_SUPPORT */ - - /* set up path to file */ - (void) fb_strlcpy(path, fileset_path, MAXPATHLEN); - (void) fb_strlcat(path, "/", MAXPATHLEN); - (void) fb_strlcat(path, fileset_name, MAXPATHLEN); - - /* now delete any files and directories on the disk */ - FB_RECUR_RM(path); -} - -/* - * Removes the fileset entity and all of its filesetentry entities. - */ -static void -fileset_delete_fileset(fileset_t *fileset) -{ - filesetentry_t *entry, *next_entry; - - /* run down the file list, removing and freeing each filesetentry */ - for (entry = fileset->fs_filelist; entry; entry = next_entry) { - - /* free the entry */ - next_entry = entry->fse_next; - - /* return it to the pool */ - switch (entry->fse_flags & FSE_TYPE_MASK) { - case FSE_TYPE_FILE: - case FSE_TYPE_LEAFDIR: - case FSE_TYPE_DIR: - ipc_free(FILEBENCH_FILESETENTRY, (void *)entry); - break; - default: - filebench_log(LOG_ERROR, - "Unallocated filesetentry found on list"); - break; - } - } - - ipc_free(FILEBENCH_FILESET, (void *)fileset); -} - -void -fileset_delete_all_filesets(void) -{ - fileset_t *fileset, *next_fileset; - - for (fileset = filebench_shm->shm_filesetlist; - fileset; fileset = next_fileset) { - next_fileset = fileset->fs_next; - fileset_delete_storage(fileset); - fileset_delete_fileset(fileset); - } - - filebench_shm->shm_filesetlist = NULL; -} -/* - * Adds an entry to the fileset's file list. Single threaded so - * no locking needed. - */ -static void -fileset_insfilelist(fileset_t *fileset, filesetentry_t *entry) -{ - entry->fse_flags = FSE_TYPE_FILE | FSE_FREE; - avl_add(&fileset->fs_free_files, entry); - - if (fileset->fs_filelist == NULL) { - fileset->fs_filelist = entry; - entry->fse_nextoftype = NULL; - } else { - entry->fse_nextoftype = fileset->fs_filelist; - fileset->fs_filelist = entry; - } -} - -/* - * Adds an entry to the fileset's directory list. Single - * threaded so no locking needed. - */ -static void -fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) -{ - entry->fse_flags = FSE_TYPE_DIR | FSE_EXISTS; - avl_add(&fileset->fs_dirs, entry); - - if (fileset->fs_dirlist == NULL) { - fileset->fs_dirlist = entry; - entry->fse_nextoftype = NULL; - } else { - entry->fse_nextoftype = fileset->fs_dirlist; - fileset->fs_dirlist = entry; - } -} - -/* - * Adds an entry to the fileset's leaf directory list. Single - * threaded so no locking needed. - */ -static void -fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry) -{ - entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE; - avl_add(&fileset->fs_free_leaf_dirs, entry); - - if (fileset->fs_leafdirlist == NULL) { - fileset->fs_leafdirlist = entry; - entry->fse_nextoftype = NULL; - } else { - entry->fse_nextoftype = fileset->fs_leafdirlist; - fileset->fs_leafdirlist = entry; - } -} - -/* - * Compares two fileset entries to determine their relative order - */ -static int -fileset_entry_compare(const void *node_1, const void *node_2) -{ - if (((filesetentry_t *)node_1)->fse_index < - ((filesetentry_t *)node_2)->fse_index) - return (-1); - - if (((filesetentry_t *)node_1)->fse_index == - ((filesetentry_t *)node_2)->fse_index) - return (0); - - return (1); -} - -/* - * Obtains a filesetentry entity for a file to be placed in a - * (sub)directory of a fileset. The size of the file may be - * specified by fileset_meansize, or calculated from a gamma - * distribution of parameter fileset_sizegamma and of mean size - * fileset_meansize. The filesetentry entity is placed on the file - * list in the specified parent filesetentry entity, which may - * be a directory filesetentry, or the root filesetentry in the - * fileset. It is also placed on the fileset's list of all - * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR - * if ipc memory for the path string cannot be allocated. - */ -static int -fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) -{ - char tmpname[16]; - filesetentry_t *entry; - double drand; - uint_t index; - - if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) - == NULL) { - filebench_log(LOG_ERROR, - "fileset_populate_file: Can't malloc filesetentry"); - return (FILEBENCH_ERROR); - } - - /* Another currently idle file */ - (void) ipc_mutex_lock(&fileset->fs_pick_lock); - index = fileset->fs_idle_files++; - (void) ipc_mutex_unlock(&fileset->fs_pick_lock); - - entry->fse_index = index; - entry->fse_parent = parent; - entry->fse_fileset = fileset; - fileset_insfilelist(fileset, entry); - - (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); - if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { - filebench_log(LOG_ERROR, - "fileset_populate_file: Can't alloc path string"); - return (FILEBENCH_ERROR); - } - - /* see if random variable was supplied for file size */ - if (fileset->fs_meansize == -1) { - entry->fse_size = (off64_t)avd_get_int(fileset->fs_size); - } else { - double gamma; - - gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; - if (gamma > 0) { - drand = gamma_dist_knuth(gamma, - fileset->fs_meansize / gamma); - entry->fse_size = (off64_t)drand; - } else { - entry->fse_size = (off64_t)fileset->fs_meansize; - } - } - - fileset->fs_bytes += entry->fse_size; - - fileset->fs_realfiles++; - return (FILEBENCH_OK); -} - -/* - * Obtaines a filesetentry entity for a leaf directory to be placed in a - * (sub)directory of a fileset. The leaf directory will always be empty so - * it can be created and deleted (mkdir, rmdir) at will. The filesetentry - * entity is placed on the leaf directory list in the specified parent - * filesetentry entity, which may be a (sub) directory filesetentry, or - * the root filesetentry in the fileset. It is also placed on the fileset's - * list of all contained leaf directories. Returns FILEBENCH_OK if successful - * or FILEBENCH_ERROR if ipc memory cannot be allocated. - */ -static int -fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial) -{ - char tmpname[16]; - filesetentry_t *entry; - uint_t index; - - if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) - == NULL) { - filebench_log(LOG_ERROR, - "fileset_populate_file: Can't malloc filesetentry"); - return (FILEBENCH_ERROR); - } - - /* Another currently idle leaf directory */ - (void) ipc_mutex_lock(&fileset->fs_pick_lock); - index = fileset->fs_idle_leafdirs++; - (void) ipc_mutex_unlock(&fileset->fs_pick_lock); - - entry->fse_index = index; - entry->fse_parent = parent; - entry->fse_fileset = fileset; - fileset_insleafdirlist(fileset, entry); - - (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); - if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { - filebench_log(LOG_ERROR, - "fileset_populate_file: Can't alloc path string"); - return (FILEBENCH_ERROR); - } - - fileset->fs_realleafdirs++; - return (FILEBENCH_OK); -} - -/* - * Creates a directory node in a fileset, by obtaining a - * filesetentry entity for the node and initializing it - * according to parameters of the fileset. It determines a - * directory tree depth and directory width, optionally using - * a gamma distribution. If its calculated depth is less then - * its actual depth in the directory tree, it becomes a leaf - * node and files itself with "width" number of file type - * filesetentries, otherwise it files itself with "width" - * number of directory type filesetentries, using recursive - * calls to fileset_populate_subdir. The end result of the - * initial call to this routine is a tree of directories of - * random width and varying depth with sufficient leaf - * directories to contain all required files. - * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path - * string memory cannot be allocated and returns the error code (currently - * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive - * calls to fileset_populate_subdir. - */ -static int -fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, - int serial, double depth) -{ - double randepth, drand, ranwidth; - int isleaf = 0; - char tmpname[16]; - filesetentry_t *entry; - int i; - uint_t index; - - depth += 1; - - /* Create dir node */ - if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) - == NULL) { - filebench_log(LOG_ERROR, - "fileset_populate_subdir: Can't malloc filesetentry"); - return (FILEBENCH_ERROR); - } - - /* another idle directory */ - (void) ipc_mutex_lock(&fileset->fs_pick_lock); - index = fileset->fs_idle_dirs++; - (void) ipc_mutex_unlock(&fileset->fs_pick_lock); - - (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); - if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { - filebench_log(LOG_ERROR, - "fileset_populate_subdir: Can't alloc path string"); - return (FILEBENCH_ERROR); - } - - entry->fse_index = index; - entry->fse_parent = parent; - entry->fse_fileset = fileset; - fileset_insdirlist(fileset, entry); - - if (fileset->fs_dirdepthrv) { - randepth = (int)avd_get_int(fileset->fs_dirdepthrv); - } else { - double gamma; - - gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0; - if (gamma > 0) { - drand = gamma_dist_knuth(gamma, - fileset->fs_meandepth / gamma); - randepth = (int)drand; - } else { - randepth = (int)fileset->fs_meandepth; - } - } - - if (fileset->fs_meanwidth == -1) { - ranwidth = avd_get_dbl(fileset->fs_dirwidth); - } else { - double gamma; - - gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; - if (gamma > 0) { - drand = gamma_dist_knuth(gamma, - fileset->fs_meanwidth / gamma); - ranwidth = drand; - } else { - ranwidth = fileset->fs_meanwidth; - } - } - - if (randepth == 0) - randepth = 1; - if (ranwidth == 0) - ranwidth = 1; - if (depth >= randepth) - isleaf = 1; - - /* - * Create directory of random width filled with files according - * to distribution, or if root directory, continue until #files required - */ - for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && - (fileset->fs_realfiles < fileset->fs_constentries); - i++) { - int ret = 0; - - if (parent && isleaf) - ret = fileset_populate_file(fileset, entry, i); - else - ret = fileset_populate_subdir(fileset, entry, i, depth); - - if (ret != 0) - return (ret); - } - - /* - * Create directory of random width filled with leaf directories - * according to distribution, or if root directory, continue until - * the number of leaf directories required has been generated. - */ - for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && - (fileset->fs_realleafdirs < fileset->fs_constleafdirs); - i++) { - int ret = 0; - - if (parent && isleaf) - ret = fileset_populate_leafdir(fileset, entry, i); - else - ret = fileset_populate_subdir(fileset, entry, i, depth); - - if (ret != 0) - return (ret); - } - - return (FILEBENCH_OK); -} - -/* - * Populates a fileset with files and subdirectory entries. Uses - * the supplied fileset_dirwidth and fileset_entries (number of files) to - * calculate the required fileset_meandepth (of subdirectories) and - * initialize the fileset_meanwidth and fileset_meansize variables. Then - * calls fileset_populate_subdir() to do the recursive - * subdirectory entry creation and leaf file entry creation. All - * of the above is skipped if the fileset has already been - * populated. Returns 0 on success, or an error code from the - * call to fileset_populate_subdir if that call fails. - */ -static int -fileset_populate(fileset_t *fileset) -{ - fbint_t entries = avd_get_int(fileset->fs_entries); - fbint_t leafdirs = avd_get_int(fileset->fs_leafdirs); - int meandirwidth; - int ret; - - /* Skip if already populated */ - if (fileset->fs_bytes > 0) - goto exists; - -#ifdef HAVE_RAW_SUPPORT - /* check for raw device */ - if (fileset->fs_attrs & FILESET_IS_RAW_DEV) - return (FILEBENCH_OK); -#endif /* HAVE_RAW_SUPPORT */ - - /* - * save value of entries and leaf dirs obtained for later - * in case it was random - */ - fileset->fs_constentries = entries; - fileset->fs_constleafdirs = leafdirs; - - /* initialize idle files and directories condition variables */ - (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr()); - (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr()); - (void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr()); - - /* no files or dirs idle (or busy) yet */ - fileset->fs_idle_files = 0; - fileset->fs_idle_dirs = 0; - fileset->fs_idle_leafdirs = 0; - - /* initialize locks and other condition variables */ - (void) pthread_mutex_init(&fileset->fs_pick_lock, - ipc_mutexattr(IPC_MUTEX_NORMAL)); - (void) pthread_mutex_init(&fileset->fs_histo_lock, - ipc_mutexattr(IPC_MUTEX_NORMAL)); - (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr()); - - /* Initialize avl btrees */ - avl_create(&(fileset->fs_free_files), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - avl_create(&(fileset->fs_noex_files), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - avl_create(&(fileset->fs_exist_files), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - avl_create(&(fileset->fs_free_leaf_dirs), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - avl_create(&(fileset->fs_noex_leaf_dirs), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - avl_create(&(fileset->fs_exist_leaf_dirs), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - avl_create(&(fileset->fs_dirs), fileset_entry_compare, - sizeof (filesetentry_t), FSE_OFFSETOF(fse_link)); - - /* is dirwidth a random variable? */ - if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { - meandirwidth = - (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean; - fileset->fs_meanwidth = -1; - } else { - meandirwidth = (int)avd_get_int(fileset->fs_dirwidth); - fileset->fs_meanwidth = (double)meandirwidth; - } - - /* - * Input params are: - * # of files - * ave # of files per dir - * max size of dir - * # ave size of file - * max size of file - */ - fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth); - - /* Has a random variable been supplied for dirdepth? */ - if (fileset->fs_dirdepthrv) { - /* yes, so set the random variable's mean value to meandepth */ - fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean = - fileset->fs_meandepth; - } - - /* test for random size variable */ - if (AVD_IS_RANDOM(fileset->fs_size)) - fileset->fs_meansize = -1; - else - fileset->fs_meansize = avd_get_int(fileset->fs_size); - - if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0) - return (ret); - - -exists: - if (fileset->fs_attrs & FILESET_IS_FILE) { - filebench_log(LOG_VERBOSE, "File %s: mbytes=%llu", - avd_get_str(fileset->fs_name), - (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); - } else { - filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs " - "avg dir = %d, avg depth = %.1lf, mbytes=%llu", - avd_get_str(fileset->fs_name), entries, leafdirs, - meandirwidth, - fileset->fs_meandepth, - (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); - } - - return (FILEBENCH_OK); -} - -/* - * Allocates a fileset instance, initializes fileset_dirgamma and - * fileset_sizegamma default values, and sets the fileset name to the - * supplied name string. Puts the allocated fileset on the - * master fileset list and returns a pointer to it. - * - * This routine implements the 'define fileset' calls found in a .f - * workload, such as in the following example: - * define fileset name=drew4ever, entries=$nfiles - */ -fileset_t * -fileset_define(avd_t name) -{ - fileset_t *fileset; - - if (name == NULL) - return (NULL); - - if ((fileset = (fileset_t *)ipc_malloc(FILEBENCH_FILESET)) == NULL) { - filebench_log(LOG_ERROR, - "fileset_define: Can't malloc fileset"); - return (NULL); - } - - filebench_log(LOG_DEBUG_IMPL, - "Defining file %s", avd_get_str(name)); - - (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); - - fileset->fs_dirgamma = avd_int_alloc(1500); - fileset->fs_sizegamma = avd_int_alloc(1500); - fileset->fs_histo_id = -1; - - /* Add fileset to global list */ - if (filebench_shm->shm_filesetlist == NULL) { - filebench_shm->shm_filesetlist = fileset; - fileset->fs_next = NULL; - } else { - fileset->fs_next = filebench_shm->shm_filesetlist; - filebench_shm->shm_filesetlist = fileset; - } - - (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); - - fileset->fs_name = name; - - return (fileset); -} - -/* - * If supplied with a pointer to a fileset and the fileset's - * fileset_prealloc flag is set, calls fileset_populate() to populate - * the fileset with filesetentries, then calls fileset_create() - * to make actual directories and files for the filesetentries. - * Otherwise, it applies fileset_populate() and fileset_create() - * to all the filesets on the master fileset list. It always - * returns zero (0) if one fileset is populated / created, - * otherwise it returns the sum of returned values from - * fileset_create() and fileset_populate(), which - * will be a negative one (-1) times the number of - * fileset_create() calls which failed. - */ -int -fileset_createset(fileset_t *fileset) -{ - fileset_t *list; - int ret = 0; - - /* set up for possible parallel allocate */ - filebench_shm->shm_fsparalloc_count = 0; - (void) pthread_cond_init( - &filebench_shm->shm_fsparalloc_cv, - ipc_condattr()); - - if (fileset && avd_get_bool(fileset->fs_prealloc)) { - - /* check for raw files */ - if (fileset_checkraw(fileset)) { - filebench_log(LOG_INFO, - "file %s/%s is a RAW device", - avd_get_str(fileset->fs_path), - avd_get_str(fileset->fs_name)); - return (FILEBENCH_OK); - } - - filebench_log(LOG_INFO, - "creating/pre-allocating %s %s", - fileset_entity_name(fileset), - avd_get_str(fileset->fs_name)); - - if ((ret = fileset_populate(fileset)) != FILEBENCH_OK) - return (ret); - - if ((ret = fileset_create(fileset)) != FILEBENCH_OK) - return (ret); - } else { - - filebench_log(LOG_INFO, - "Creating/pre-allocating files and filesets"); - - list = filebench_shm->shm_filesetlist; - while (list) { - /* check for raw files */ - if (fileset_checkraw(list)) { - filebench_log(LOG_INFO, - "file %s/%s is a RAW device", - avd_get_str(list->fs_path), - avd_get_str(list->fs_name)); - list = list->fs_next; - continue; - } - - if ((ret = fileset_populate(list)) != FILEBENCH_OK) - return (ret); - - if ((ret = fileset_create(list)) != FILEBENCH_OK) - return (ret); - - list = list->fs_next; - } - } - - /* wait for allocation threads to finish */ - filebench_log(LOG_INFO, - "waiting for fileset pre-allocation to finish"); - - (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); - while (filebench_shm->shm_fsparalloc_count > 0) - (void) pthread_cond_wait( - &filebench_shm->shm_fsparalloc_cv, - &filebench_shm->shm_fsparalloc_lock); - (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); - - if (filebench_shm->shm_fsparalloc_count < 0) - return (FILEBENCH_ERROR); - - return (FILEBENCH_OK); -} - -/* - * Searches through the master fileset list for the named fileset. - * If found, returns pointer to same, otherwise returns NULL. - */ -fileset_t * -fileset_find(char *name) -{ - fileset_t *fileset = filebench_shm->shm_filesetlist; - - (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); - - while (fileset) { - if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) { - (void) ipc_mutex_unlock( - &filebench_shm->shm_fileset_lock); - return (fileset); - } - fileset = fileset->fs_next; - } - (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); - - return (NULL); -} - -/* - * Iterates over all the file sets in the filesetlist, - * executing the supplied command "*cmd()" on them. Also - * indicates to the executed command if it is the first - * time the command has been executed since the current - * call to fileset_iter. - */ -int -fileset_iter(int (*cmd)(fileset_t *fileset, int first)) -{ - fileset_t *fileset = filebench_shm->shm_filesetlist; - int count = 0; - - (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); - - while (fileset) { - if (cmd(fileset, count == 0) == FILEBENCH_ERROR) { - (void) ipc_mutex_unlock( - &filebench_shm->shm_fileset_lock); - return (FILEBENCH_ERROR); - } - fileset = fileset->fs_next; - count++; - } - - (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); - return (FILEBENCH_OK); -} - -/* - * Prints information to the filebench log about the file - * object. Also prints a header on the first call. - */ -int -fileset_print(fileset_t *fileset, int first) -{ - int pathlength; - char *fileset_path; - char *fileset_name; - static char pad[] = " "; /* 30 spaces */ - - if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { - filebench_log(LOG_ERROR, "%s path not set", - fileset_entity_name(fileset)); - return (FILEBENCH_ERROR); - } - - if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { - filebench_log(LOG_ERROR, "%s name not set", - fileset_entity_name(fileset)); - return (FILEBENCH_ERROR); - } - - pathlength = strlen(fileset_path) + strlen(fileset_name); - - if (pathlength > 29) - pathlength = 29; - - if (first) { - filebench_log(LOG_INFO, "File or Fileset name%20s%12s%10s", - "file size", - "dir width", - "entries"); - } - - if (fileset->fs_attrs & FILESET_IS_FILE) { - if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { - filebench_log(LOG_INFO, - "%s/%s%s (Raw Device)", - fileset_path, fileset_name, &pad[pathlength]); - } else { - filebench_log(LOG_INFO, - "%s/%s%s%9llu (Single File)", - fileset_path, fileset_name, &pad[pathlength], - (u_longlong_t)avd_get_int(fileset->fs_size)); - } - } else { - filebench_log(LOG_INFO, "%s/%s%s%9llu%12llu%10llu", - fileset_path, fileset_name, - &pad[pathlength], - (u_longlong_t)avd_get_int(fileset->fs_size), - (u_longlong_t)avd_get_int(fileset->fs_dirwidth), - (u_longlong_t)fileset->fs_constentries); - } - return (FILEBENCH_OK); -} - -/* - * checks to see if the path/name pair points to a raw device. If - * so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1. - * If RAW is not defined, or it is not a raw device, it clears the - * raw device flag and returns 0. - */ -int -fileset_checkraw(fileset_t *fileset) -{ - char path[MAXPATHLEN]; - struct stat64 sb; - char *pathname; - char *setname; - - fileset->fs_attrs &= (~FILESET_IS_RAW_DEV); - -#ifdef HAVE_RAW_SUPPORT - /* check for raw device */ - if ((pathname = avd_get_str(fileset->fs_path)) == NULL) - return (FILEBENCH_OK); - - if ((setname = avd_get_str(fileset->fs_name)) == NULL) - return (FILEBENCH_OK); - - (void) fb_strlcpy(path, pathname, MAXPATHLEN); - (void) fb_strlcat(path, "/", MAXPATHLEN); - (void) fb_strlcat(path, setname, MAXPATHLEN); - if ((stat64(path, &sb) == 0) && - ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { - fileset->fs_attrs |= FILESET_IS_RAW_DEV; - if (!(fileset->fs_attrs & FILESET_IS_FILE)) { - filebench_log(LOG_ERROR, - "WARNING Fileset %s/%s Cannot be RAW device", - avd_get_str(fileset->fs_path), - avd_get_str(fileset->fs_name)); - filebench_shutdown(1); - } - - return (1); - } -#endif /* HAVE_RAW_SUPPORT */ - - return (FILEBENCH_OK); -} |