/* * Allocates a var (var_t) from interprocess shared memory. * Places the allocated var on the end of the globally shared * var_dyn_list. Finally, the routine allocates a string * containing a copy of the supplied "name" string. If any * allocations fails, returns NULL, otherwise it returns a * pointer to the newly allocated var. */ static var_t * var_alloc_dynamic(char *name) { var_t *var = NULL; var_t *prev = NULL; var_t *newvar; if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) { filebench_log(LOG_ERROR, "Out of memory for variables"); return (NULL); } (void) memset(newvar, 0, sizeof (newvar)); for (var = filebench_shm->var_dyn_list; var != NULL; var = var->var_next) prev = var; /* Find end of list */ if (prev != NULL) prev->var_next = newvar; else filebench_shm->var_dyn_list = newvar; if ((newvar->var_name = ipc_stralloc(name)) == NULL) { filebench_log(LOG_ERROR, "Out of memory for variables"); return (NULL); } return (newvar); }
/* * Allocates a var_integer_t from ipc memory space and * pre-loads it with the vinteger_t "integer". Returns * the var_integer_t on success, NULL on failure. */ var_integer_t integer_alloc(vinteger_t integer) { var_integer_t rtn; if ((rtn = (vinteger_t *)ipc_malloc(FILEBENCH_INTEGER)) == NULL) { filebench_log(LOG_ERROR, "Alloc integer failed"); return (NULL); } *rtn = integer; filebench_log(LOG_DEBUG_IMPL, "Alloc integer %lld", integer); return (rtn); }
/* * Define a random entity which will contain the parameters of a random * distribution. */ randdist_t * randdist_alloc(void) { randdist_t *rndp; if ((rndp = (randdist_t *)ipc_malloc(FILEBENCH_RANDDIST)) == NULL) { filebench_log(LOG_ERROR, "Out of memory for random dist"); return (NULL); } /* place on global list */ rndp->rnd_next = filebench_shm->shm_rand_list; filebench_shm->shm_rand_list = rndp; return (rndp); }
/* * Allocate space for a new custom variable in the shared memory location. */ cvar_t * cvar_alloc(void) { cvar_t *cvar; if ((cvar = (cvar_t *)ipc_malloc(FILEBENCH_CVAR)) == NULL) { filebench_log(LOG_ERROR, "Out of memory for custom variable"); return (NULL); } /* place on the head of the global list */ cvar->next = filebench_shm->shm_cvar_list; filebench_shm->shm_cvar_list = cvar; return (cvar); }
/* * Allocates a string pointer in interprocess shared memory, * then allocates and initializes a piece of shared string memory, * putting the pointer to it into the just allocated string * pointer location. The routine returns a pointer to the * string pointer location or returns NULL on error. */ var_string_t string_alloc(char *string) { char **rtn; if ((rtn = (char **)ipc_malloc(FILEBENCH_STRING)) == NULL) { filebench_log(LOG_ERROR, "Alloc string failed"); return (NULL); } *rtn = ipc_stralloc(string); filebench_log(LOG_DEBUG_IMPL, "Alloc string %s ptr %zx", string, rtn); return (rtn); }
/* * Obtaines 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 fs_meansize, or calculated from a gamma * distribution of parameter fs_sizegamma and of mean size * fs_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 0 if successful or -1 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; double gamma; if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't malloc filesetentry"); return (-1); } (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); entry->fse_parent = parent; entry->fse_fileset = fileset; entry->fse_flags |= FSE_FREE; 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 (-1); } gamma = *(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 (0); }
/* * Create an in-memory thread object linked to a parent procflow. * A threadflow entity is allocated from shared memory and * initialized from the "inherit" threadflow if supplied, * otherwise to zeros. The threadflow is assigned a unique * thread id, the supplied instance number, the supplied name * and added to the procflow's pf_thread list. If no name is * supplied or the threadflow can't be allocated, NULL is * returned Otherwise a pointer to the newly allocated threadflow * is returned. * * The filebench_shm->shm_threadflow_lock must be held by the caller. */ static threadflow_t * threadflow_define_common(procflow_t *procflow, char *name, threadflow_t *inherit, int instance) { threadflow_t *threadflow; threadflow_t **threadlistp = &procflow->pf_threads; if (name == NULL) return (NULL); threadflow = (threadflow_t *)ipc_malloc(FILEBENCH_THREADFLOW); if (threadflow == NULL) return (NULL); if (inherit) (void) memcpy(threadflow, inherit, sizeof (threadflow_t)); else (void) memset(threadflow, 0, sizeof (threadflow_t)); threadflow->tf_utid = ++filebench_shm->shm_utid; threadflow->tf_instance = instance; (void) strcpy(threadflow->tf_name, name); threadflow->tf_process = procflow; (void) pthread_mutex_init(&threadflow->tf_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d", name, instance); /* Add threadflow to list */ if (*threadlistp == NULL) { *threadlistp = threadflow; threadflow->tf_next = NULL; } else { threadflow->tf_next = *threadlistp; *threadlistp = threadflow; } return (threadflow); }
/* * Return 0 on success and a non zero error code on failure. */ static int alloc_cvar_lib_info(const char *filename) { int ret = -1; cvar_library_info_t *cli = NULL; cvar_library_info_t *t; cli = (cvar_library_info_t *) ipc_malloc(FILEBENCH_CVAR_LIB_INFO); if (!cli) goto out; cli->filename = ipc_stralloc(filename); if (!cli->filename) goto out; cli->type = ipc_stralloc(gettype(filename)); if (!cli->type) goto out; cli->next = NULL; if (filebench_shm->shm_cvar_lib_info_list) { for (t = filebench_shm->shm_cvar_lib_info_list; t->next != NULL; t = t->next); /* Seek to the last entry. */ cli->index = t->index + 1; t->next = cli; } else { cli->index = 0; filebench_shm->shm_cvar_lib_info_list = cli; } ret = 0; out: if (ret && cli) { /* NOTE: There is no mechanism to free cli->filename and cli->type. */ ipc_free(FILEBENCH_CVAR_LIB_INFO, (char *) cli); } return ret; }
/* * Allocates a fileset instance, initializes fs_dirgamma and * fs_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. */ fileset_t * fileset_define(char *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", name); (void) ipc_mutex_lock(&filebench_shm->fileset_lock); fileset->fs_dirgamma = integer_alloc(1500); fileset->fs_sizegamma = integer_alloc(1500); /* Add fileset to global list */ if (filebench_shm->filesetlist == NULL) { filebench_shm->filesetlist = fileset; fileset->fs_next = NULL; } else { fileset->fs_next = filebench_shm->filesetlist; filebench_shm->filesetlist = fileset; } (void) ipc_mutex_unlock(&filebench_shm->fileset_lock); (void) strcpy(fileset->fs_name, name); return (fileset); }
/* * Allocates a flowop entity and initializes it with inherited * contents from the "inherit" flowop, if it is supplied, or * with zeros otherwise. In either case the fo_next and fo_exec_next * pointers are set to NULL, and fo_thread is set to point to * the owning threadflow. The initialized flowop is placed at * the head of the global flowop list, and also placed on the * tail of the supplied local flowop list, which will either * be a threadflow's tf_thrd_fops list or a composite flowop's * fo_comp_fops list. The routine locks the flowop's fo_lock and * leaves it held on return. If successful, it returns a pointer * to the allocated and initialized flowop, otherwise it returns NULL. * * filebench_shm->shm_flowop_lock must be held by caller. */ static flowop_t * flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit, flowop_t **flowoplist_hdp, int instance, int type) { flowop_t *flowop; if (name == NULL) return (NULL); if ((flowop = (flowop_t *)ipc_malloc(FILEBENCH_FLOWOP)) == NULL) { filebench_log(LOG_ERROR, "flowop_define: Can't malloc flowop"); return (NULL); } filebench_log(LOG_DEBUG_IMPL, "defining flowops %s-%d, addr %zx", name, instance, flowop); if (flowop == NULL) return (NULL); if (inherit) { (void) memcpy(flowop, inherit, sizeof (flowop_t)); (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) ipc_mutex_lock(&flowop->fo_lock); flowop->fo_next = NULL; flowop->fo_exec_next = NULL; filebench_log(LOG_DEBUG_IMPL, "flowop %s-%d calling init", name, instance); } else { (void) memset(flowop, 0, sizeof (flowop_t)); flowop->fo_iters = avd_int_alloc(1); flowop->fo_type = type; (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) ipc_mutex_lock(&flowop->fo_lock); } /* Create backpointer to thread */ flowop->fo_thread = threadflow; /* Add flowop to global list */ if (filebench_shm->shm_flowoplist == NULL) { filebench_shm->shm_flowoplist = flowop; flowop->fo_next = NULL; } else { flowop->fo_next = filebench_shm->shm_flowoplist; filebench_shm->shm_flowoplist = flowop; } (void) strcpy(flowop->fo_name, name); flowop->fo_instance = instance; if (flowoplist_hdp == NULL) return (flowop); /* Add flowop to thread op list */ if (*flowoplist_hdp == NULL) { *flowoplist_hdp = flowop; flowop->fo_exec_next = NULL; } else { flowop_t *flowend; /* Find the end of the thread list */ flowend = *flowoplist_hdp; while (flowend->fo_exec_next != NULL) flowend = flowend->fo_exec_next; flowend->fo_exec_next = flowop; flowop->fo_exec_next = NULL; } return (flowop); }
/* * 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 0 on success. Returns -1 if ipc path string memory * cannot be allocated and returns an error code (currently * also -1) 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, gamma; int isleaf = 0; char tmpname[16]; filesetentry_t *entry; int i; 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 (-1); } (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); (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 (-1); } entry->fse_parent = parent; entry->fse_flags |= FSE_DIR | FSE_FREE; fileset_insdirlist(fileset, entry); gamma = *(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; } gamma = *(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 according to distribution, or * if root directory, continue until #files required */ for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && (fileset->fs_realfiles < *(fileset->fs_entries)); 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); } return (0); }
/* * Obtaines 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 fs_meansize, or calculated from a gamma * distribution of parameter fs_sizegamma and of mean size * fs_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 0 if successful or -1 if ipc memory * for the path string cannot be allocated, or if a RAW device * cannot be located. */ static int fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, char *path, int serial) { char tmpname[16]; filesetentry_t *entry; double drand; double gamma; struct stat64 sb; int fd; if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't malloc filesetentry"); return (-1); } (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); entry->fse_parent = parent; entry->fse_fileset = fileset; entry->fse_flags |= FSE_FREE; /* RAW File name */ if (path) { /* check for raw device */ fd = open(path, O_RDONLY); if ((fstat64(fd, &sb) == 0) && ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { entry->fse_size = lseek64(fd, 0, SEEK_END); close(fd); fileset->fs_attrs |= FILESET_IS_RAW_DEV; filebench_log(LOG_INFO, "RAW device for %s on %s size %lld", fileset->fs_name, path, entry->fse_size); } else { filebench_log(LOG_ERROR, "fileset_populate_file: Cannot open RAW device %s", path); close(fd); return (-1); } entry->fse_flags &= FSE_FREE; entry->fse_flags |= FSE_EXISTS; if ((entry->fse_path = (char *)ipc_pathalloc(path)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't alloc path string"); return (-1); } } else { (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); gamma = *(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; } if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't alloc path string"); return (-1); } } fileset_insfilelist(fileset, entry); fileset->fs_bytes += entry->fse_size; fileset->fs_realfiles++; return (0); }
struct posset * posset_alloc(avd_t name, avd_t type, avd_t seed, avd_t max, avd_t entries) { struct posset *ps; int ret; ps = (struct posset *)ipc_malloc(FILEBENCH_POSSET); if (!ps) { filebench_log(LOG_ERROR, "posset_alloc: " "can't malloc posset in IPC region"); return NULL; } /* we do not support any possets except "rnd" at the moment */ if (!strcmp(avd_get_str(type), "rnd")) { ps->ps_type = avd_int_alloc(POSSET_TYPE_RND); } else if (!strcmp(avd_get_str(type), "collection")) { ps->ps_type = avd_int_alloc(POSSET_TYPE_COLLECTION); } else { filebench_log(LOG_ERROR, "posset_alloc: wrong posset type"); ipc_free(FILEBENCH_POSSET, (char *)ps); return NULL; } ps->ps_name = name; ps->ps_rnd_seed = seed; ps->ps_rnd_max = max; ps->ps_entries = entries; if (avd_get_int(ps->ps_entries) > POSSET_MAX_ENTRIES) { filebench_log(LOG_ERROR, "posset_alloc: the number of posset " "entries is too high"); ipc_free(FILEBENCH_POSSET, (char *)ps); return NULL; } /* depending on the posset type generate (or load) positions */ switch (avd_get_int(ps->ps_type)) { case(POSSET_TYPE_RND): ret = posset_rnd_fill(ps); break; case(POSSET_TYPE_COLLECTION): ret = posset_collection_fill(ps); break; default: filebench_log(LOG_ERROR, "posset_alloc: wrong posset type"); ipc_free(FILEBENCH_POSSET, (char *)ps); return NULL; } if (ret < 0) { filebench_log(LOG_ERROR, "posset_alloc: could not fill posset"); ipc_free(FILEBENCH_POSSET, (char *)ps); return NULL; } /* add posset to the global list */ (void)ipc_mutex_lock(&filebench_shm->shm_posset_lock); if (filebench_shm->shm_possetlist == NULL) { filebench_shm->shm_possetlist = ps; ps->ps_next = NULL; } else { ps->ps_next = filebench_shm->shm_possetlist; filebench_shm->shm_possetlist = ps; } (void)ipc_mutex_unlock(&filebench_shm->shm_posset_lock); return ps; }