diff options
Diffstat (limited to 'zfs/lib/libumem/envvar.c')
-rw-r--r-- | zfs/lib/libumem/envvar.c | 746 |
1 files changed, 0 insertions, 746 deletions
diff --git a/zfs/lib/libumem/envvar.c b/zfs/lib/libumem/envvar.c deleted file mode 100644 index 949d33ce1..000000000 --- a/zfs/lib/libumem/envvar.c +++ /dev/null @@ -1,746 +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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> -#include <dlfcn.h> -#include "umem_base.h" -#include "vmem_base.h" - -/* - * A umem environment variable, like UMEM_DEBUG, is set to a series - * of items, seperated by ',': - * - * UMEM_DEBUG="audit=10,guards,firewall=512" - * - * This structure describes items. Each item has a name, type, and - * description. During processing, an item read from the user may - * be either "valid" or "invalid". - * - * A valid item has an argument, if required, and it is of the right - * form (doesn't overflow, doesn't contain any unexpected characters). - * - * If the item is valid, item_flag_target != NULL, and: - * type is not CLEARFLAG, then (*item_flag_target) |= item_flag_value - * type is CLEARFLAG, then (*item_flag_target) &= ~item_flag_value - */ - -#define UMEM_ENV_ITEM_MAX 512 - -struct umem_env_item; - -typedef int arg_process_t(const struct umem_env_item *item, const char *value); -#define ARG_SUCCESS 0 /* processing successful */ -#define ARG_BAD 1 /* argument had a bad value */ - -typedef struct umem_env_item { - const char *item_name; /* tag in environment variable */ - const char *item_interface_stability; - enum { - ITEM_INVALID, - ITEM_FLAG, /* only a flag. No argument allowed */ - ITEM_CLEARFLAG, /* only a flag, but clear instead of set */ - ITEM_OPTUINT, /* optional integer argument */ - ITEM_UINT, /* required integer argument */ - ITEM_OPTSIZE, /* optional size_t argument */ - ITEM_SIZE, /* required size_t argument */ - ITEM_SPECIAL /* special argument processing */ - } item_type; - const char *item_description; - uint_t *item_flag_target; /* the variable containing the flag */ - uint_t item_flag_value; /* the value to OR in */ - uint_t *item_uint_target; /* the variable to hold the integer */ - size_t *item_size_target; - arg_process_t *item_special; /* callback for special handling */ -} umem_env_item_t; - -#ifndef UMEM_STANDALONE -static arg_process_t umem_backend_process; -#endif - -static arg_process_t umem_log_process; - -static size_t umem_size_tempval; -static arg_process_t umem_size_process; - -const char *____umem_environ_msg_options = "-- UMEM_OPTIONS --"; - -static umem_env_item_t umem_options_items[] = { -#ifndef UMEM_STANDALONE - { "backend", "Evolving", ITEM_SPECIAL, - "=sbrk for sbrk(2), =mmap for mmap(2)", - NULL, 0, NULL, NULL, - &umem_backend_process - }, -#endif - - { "concurrency", "Private", ITEM_UINT, - "Max concurrency", - NULL, 0, &umem_max_ncpus - }, - { "max_contention", "Private", ITEM_UINT, - "Maximum contention in a reap interval before the depot is " - "resized.", - NULL, 0, &umem_depot_contention - }, - { "nomagazines", "Private", ITEM_FLAG, - "no caches will be multithreaded, and no caching will occur.", - &umem_flags, UMF_NOMAGAZINE - }, - { "reap_interval", "Private", ITEM_UINT, - "Minimum time between reaps and updates, in seconds.", - NULL, 0, &umem_reap_interval - }, - - { "size_add", "Private", ITEM_SPECIAL, - "add a size to the cache size table", - NULL, 0, NULL, - &umem_size_tempval, &umem_size_process - }, - { "size_clear", "Private", ITEM_SPECIAL, - "clear all but the largest size from the cache size table", - NULL, 0, NULL, - &umem_size_tempval, &umem_size_process - }, - { "size_remove", "Private", ITEM_SPECIAL, - "remove a size from the cache size table", - NULL, 0, NULL, - &umem_size_tempval, &umem_size_process - }, - -#ifndef UMEM_STANDALONE - { "sbrk_minalloc", "Private", ITEM_SIZE, - "The minimum allocation chunk for the sbrk(2) heap.", - NULL, 0, NULL, &vmem_sbrk_minalloc - }, - { "sbrk_pagesize", "Private", ITEM_SIZE, - "The preferred page size for the sbrk(2) heap.", - NULL, 0, NULL, &vmem_sbrk_pagesize - }, -#endif - - { NULL, "-- end of UMEM_OPTIONS --", ITEM_INVALID } -}; - -const char *____umem_environ_msg_debug = "-- UMEM_DEBUG --"; - -static umem_env_item_t umem_debug_items[] = { - { "default", "Unstable", ITEM_FLAG, - "audit,contents,guards", - &umem_flags, - UMF_AUDIT | UMF_CONTENTS | UMF_DEADBEEF | UMF_REDZONE - }, - { "audit", "Unstable", ITEM_OPTUINT, - "Enable auditing. optionally =frames to set the number of " - "stored stack frames", - &umem_flags, UMF_AUDIT, &umem_stack_depth - }, - { "contents", "Unstable", ITEM_OPTSIZE, - "Enable contents storing. UMEM_LOGGING=contents also " - "required. optionally =bytes to set the number of stored " - "bytes", - &umem_flags, UMF_CONTENTS, NULL, &umem_content_maxsave - }, - { "guards", "Unstable", ITEM_FLAG, - "Enables guards and special patterns", - &umem_flags, UMF_DEADBEEF | UMF_REDZONE - }, - { "verbose", "Unstable", ITEM_FLAG, - "Enables writing error messages to stderr", - &umem_output, 1 - }, - - { "nosignal", "Private", ITEM_FLAG, - "Abort if called from a signal handler. Turns on 'audit'. " - "Note that this is not always a bug.", - &umem_flags, UMF_AUDIT | UMF_CHECKSIGNAL - }, - { "firewall", "Private", ITEM_SIZE, - "=minbytes. Every object >= minbytes in size will have its " - "end against an unmapped page", - &umem_flags, UMF_FIREWALL, NULL, &umem_minfirewall - }, - { "lite", "Private", ITEM_FLAG, - "debugging-lite", - &umem_flags, UMF_LITE - }, - { "maxverify", "Private", ITEM_SIZE, - "=maxbytes, Maximum bytes to check when 'guards' is active. " - "Normally all bytes are checked.", - NULL, 0, NULL, &umem_maxverify - }, - { "noabort", "Private", ITEM_CLEARFLAG, - "umem will not abort when a recoverable error occurs " - "(i.e. double frees, certain kinds of corruption)", - &umem_abort, 1 - }, - { "mtbf", "Private", ITEM_UINT, - "=mtbf, the mean time between injected failures. Works best " - "if prime.\n", - NULL, 0, &umem_mtbf - }, - { "random", "Private", ITEM_FLAG, - "randomize flags on a per-cache basis", - &umem_flags, UMF_RANDOMIZE - }, - { "allverbose", "Private", ITEM_FLAG, - "Enables writing all logged messages to stderr", - &umem_output, 2 - }, - - { NULL, "-- end of UMEM_DEBUG --", ITEM_INVALID } -}; - -const char *____umem_environ_msg_logging = "-- UMEM_LOGGING --"; - -static umem_env_item_t umem_logging_items[] = { - { "transaction", "Unstable", ITEM_SPECIAL, - "If 'audit' is set in UMEM_DEBUG, the audit structures " - "from previous transactions are entered into this log.", - NULL, 0, NULL, - &umem_transaction_log_size, &umem_log_process - }, - { "contents", "Unstable", ITEM_SPECIAL, - "If 'audit' is set in UMEM_DEBUG, the contents of objects " - "are recorded in this log as they are freed. If the " - "'contents' option is not set in UMEM_DEBUG, the first " - "256 bytes of each freed buffer will be saved.", - &umem_flags, UMF_CONTENTS, NULL, - &umem_content_log_size, &umem_log_process - }, - { "fail", "Unstable", ITEM_SPECIAL, - "Records are entered into this log for every failed " - "allocation.", - NULL, 0, NULL, - &umem_failure_log_size, &umem_log_process - }, - - { "slab", "Private", ITEM_SPECIAL, - "Every slab created will be entered into this log.", - NULL, 0, NULL, - &umem_slab_log_size, &umem_log_process - }, - - { NULL, "-- end of UMEM_LOGGING --", ITEM_INVALID } -}; - -typedef struct umem_envvar { - const char *env_name; - const char *env_func; - umem_env_item_t *env_item_list; - const char *env_getenv_result; - const char *env_func_result; -} umem_envvar_t; - -static umem_envvar_t umem_envvars[] = { - { "UMEM_DEBUG", "_umem_debug_init", umem_debug_items }, - { "UMEM_OPTIONS", "_umem_options_init", umem_options_items }, - { "UMEM_LOGGING", "_umem_logging_init", umem_logging_items }, - { NULL, NULL, NULL } -}; - -static umem_envvar_t *env_current; -#define CURRENT (env_current->env_name) - -static int -empty(const char *str) -{ - char c; - - while ((c = *str) != '\0' && isspace(c)) - str++; - - return (*str == '\0'); -} - -static int -item_uint_process(const umem_env_item_t *item, const char *item_arg) -{ - ulong_t result; - char *endptr = ""; - int olderrno; - - olderrno = errno; - errno = 0; - - if (empty(item_arg)) { - goto badnumber; - } - - result = strtoul(item_arg, &endptr, 10); - - if (result == ULONG_MAX && errno == ERANGE) { - errno = olderrno; - goto overflow; - } - errno = olderrno; - - if (*endptr != '\0') - goto badnumber; - if ((uint_t)result != result) - goto overflow; - - (*item->item_uint_target) = (uint_t)result; - return (ARG_SUCCESS); - -badnumber: - log_message("%s: %s: not a number\n", CURRENT, item->item_name); - return (ARG_BAD); - -overflow: - log_message("%s: %s: overflowed\n", CURRENT, item->item_name); - return (ARG_BAD); -} - -static int -item_size_process(const umem_env_item_t *item, const char *item_arg) -{ - ulong_t result; - ulong_t result_arg; - char *endptr = ""; - int olderrno; - - if (empty(item_arg)) - goto badnumber; - - olderrno = errno; - errno = 0; - - result_arg = strtoul(item_arg, &endptr, 10); - - if (result_arg == ULONG_MAX && errno == ERANGE) { - errno = olderrno; - goto overflow; - } - errno = olderrno; - - result = result_arg; - - switch (*endptr) { - case 't': - case 'T': - result *= 1024; - if (result < result_arg) - goto overflow; - /*FALLTHRU*/ - case 'g': - case 'G': - result *= 1024; - if (result < result_arg) - goto overflow; - /*FALLTHRU*/ - case 'm': - case 'M': - result *= 1024; - if (result < result_arg) - goto overflow; - /*FALLTHRU*/ - case 'k': - case 'K': - result *= 1024; - if (result < result_arg) - goto overflow; - endptr++; /* skip over the size character */ - break; - default: - break; /* handled later */ - } - - if (*endptr != '\0') - goto badnumber; - - (*item->item_size_target) = result; - return (ARG_SUCCESS); - -badnumber: - log_message("%s: %s: not a number\n", CURRENT, item->item_name); - return (ARG_BAD); - -overflow: - log_message("%s: %s: overflowed\n", CURRENT, item->item_name); - return (ARG_BAD); -} - -static int -umem_log_process(const umem_env_item_t *item, const char *item_arg) -{ - if (item_arg != NULL) { - int ret; - ret = item_size_process(item, item_arg); - if (ret != ARG_SUCCESS) - return (ret); - - if (*item->item_size_target == 0) - return (ARG_SUCCESS); - } else - *item->item_size_target = 64*1024; - - umem_logging = 1; - return (ARG_SUCCESS); -} - -static int -umem_size_process(const umem_env_item_t *item, const char *item_arg) -{ - const char *name = item->item_name; - void (*action_func)(size_t); - - size_t result; - - int ret; - - if (strcmp(name, "size_clear") == 0) { - if (item_arg != NULL) { - log_message("%s: %s: does not take a value. ignored\n", - CURRENT, name); - return (ARG_BAD); - } - umem_alloc_sizes_clear(); - return (ARG_SUCCESS); - } else if (strcmp(name, "size_add") == 0) { - action_func = umem_alloc_sizes_add; - } else if (strcmp(name, "size_remove") == 0) { - action_func = umem_alloc_sizes_remove; - } else { - log_message("%s: %s: internally unrecognized\n", - CURRENT, name, name, name); - return (ARG_BAD); - } - - if (item_arg == NULL) { - log_message("%s: %s: requires a value. ignored\n", - CURRENT, name); - return (ARG_BAD); - } - - ret = item_size_process(item, item_arg); - if (ret != ARG_SUCCESS) - return (ret); - - result = *item->item_size_target; - action_func(result); - return (ARG_SUCCESS); -} - -#ifndef UMEM_STANDALONE -static int -umem_backend_process(const umem_env_item_t *item, const char *item_arg) -{ - const char *name = item->item_name; - - if (item_arg == NULL) - goto fail; - - if (strcmp(item_arg, "sbrk") == 0) - vmem_backend |= VMEM_BACKEND_SBRK; - else if (strcmp(item_arg, "mmap") == 0) - vmem_backend |= VMEM_BACKEND_MMAP; - else - goto fail; - - return (ARG_SUCCESS); - -fail: - log_message("%s: %s: must be %s=sbrk or %s=mmap\n", - CURRENT, name, name, name); - return (ARG_BAD); -} -#endif - -static int -process_item(const umem_env_item_t *item, const char *item_arg) -{ - int arg_required = 0; - arg_process_t *processor; - - switch (item->item_type) { - case ITEM_FLAG: - case ITEM_CLEARFLAG: - case ITEM_OPTUINT: - case ITEM_OPTSIZE: - case ITEM_SPECIAL: - arg_required = 0; - break; - - case ITEM_UINT: - case ITEM_SIZE: - arg_required = 1; - break; - } - - switch (item->item_type) { - case ITEM_FLAG: - case ITEM_CLEARFLAG: - if (item_arg != NULL) { - log_message("%s: %s: does not take a value. ignored\n", - CURRENT, item->item_name); - return (1); - } - processor = NULL; - break; - - case ITEM_UINT: - case ITEM_OPTUINT: - processor = item_uint_process; - break; - - case ITEM_SIZE: - case ITEM_OPTSIZE: - processor = item_size_process; - break; - - case ITEM_SPECIAL: - processor = item->item_special; - break; - - default: - log_message("%s: %s: Invalid type. Ignored\n", - CURRENT, item->item_name); - return (1); - } - - if (arg_required && item_arg == NULL) { - log_message("%s: %s: Required value missing\n", - CURRENT, item->item_name); - goto invalid; - } - - if (item_arg != NULL || item->item_type == ITEM_SPECIAL) { - if (processor(item, item_arg) != ARG_SUCCESS) - goto invalid; - } - - if (item->item_flag_target) { - if (item->item_type == ITEM_CLEARFLAG) - (*item->item_flag_target) &= ~item->item_flag_value; - else - (*item->item_flag_target) |= item->item_flag_value; - } - return (0); - -invalid: - return (1); -} - -#define ENV_SHORT_BYTES 10 /* bytes to print on error */ -void -umem_process_value(umem_env_item_t *item_list, const char *beg, const char *end) -{ - char buf[UMEM_ENV_ITEM_MAX]; - char *argptr; - - size_t count; - - while (beg < end && isspace(*beg)) - beg++; - - while (beg < end && isspace(*(end - 1))) - end--; - - if (beg >= end) { - log_message("%s: empty option\n", CURRENT); - return; - } - - count = end - beg; - - if (count + 1 > sizeof (buf)) { - char outbuf[ENV_SHORT_BYTES + 1]; - /* - * Have to do this, since sprintf("%10s",...) calls malloc() - */ - (void) strncpy(outbuf, beg, ENV_SHORT_BYTES); - outbuf[ENV_SHORT_BYTES] = 0; - - log_message("%s: argument \"%s...\" too long\n", CURRENT, - outbuf); - return; - } - - (void) strncpy(buf, beg, count); - buf[count] = 0; - - argptr = strchr(buf, '='); - - if (argptr != NULL) - *argptr++ = 0; - - for (; item_list->item_name != NULL; item_list++) { - if (strcmp(buf, item_list->item_name) == 0) { - (void) process_item(item_list, argptr); - return; - } - } - log_message("%s: '%s' not recognized\n", CURRENT, buf); -} - -/*ARGSUSED*/ -void -umem_setup_envvars(int invalid) -{ - umem_envvar_t *cur_env; - static volatile enum { - STATE_START, - STATE_GETENV, - STATE_DLOPEN, - STATE_DLSYM, - STATE_FUNC, - STATE_DONE - } state = STATE_START; -#ifndef UMEM_STANDALONE - void *h; -#endif - - if (invalid) { - const char *where; - /* - * One of the calls below invoked malloc() recursively. We - * remove any partial results and return. - */ - - switch (state) { - case STATE_START: - where = "before getenv(3C) calls -- " - "getenv(3C) results ignored."; - break; - case STATE_GETENV: - where = "during getenv(3C) calls -- " - "getenv(3C) results ignored."; - break; - case STATE_DLOPEN: - where = "during dlopen(3C) call -- " - "_umem_*() results ignored."; - break; - case STATE_DLSYM: - where = "during dlsym(3C) call -- " - "_umem_*() results ignored."; - break; - case STATE_FUNC: - where = "during _umem_*() call -- " - "_umem_*() results ignored."; - break; - case STATE_DONE: - where = "after dlsym() or _umem_*() calls."; - break; - default: - where = "at unknown point -- " - "_umem_*() results ignored."; - break; - } - - log_message("recursive allocation %s\n", where); - - for (cur_env = umem_envvars; cur_env->env_name != NULL; - cur_env++) { - if (state == STATE_GETENV) - cur_env->env_getenv_result = NULL; - if (state != STATE_DONE) - cur_env->env_func_result = NULL; - } - - state = STATE_DONE; - return; - } - - state = STATE_GETENV; - - for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) { - cur_env->env_getenv_result = getenv(cur_env->env_name); - if (state == STATE_DONE) - return; /* recursed */ - } - -#ifndef UMEM_STANDALONE - state = STATE_DLOPEN; - - /* get a handle to the "a.out" object */ - if ((h = dlopen(0, RTLD_FIRST | RTLD_LAZY)) != NULL) { - for (cur_env = umem_envvars; cur_env->env_name != NULL; - cur_env++) { - const char *(*func)(void); - const char *value; - - state = STATE_DLSYM; - func = (const char *(*)(void))dlsym(h, - cur_env->env_func); - - if (state == STATE_DONE) - break; /* recursed */ - - state = STATE_FUNC; - if (func != NULL) { - value = func(); - if (state == STATE_DONE) - break; /* recursed */ - cur_env->env_func_result = value; - } - } - (void) dlclose(h); - } else { - (void) dlerror(); /* snarf dlerror() */ - } -#endif /* UMEM_STANDALONE */ - - state = STATE_DONE; -} - -/* - * Process the environment variables. - */ -void -umem_process_envvars(void) -{ - const char *value; - const char *end, *next; - umem_envvar_t *cur_env; - - for (cur_env = umem_envvars; cur_env->env_name != NULL; cur_env++) { - env_current = cur_env; - - value = cur_env->env_getenv_result; - if (value == NULL) - value = cur_env->env_func_result; - - /* ignore if missing or empty */ - if (value == NULL) - continue; - - for (end = value; *end != '\0'; value = next) { - end = strchr(value, ','); - if (end != NULL) - next = end + 1; /* skip the comma */ - else - next = end = value + strlen(value); - - umem_process_value(cur_env->env_item_list, value, end); - } - } -} |