diff options
author | Brian Behlendorf <[email protected]> | 2008-12-03 12:09:06 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2008-12-03 12:09:06 -0800 |
commit | b128c09fbee863d15be744a2ce602b514eddbe3a (patch) | |
tree | e7b220dec77fb17703f5b45f164370e30f52e7c2 /zfs/lib/libumem | |
parent | b6097ae55adc8edb7149c4d433fa45a6ea3c45e7 (diff) |
Rebase to OpenSolaris b103, in the process we are removing any code which did not originate from the OpenSolaris source. These changes will be reintroduced in topic branches for easier tracking
Diffstat (limited to 'zfs/lib/libumem')
28 files changed, 1305 insertions, 1020 deletions
diff --git a/zfs/lib/libumem/config.h b/zfs/lib/libumem/config.h deleted file mode 100644 index 9994cd102..000000000 --- a/zfs/lib/libumem/config.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#define UMEM_PTHREAD_MUTEX_TOO_BIG 1 - -#define HAVE_SYS_TIME_H 1 -#define HAVE_DLFCN_H 1 -#define HAVE_UNISTD_H 1 -#define HAVE_SYS_MMAN_H 1 -#define HAVE_SYS_SYSMACROS_H 1 -#define HAVE_STRINGS_H 1 - -#endif diff --git a/zfs/lib/libumem/envvar.c b/zfs/lib/libumem/envvar.c index 7452de7c5..949d33ce1 100644 --- a/zfs/lib/libumem/envvar.c +++ b/zfs/lib/libumem/envvar.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,26 +18,20 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)envvar.c 1.5 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" #include <ctype.h> #include <errno.h> #include <limits.h> #include <stdlib.h> #include <string.h> -#if HAVE_DLFCN_H #include <dlfcn.h> -#endif - #include "umem_base.h" #include "vmem_base.h" @@ -95,6 +88,9 @@ static arg_process_t umem_backend_process; 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[] = { @@ -124,14 +120,32 @@ static umem_env_item_t umem_options_items[] = { NULL, 0, &umem_reap_interval }, -#ifndef _WIN32 + { "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 -#endif { NULL, "-- end of UMEM_OPTIONS --", ITEM_INVALID } }; @@ -393,6 +407,49 @@ umem_log_process(const umem_env_item_t *item, const char *item_arg) 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) @@ -437,11 +494,6 @@ process_item(const umem_env_item_t *item, const char *item_arg) case ITEM_SIZE: arg_required = 1; break; - - default: - log_message("%s: %s: Invalid type. Ignored\n", - CURRENT, item->item_name); - return (1); } switch (item->item_type) { @@ -558,6 +610,7 @@ umem_setup_envvars(int invalid) static volatile enum { STATE_START, STATE_GETENV, + STATE_DLOPEN, STATE_DLSYM, STATE_FUNC, STATE_DONE @@ -582,6 +635,10 @@ umem_setup_envvars(int invalid) 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."; @@ -622,12 +679,8 @@ umem_setup_envvars(int invalid) } #ifndef UMEM_STANDALONE -#ifdef _WIN32 -# define dlopen(a, b) GetModuleHandle(NULL) -# define dlsym(a, b) GetProcAddress((HANDLE)a, b) -# define dlclose(a) 0 -# define dlerror() 0 -#endif + 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; diff --git a/zfs/lib/libumem/getpcstack.c b/zfs/lib/libumem/getpcstack.c index dffcc8591..8c3a47e19 100644 --- a/zfs/lib/libumem/getpcstack.c +++ b/zfs/lib/libumem/getpcstack.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,39 +18,21 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)getpcstack.c 1.5 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" #include "misc.h" - -#if HAVE_UCONTEXT_H #include <ucontext.h> -#endif - -#if HAVE_SYS_FRAME_H #include <sys/frame.h> -#endif -#if HAVE_SYS_STACK_H #include <sys/stack.h> -#endif - #include <stdio.h> -#if defined(__MACH__) -/* - * Darwin doesn't have any exposed frame info, so give it some space. - */ -#define UMEM_FRAMESIZE (2 * sizeof(long long)) - -#elif defined(__sparc) || defined(__sparcv9) +#if defined(__sparc) || defined(__sparcv9) extern void flush_windows(void); #define UMEM_FRAMESIZE MINFRAME @@ -62,7 +43,7 @@ extern void flush_windows(void); */ #define UMEM_FRAMESIZE (sizeof (struct frame)) -#elif !defined(EC_UMEM_DUMMY_PCSTACK) +#else #error needs update for new architecture #endif @@ -74,9 +55,6 @@ extern void flush_windows(void); int getpcstack(uintptr_t *pcstack, int pcstack_limit, int check_signal) { -#ifdef EC_UMEM_DUMMY_PCSTACK - return 0; -#else struct frame *fp; struct frame *nextfp, *minfp; int depth = 0; @@ -207,5 +185,4 @@ getpcstack(uintptr_t *pcstack, int pcstack_limit, int check_signal) minfp = fp; } return (depth); -#endif } diff --git a/zfs/lib/libumem/misc.h b/zfs/lib/libumem/include/misc.h index 41e1fde3a..f1fdcc181 100644 --- a/zfs/lib/libumem/misc.h +++ b/zfs/lib/libumem/include/misc.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,29 +18,21 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ #ifndef _MISC_H #define _MISC_H -/* #pragma ident "@(#)misc.h 1.6 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" #include <sys/types.h> -#ifndef _WIN32 #include <sys/time.h> -#endif -#ifdef HAVE_THREAD_H -# include <thread.h> -#else -# include "sol_compat.h" -#endif +#include <thread.h> +#include <pthread.h> #include <stdarg.h> #ifdef __cplusplus @@ -74,9 +65,9 @@ void log_message(const char *format, ...); /* * returns the index of the (high/low) bit + 1 */ -int highbit(ulong_t) __attribute__ ((pure)); -int lowbit(ulong_t) __attribute__ ((pure)); -/* #pragma no_side_effect(highbit, lowbit) */ +int highbit(ulong_t); +int lowbit(ulong_t); +#pragma no_side_effect(highbit, lowbit) /* * Converts a hrtime_t to a timestruc_t @@ -102,9 +93,9 @@ void umem_error_enter(const char *); /* * prints error message and stack trace, then aborts. Cannot return. */ -void umem_panic(const char *format, ...) __attribute__((noreturn)); -/* #pragma does_not_return(umem_panic) */ -/* #pragma rarely_called(umem_panic) */ +void umem_panic(const char *format, ...) __NORETURN; +#pragma does_not_return(umem_panic) +#pragma rarely_called(umem_panic) /* * like umem_err, but only aborts if umem_abort > 0 @@ -121,9 +112,9 @@ void umem_err_recoverable(const char *format, ...); __umem_assert_failed(#assertion, __FILE__, __LINE__)) #endif -int __umem_assert_failed(const char *assertion, const char *file, int line) __attribute__ ((noreturn)); -/* #pragma does_not_return(__umem_assert_failed) */ -/* #pragma rarely_called(__umem_assert_failed) */ +int __umem_assert_failed(const char *assertion, const char *file, int line); +#pragma does_not_return(__umem_assert_failed) +#pragma rarely_called(__umem_assert_failed) /* * These have architecture-specific implementations. */ diff --git a/zfs/lib/libumem/include/umem.h b/zfs/lib/libumem/include/umem.h index ac6ed92ee..f8dc47529 100644 --- a/zfs/lib/libumem/include/umem.h +++ b/zfs/lib/libumem/include/umem.h @@ -27,7 +27,7 @@ #ifndef _UMEM_H #define _UMEM_H - +#pragma ident "%Z%%M% %I% %E% SMI" #include <sys/types.h> #include <sys/vmem.h> diff --git a/zfs/lib/libumem/umem_base.h b/zfs/lib/libumem/include/umem_base.h index ad3cc1ef0..e78bebfb5 100644 --- a/zfs/lib/libumem/umem_base.h +++ b/zfs/lib/libumem/include/umem_base.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,14 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _UMEM_BASE_H #define _UMEM_BASE_H -/* #pragma ident "@(#)umem_base.h 1.4 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" #include <umem_impl.h> @@ -50,7 +49,7 @@ extern int umem_ready; extern thread_t umem_init_thr; /* the thread doing the init */ extern int umem_init(void); /* do umem's initialization */ -/* #pragma rarely_called(umem_init) */ +#pragma rarely_called(umem_init) extern umem_log_header_t *umem_transaction_log; extern umem_log_header_t *umem_content_log; @@ -120,6 +119,10 @@ extern void umem_process_updates(void); extern void umem_cache_applyall(void (*)(umem_cache_t *)); extern void umem_cache_update(umem_cache_t *); +extern void umem_alloc_sizes_add(size_t); +extern void umem_alloc_sizes_clear(void); +extern void umem_alloc_sizes_remove(size_t); + /* * umem_fork.c: private interfaces */ diff --git a/zfs/lib/libumem/umem_impl.h b/zfs/lib/libumem/include/umem_impl.h index a2e886f25..c6481d975 100644 --- a/zfs/lib/libumem/umem_impl.h +++ b/zfs/lib/libumem/include/umem_impl.h @@ -23,31 +23,18 @@ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ #ifndef _UMEM_IMPL_H #define _UMEM_IMPL_H -/* #pragma ident "@(#)umem_impl.h 1.6 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" #include <umem.h> -#ifdef HAVE_SYS_SYSMACROS_H #include <sys/sysmacros.h> -#endif - -#if HAVE_SYS_TIME_H #include <sys/time.h> -#endif - #include <sys/vmem.h> -#ifdef HAVE_THREAD_H -# include <thread.h> -#else -# include "sol_compat.h" -#endif +#include <thread.h> #ifdef __cplusplus extern "C" { @@ -235,11 +222,7 @@ typedef struct umem_magtype { umem_cache_t *mt_cache; /* magazine cache */ } umem_magtype_t; -#if (defined(__PTHREAD_MUTEX_SIZE__) && __PTHREAD_MUTEX_SIZE__ >= 24) || defined(UMEM_PTHREAD_MUTEX_TOO_BIG) -#define UMEM_CPU_CACHE_SIZE 128 /* must be power of 2 */ -#else #define UMEM_CPU_CACHE_SIZE 64 /* must be power of 2 */ -#endif #define UMEM_CPU_PAD (UMEM_CPU_CACHE_SIZE - sizeof (mutex_t) - \ 2 * sizeof (uint_t) - 2 * sizeof (void *) - 4 * sizeof (int)) #define UMEM_CACHE_SIZE(ncpus) \ @@ -255,10 +238,7 @@ typedef struct umem_cpu_cache { int cc_prounds; /* number of objects in previous mag */ int cc_magsize; /* number of rounds in a full mag */ int cc_flags; /* CPU-local copy of cache_flags */ -#if (!defined(_LP64) || defined(UMEM_PTHREAD_MUTEX_TOO_BIG)) && !defined(_WIN32) - /* on win32, UMEM_CPU_PAD evaluates to zero, and the MS compiler - * won't allow static initialization of arrays containing structures - * that contain zero size arrays */ +#ifndef _LP64 char cc_pad[UMEM_CPU_PAD]; /* for nice alignment (32-bit) */ #endif } umem_cpu_cache_t; @@ -352,8 +332,7 @@ typedef struct umem_cpu_log_header { size_t clh_avail; int clh_chunk; int clh_hits; - char clh_pad[UMEM_CPU_CACHE_SIZE - - sizeof (mutex_t) - sizeof (char *) - + char clh_pad[64 - sizeof (mutex_t) - sizeof (char *) - sizeof (size_t) - 2 * sizeof (int)]; } umem_cpu_log_header_t; diff --git a/zfs/lib/libumem/vmem_base.h b/zfs/lib/libumem/include/vmem_base.h index 06c1efc52..46ed39734 100644 --- a/zfs/lib/libumem/vmem_base.h +++ b/zfs/lib/libumem/include/vmem_base.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,14 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _VMEM_BASE_H #define _VMEM_BASE_H -/* #pragma ident "@(#)vmem_base.h 1.3 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" #include <sys/vmem.h> #include <umem.h> @@ -60,6 +59,7 @@ extern void vmem_reap(void); /* vmem_populate()-safe reap */ extern size_t pagesize; extern size_t vmem_sbrk_pagesize; +extern size_t vmem_sbrk_minalloc; extern uint_t vmem_backend; #define VMEM_BACKEND_SBRK 0x0000001 diff --git a/zfs/lib/libumem/vmem_stand.h b/zfs/lib/libumem/include/vmem_stand.h index aeb8d11a3..fe72ed486 100644 --- a/zfs/lib/libumem/vmem_stand.h +++ b/zfs/lib/libumem/include/vmem_stand.h @@ -27,7 +27,7 @@ #ifndef _VMEM_STAND_H #define _VMEM_STAND_H -/* #pragma ident "@(#)vmem_stand.h 1.3 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" /* * additional functions defined by the standalone backend diff --git a/zfs/lib/libumem/init_lib.c b/zfs/lib/libumem/init_lib.c index bc1b3819f..dd5500a13 100644 --- a/zfs/lib/libumem/init_lib.c +++ b/zfs/lib/libumem/init_lib.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,64 +18,39 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)init_lib.c 1.2 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" /* * Initialization routines for the library version of libumem. */ -#include "config.h" #include "umem_base.h" #include "vmem_base.h" - -#if HAVE_UNISTD_H #include <unistd.h> -#endif -#if HAVE_DLFCN_H #include <dlfcn.h> -#endif - -#include <fcntl.h> -#include <string.h> - -#ifdef __FreeBSD__ -#include <machine/param.h> -#endif void vmem_heap_init(void) { -#ifdef _WIN32 - vmem_backend = VMEM_BACKEND_MMAP; -#else -#if 0 void *handle = dlopen("libmapmalloc.so.1", RTLD_NOLOAD); if (handle != NULL) { -#endif log_message("sbrk backend disabled\n"); vmem_backend = VMEM_BACKEND_MMAP; -#if 0 } -#endif -#endif if ((vmem_backend & VMEM_BACKEND_MMAP) != 0) { vmem_backend = VMEM_BACKEND_MMAP; (void) vmem_mmap_arena(NULL, NULL); } else { -#ifndef _WIN32 vmem_backend = VMEM_BACKEND_SBRK; (void) vmem_sbrk_arena(NULL, NULL); -#endif } } @@ -84,66 +58,14 @@ vmem_heap_init(void) void umem_type_init(caddr_t start, size_t len, size_t pgsize) { -#ifdef _WIN32 - SYSTEM_INFO info; - GetSystemInfo(&info); - pagesize = info.dwPageSize; -#elif !defined(__FreeBSD__) pagesize = _sysconf(_SC_PAGESIZE); -#else - pagesize = PAGE_SIZE; -#endif } int umem_get_max_ncpus(void) { -#ifdef linux - /* - * HACK: sysconf() will invoke malloc() on Linux as part of reading - * in /proc/stat. To avoid recursion in the malloc replacement - * version of libumem, read /proc/stat into a static buffer. - */ - static char proc_stat[8192]; - int fd; - int ncpus = 1; - - fd = open("/proc/stat", O_RDONLY); - if (fd >= 0) { - const ssize_t n = read(fd, proc_stat, sizeof(proc_stat) - 1); - if (n >= 0) { - const char *cur; - const char *next; - - proc_stat[n] = '\0'; - cur = proc_stat; - while (*cur && (next = strstr(cur + 3, "cpu"))) { - cur = next; - } - - if (*cur) - ncpus = atoi(cur + 3) + 1; - } - - close(fd); - } - - return ncpus; - -#else /* !linux */ - -#if _SC_NPROCESSORS_ONLN - return (2 * sysconf(_SC_NPROCESSORS_ONLN)); -#elif defined(_SC_NPROCESSORS_CONF) - return (2 * sysconf(_SC_NPROCESSORS_CONF)); -#elif defined(_WIN32) - SYSTEM_INFO info; - GetSystemInfo(&info); - return info.dwNumberOfProcessors; -#else - /* XXX: determine CPU count on other platforms */ - return (1); -#endif - -#endif /* linux */ + if (thr_main() != -1) + return (2 * sysconf(_SC_NPROCESSORS_ONLN)); + else + return (1); } diff --git a/zfs/lib/libumem/init_stand.c b/zfs/lib/libumem/init_stand.c new file mode 100644 index 000000000..a864c40f2 --- /dev/null +++ b/zfs/lib/libumem/init_stand.c @@ -0,0 +1,64 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Initialization routines for the standalone version of libumem. + */ + +#include "umem_base.h" +#include "vmem_base.h" + +#include "vmem_stand.h" + +void +vmem_heap_init(void) +{ + vmem_backend = VMEM_BACKEND_STAND; + (void) vmem_stand_arena(NULL, NULL); +} + +void +umem_type_init(caddr_t base, size_t len, size_t pgsize) +{ + pagesize = pgsize; + + vmem_stand_init(); + (void) vmem_stand_add(base, len); +} + +int +umem_get_max_ncpus(void) +{ + return (1); +} + +int +umem_add(caddr_t base, size_t len) +{ + return (vmem_stand_add(base, len)); +} diff --git a/zfs/lib/libumem/linktest_stand.c b/zfs/lib/libumem/linktest_stand.c new file mode 100644 index 000000000..8ae9fdbec --- /dev/null +++ b/zfs/lib/libumem/linktest_stand.c @@ -0,0 +1,71 @@ +/* + * 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" + +/* + * This file is used to verify that the standalone's external dependencies + * haven't changed in a way that'll break things that use it. + */ + +void __umem_assert_failed(void) {} +void atomic_add_64(void) {} +void atomic_add_32_nv(void) {} +void dladdr1(void) {} +void bcopy(void) {} +void bzero(void) {} +void exit(void) {} +void getenv(void) {} +void gethrtime(void) {} +void membar_producer(void) {} +void memcpy(void) {} +void _memcpy(void) {} +void memset(void) {} +void snprintf(void) {} +void strchr(void) {} +void strcmp(void) {} +void strlen(void) {} +void strncpy(void) {} +void strrchr(void) {} +void strtoul(void) {} +void umem_err_recoverable(void) {} +void umem_panic(void) {} +void vsnprintf(void) {} + +#ifdef __i386 +void __mul64(void) {} +void __rem64(void) {} +void __div64(void) {} + +#ifdef __GNUC__ +void __divdi3(void) {} +void __moddi3(void) {} +#endif /* __GNUC__ */ + +#endif /* __i386 */ + +int __ctype; +int errno; diff --git a/zfs/lib/libumem/malloc.c b/zfs/lib/libumem/malloc.c new file mode 100644 index 000000000..906f369d2 --- /dev/null +++ b/zfs/lib/libumem/malloc.c @@ -0,0 +1,415 @@ +/* + * 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 <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/sysmacros.h> +#include "umem_base.h" +#include "misc.h" + +/* + * malloc_data_t is an 8-byte structure which is located "before" the pointer + * returned from {m,c,re}alloc and memalign. The first four bytes give + * information about the buffer, and the second four bytes are a status byte. + * + * See umem_impl.h for the various magic numbers used, and the size + * encode/decode macros. + * + * The 'size' of the buffer includes the tags. That is, we encode the + * argument to umem_alloc(), not the argument to malloc(). + */ + +typedef struct malloc_data { + uint32_t malloc_size; + uint32_t malloc_stat; /* = UMEM_MALLOC_ENCODE(state, malloc_size) */ +} malloc_data_t; + +void * +malloc(size_t size_arg) +{ +#ifdef _LP64 + uint32_t high_size = 0; +#endif + size_t size; + + malloc_data_t *ret; + size = size_arg + sizeof (malloc_data_t); + +#ifdef _LP64 + if (size > UMEM_SECOND_ALIGN) { + size += sizeof (malloc_data_t); + high_size = (size >> 32); + } +#endif + if (size < size_arg) { + errno = ENOMEM; /* overflow */ + return (NULL); + } + ret = (malloc_data_t *)_umem_alloc(size, UMEM_DEFAULT); + if (ret == NULL) { + if (size <= UMEM_MAXBUF) + errno = EAGAIN; + else + errno = ENOMEM; + return (NULL); +#ifdef _LP64 + } else if (high_size > 0) { + uint32_t low_size = (uint32_t)size; + + /* + * uses different magic numbers to make it harder to + * undetectably corrupt + */ + ret->malloc_size = high_size; + ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, high_size); + ret++; + + ret->malloc_size = low_size; + ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_OVERSIZE_MAGIC, + low_size); + ret++; + } else if (size > UMEM_SECOND_ALIGN) { + uint32_t low_size = (uint32_t)size; + + ret++; /* leave the first 8 bytes alone */ + + ret->malloc_size = low_size; + ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC, + low_size); + ret++; +#endif + } else { + ret->malloc_size = size; + ret->malloc_stat = UMEM_MALLOC_ENCODE(MALLOC_MAGIC, size); + ret++; + } + return ((void *)ret); +} + +void * +calloc(size_t nelem, size_t elsize) +{ + size_t size = nelem * elsize; + void *retval; + + if (nelem > 0 && elsize > 0 && size/nelem != elsize) { + errno = ENOMEM; /* overflow */ + return (NULL); + } + + retval = malloc(size); + if (retval == NULL) + return (NULL); + + (void) memset(retval, 0, size); + return (retval); +} + +/* + * memalign uses vmem_xalloc to do its work. + * + * in 64-bit, the memaligned buffer always has two tags. This simplifies the + * code. + */ + +void * +memalign(size_t align, size_t size_arg) +{ + size_t size; + uintptr_t phase; + + void *buf; + malloc_data_t *ret; + + size_t overhead; + + if (size_arg == 0 || align == 0 || (align & (align - 1)) != 0) { + errno = EINVAL; + return (NULL); + } + + /* + * if malloc provides the required alignment, use it. + */ + if (align <= UMEM_ALIGN || + (align <= UMEM_SECOND_ALIGN && size_arg >= UMEM_SECOND_ALIGN)) + return (malloc(size_arg)); + +#ifdef _LP64 + overhead = 2 * sizeof (malloc_data_t); +#else + overhead = sizeof (malloc_data_t); +#endif + + ASSERT(overhead <= align); + + size = size_arg + overhead; + phase = align - overhead; + + if (umem_memalign_arena == NULL && umem_init() == 0) { + errno = ENOMEM; + return (NULL); + } + + if (size < size_arg) { + errno = ENOMEM; /* overflow */ + return (NULL); + } + + buf = vmem_xalloc(umem_memalign_arena, size, align, phase, + 0, NULL, NULL, VM_NOSLEEP); + + if (buf == NULL) { + if ((size_arg + align) <= UMEM_MAXBUF) + errno = EAGAIN; + else + errno = ENOMEM; + + return (NULL); + } + + ret = (malloc_data_t *)buf; + { + uint32_t low_size = (uint32_t)size; + +#ifdef _LP64 + uint32_t high_size = (uint32_t)(size >> 32); + + ret->malloc_size = high_size; + ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC, + high_size); + ret++; +#endif + + ret->malloc_size = low_size; + ret->malloc_stat = UMEM_MALLOC_ENCODE(MEMALIGN_MAGIC, low_size); + ret++; + } + + ASSERT(P2PHASE((uintptr_t)ret, align) == 0); + ASSERT((void *)((uintptr_t)ret - overhead) == buf); + + return ((void *)ret); +} + +void * +valloc(size_t size) +{ + return (memalign(pagesize, size)); +} + +/* + * process_free: + * + * Pulls information out of a buffer pointer, and optionally free it. + * This is used by free() and realloc() to process buffers. + * + * On failure, calls umem_err_recoverable() with an appropriate message + * On success, returns the data size through *data_size_arg, if (!is_free). + * + * Preserves errno, since free()'s semantics require it. + */ + +static int +process_free(void *buf_arg, + int do_free, /* free the buffer, or just get its size? */ + size_t *data_size_arg) /* output: bytes of data in buf_arg */ +{ + malloc_data_t *buf; + + void *base; + size_t size; + size_t data_size; + + const char *message; + int old_errno = errno; + + buf = (malloc_data_t *)buf_arg; + + buf--; + size = buf->malloc_size; + + switch (UMEM_MALLOC_DECODE(buf->malloc_stat, size)) { + + case MALLOC_MAGIC: + base = (void *)buf; + data_size = size - sizeof (malloc_data_t); + + if (do_free) + buf->malloc_stat = UMEM_FREE_PATTERN_32; + + goto process_malloc; + +#ifdef _LP64 + case MALLOC_SECOND_MAGIC: + base = (void *)(buf - 1); + data_size = size - 2 * sizeof (malloc_data_t); + + if (do_free) + buf->malloc_stat = UMEM_FREE_PATTERN_32; + + goto process_malloc; + + case MALLOC_OVERSIZE_MAGIC: { + size_t high_size; + + buf--; + high_size = buf->malloc_size; + + if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) != + MALLOC_MAGIC) { + message = "invalid or corrupted buffer"; + break; + } + + size += high_size << 32; + + base = (void *)buf; + data_size = size - 2 * sizeof (malloc_data_t); + + if (do_free) { + buf->malloc_stat = UMEM_FREE_PATTERN_32; + (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32; + } + + goto process_malloc; + } +#endif + + case MEMALIGN_MAGIC: { + size_t overhead = sizeof (malloc_data_t); + +#ifdef _LP64 + size_t high_size; + + overhead += sizeof (malloc_data_t); + + buf--; + high_size = buf->malloc_size; + + if (UMEM_MALLOC_DECODE(buf->malloc_stat, high_size) != + MEMALIGN_MAGIC) { + message = "invalid or corrupted buffer"; + break; + } + size += high_size << 32; + + /* + * destroy the main tag's malloc_stat + */ + if (do_free) + (buf + 1)->malloc_stat = UMEM_FREE_PATTERN_32; +#endif + + base = (void *)buf; + data_size = size - overhead; + + if (do_free) + buf->malloc_stat = UMEM_FREE_PATTERN_32; + + goto process_memalign; + } + default: + if (buf->malloc_stat == UMEM_FREE_PATTERN_32) + message = "double-free or invalid buffer"; + else + message = "invalid or corrupted buffer"; + break; + } + + umem_err_recoverable("%s(%p): %s\n", + do_free? "free" : "realloc", buf_arg, message); + + errno = old_errno; + return (0); + +process_malloc: + if (do_free) + _umem_free(base, size); + else + *data_size_arg = data_size; + + errno = old_errno; + return (1); + +process_memalign: + if (do_free) + vmem_xfree(umem_memalign_arena, base, size); + else + *data_size_arg = data_size; + + errno = old_errno; + return (1); +} + +void +free(void *buf) +{ + if (buf == NULL) + return; + + /* + * Process buf, freeing it if it is not corrupt. + */ + (void) process_free(buf, 1, NULL); +} + +void * +realloc(void *buf_arg, size_t newsize) +{ + size_t oldsize; + void *buf; + + if (buf_arg == NULL) + return (malloc(newsize)); + + if (newsize == 0) { + free(buf_arg); + return (NULL); + } + + /* + * get the old data size without freeing the buffer + */ + if (process_free(buf_arg, 0, &oldsize) == 0) { + errno = EINVAL; + return (NULL); + } + + if (newsize == oldsize) /* size didn't change */ + return (buf_arg); + + buf = malloc(newsize); + if (buf == NULL) + return (NULL); + + (void) memcpy(buf, buf_arg, MIN(newsize, oldsize)); + free(buf_arg); + return (buf); +} diff --git a/zfs/lib/libumem/misc.c b/zfs/lib/libumem/misc.c index aa4d63ff0..a3da9e5b0 100644 --- a/zfs/lib/libumem/misc.c +++ b/zfs/lib/libumem/misc.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,41 +18,26 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)misc.c 1.6 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#define _BUILDING_UMEM_MISC_C -#include "config.h" -/* #include "mtlib.h" */ -#if HAVE_UNISTD_H #include <unistd.h> -#endif -#if HAVE_DLFCN_H #include <dlfcn.h> -#endif #include <signal.h> #include <stdarg.h> #include <stdio.h> #include <string.h> -#if HAVE_SYS_MACHELF_H #include <sys/machelf.h> -#endif #include <umem_impl.h> #include "misc.h" -#ifdef ECELERITY -#include "util.h" -#endif - #define UMEM_ERRFD 2 /* goes to standard error */ #define UMEM_MAX_ERROR_SIZE 4096 /* error messages are truncated to this */ @@ -77,15 +61,12 @@ static uint_t umem_error_end = 0; } static void -umem_log_enter(const char *error_str, int serious) +umem_log_enter(const char *error_str) { int looped; char c; looped = 0; -#ifdef ECELERITY - mem_printf(serious ? DCRITICAL : DINFO, "umem: %s", error_str); -#endif (void) mutex_lock(&umem_error_lock); @@ -118,7 +99,7 @@ umem_error_enter(const char *error_str) (void) write(UMEM_ERRFD, error_str, strlen(error_str)); #endif - umem_log_enter(error_str, 1); + umem_log_enter(error_str); } int @@ -204,7 +185,7 @@ log_message(const char *format, ...) (void) write(UMEM_ERRFD, buf, strlen(buf)); #endif - umem_log_enter(buf, 0); + umem_log_enter(buf); } #ifndef UMEM_STANDALONE @@ -260,7 +241,6 @@ umem_printf_warn(void *ignored, const char *format, ...) int print_sym(void *pointer) { -#if HAVE_SYS_MACHELF_H int result; Dl_info sym_info; @@ -292,7 +272,4 @@ print_sym(void *pointer) (char *)pointer - (char *)sym_info.dli_saddr); return (1); } -#else - return 0; -#endif } diff --git a/zfs/lib/libumem/sol_compat.h b/zfs/lib/libumem/sol_compat.h deleted file mode 100644 index 4b7e6cf32..000000000 --- a/zfs/lib/libumem/sol_compat.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2006 OmniTI, Inc. All rights reserved - * This header file distributed under the terms of the CDDL. - * Portions Copyright 2004 Sun Microsystems, Inc. All Rights reserved. - */ -#ifndef _EC_UMEM_SOL_COMPAT_H_ -#define _EC_UMEM_SOL_COMPAT_H_ - -#include "config.h" - -#include <stdint.h> -#include <pthread.h> - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#ifdef _WIN32 -# define THR_RETURN DWORD -# define THR_API WINAPI -# define INLINE __inline -#else -# define THR_RETURN void * -# define THR_API -# define INLINE inline -#endif - -#if defined(__MACH__) || defined(_WIN32) -#define NO_WEAK_SYMBOLS -#define _umem_cache_alloc(a,b) umem_cache_alloc(a,b) -#define _umem_cache_free(a,b) umem_cache_free(a,b) -#define _umem_zalloc(a,b) umem_zalloc(a,b) -#define _umem_alloc(a,b) umem_alloc(a,b) -#define _umem_alloc_align(a,b,c) umem_alloc_align(a,b,c) -#define _umem_free(a,b) umem_free(a,b) -#define _umem_free_align(a,b) umem_free_align(a,b) -#endif - -#ifdef _WIN32 -#define bcopy(s, d, n) memcpy(d, s, n) -#define bzero(m, s) memset(m, 0, s) -#endif - -typedef pthread_t thread_t; -typedef pthread_mutex_t mutex_t; -typedef pthread_cond_t cond_t; -typedef u_int64_t hrtime_t; -typedef uint32_t uint_t; -typedef unsigned long ulong_t; -typedef struct timespec timestruc_t; -typedef long long longlong_t; -typedef struct timespec timespec_t; -static INLINE hrtime_t gethrtime(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return (((u_int64_t)tv.tv_sec) << 32) | tv.tv_usec; -} -# define thr_self() pthread_self() -static INLINE thread_t _thr_self(void) { - return thr_self(); -} -#if defined(_MACH_PORT_T) -#define CPUHINT() (pthread_mach_thread_np(pthread_self())) -#endif -# define thr_sigsetmask pthread_sigmask - -#define THR_BOUND 1 -#define THR_DETACHED 2 -#define THR_DAEMON 4 - -static INLINE int thr_create(void *stack_base, - size_t stack_size, THR_RETURN (THR_API *start_func)(void*), - void *arg, long flags, thread_t *new_thread_ID) -{ - int ret; - pthread_attr_t attr; - - pthread_attr_init(&attr); - - if (flags & THR_DETACHED) { - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - } - ret = pthread_create(new_thread_ID, &attr, start_func, arg); - pthread_attr_destroy(&attr); - return ret; -} - - -# define mutex_init(mp, type, arg) pthread_mutex_init(mp, NULL) -# define mutex_lock(mp) pthread_mutex_lock(mp) -# define mutex_unlock(mp) pthread_mutex_unlock(mp) -# define mutex_destroy(mp) pthread_mutex_destroy(mp) -# define mutex_trylock(mp) pthread_mutex_trylock(mp) -# define DEFAULTMUTEX PTHREAD_MUTEX_INITIALIZER -# define DEFAULTCV PTHREAD_COND_INITIALIZER -# define MUTEX_HELD(mp) 1 /* not really, but only used in an assert */ - -# define cond_init(c, type, arg) pthread_cond_init(c, NULL) -# define cond_wait(c, m) pthread_cond_wait(c, m) -# define _cond_wait(c, m) pthread_cond_wait(c, m) -# define cond_signal(c) pthread_cond_signal(c) -# define cond_broadcast(c) pthread_cond_broadcast(c) -# define cond_destroy(c) pthread_cond_destroy(c) -# define cond_timedwait pthread_cond_timedwait -# define _cond_timedwait pthread_cond_timedwait - -#ifndef RTLD_FIRST -# define RTLD_FIRST 0 -#endif - -#ifdef ECELERITY -# include "ec_atomic.h" -#else -# ifdef _WIN32 -# define ec_atomic_inc(a) InterlockedIncrement(a) -# define ec_atomic_inc64(a) InterlockedIncrement64(a) -# elif (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) -static INLINE uint_t ec_atomic_cas(uint_t *mem, uint_t with, uint_t cmp) -{ - uint_t prev; - __asm volatile ("lock; cmpxchgl %1, %2" - : "=a" (prev) - : "r" (with), "m" (*(mem)), "0" (cmp) - : "memory"); - return prev; -} -# elif defined(__sparc__) && defined(__GNUC__) -static INLINE uint_t ec_atomic_cas(uint_t *mem, uint_t with, uint_t cmp) -{ - __asm volatile ("cas [%3],%2,%0" - : "+r"(with), "=m"(*(mem)) - : "r"(cmp), "r"(mem), "m"(*(mem)) ); - return with; -} -# endif - -# ifndef ec_atomic_inc -static INLINE uint_t ec_atomic_inc(uint_t *mem) -{ - register uint_t last; - do { - last = *mem; - } while (ec_atomic_cas(mem, last+1, last) != last); - return ++last; -} -# endif -# ifndef ec_atomic_inc64 - /* yeah, it's not great. It's only used to bump failed allocation - * counts, so it is not critical right now. */ -# define ec_atomic_inc64(a) (*a)++ -# endif - -#endif - -#define P2PHASE(x, align) ((x) & ((align) - 1)) -#define P2ALIGN(x, align) ((x) & -(align)) -#define P2NPHASE(x, align) (-(x) & ((align) - 1)) -#define P2ROUNDUP(x, align) (-(-(x) & -(align))) -#define P2END(x, align) (-(~(x) & -(align))) -#define P2PHASEUP(x, align, phase) ((phase) - (((phase) - (x)) & -(align))) -#define P2CROSS(x, y, align) (((x) ^ (y)) > (align) - 1) -#define P2SAMEHIGHBIT(x, y) (((x) ^ (y)) < ((x) & (y))) -#define IS_P2ALIGNED(v, a) ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0) -#define ISP2(x) (((x) & ((x) - 1)) == 0) - -/* beware! umem only uses these atomic adds for incrementing by 1 */ -#define atomic_add_64(lvalptr, delta) ec_atomic_inc64(lvalptr) -#define atomic_add_32_nv(a, b) ec_atomic_inc(a) - -#ifndef NANOSEC -#define NANOSEC 1000000000 -#endif - -#ifdef _WIN32 -#define issetugid() 0 -#elif !defined(__FreeBSD__) -#define issetugid() (geteuid() == 0) -#endif - -#define _sysconf(a) sysconf(a) -#define __NORETURN __attribute__ ((noreturn)) - -#define EC_UMEM_DUMMY_PCSTACK 1 -static INLINE int __nthreads(void) -{ - /* or more; just to force multi-threaded mode */ - return 2; -} - -#if (SIZEOF_VOID_P == 8) -# define _LP64 1 -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - - -#endif diff --git a/zfs/lib/libumem/stub_stand.c b/zfs/lib/libumem/stub_stand.c new file mode 100644 index 000000000..025001ff7 --- /dev/null +++ b/zfs/lib/libumem/stub_stand.c @@ -0,0 +1,129 @@ +/* + * 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" + +/* + * Stubs for the standalone to reduce the dependence on external libraries + */ + +#include <string.h> +#include "misc.h" + +/*ARGSUSED*/ +int +cond_init(cond_t *cvp, int type, void *arg) +{ + return (0); +} + +/*ARGSUSED*/ +int +cond_destroy(cond_t *cvp) +{ + return (0); +} + +/*ARGSUSED*/ +int +cond_wait(cond_t *cv, mutex_t *mutex) +{ + umem_panic("attempt to wait on standumem cv %p", cv); + + /*NOTREACHED*/ + return (0); +} + +/*ARGSUSED*/ +int +cond_broadcast(cond_t *cvp) +{ + return (0); +} + +/*ARGSUSED*/ +int +pthread_setcancelstate(int state, int *oldstate) +{ + return (0); +} + +thread_t +thr_self(void) +{ + return ((thread_t)1); +} + +static mutex_t _mp = DEFAULTMUTEX; + +/*ARGSUSED*/ +int +mutex_init(mutex_t *mp, int type, void *arg) +{ + (void) memcpy(mp, &_mp, sizeof (mutex_t)); + return (0); +} + +/*ARGSUSED*/ +int +mutex_destroy(mutex_t *mp) +{ + return (0); +} + +/*ARGSUSED*/ +int +_mutex_held(mutex_t *mp) +{ + return (1); +} + +/*ARGSUSED*/ +int +mutex_lock(mutex_t *mp) +{ + return (0); +} + +/*ARGSUSED*/ +int +mutex_trylock(mutex_t *mp) +{ + return (0); +} + +/*ARGSUSED*/ +int +mutex_unlock(mutex_t *mp) +{ + return (0); +} + +int +issetugid(void) +{ + return (1); +} diff --git a/zfs/lib/libumem/sys/vmem.h b/zfs/lib/libumem/sys/vmem.h deleted file mode 100644 index fed44c3d4..000000000 --- a/zfs/lib/libumem/sys/vmem.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (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 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SYS_VMEM_H -#define _SYS_VMEM_H - -/* #pragma ident "@(#)vmem.h 1.13 05/06/08 SMI" */ - -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * Per-allocation flags - */ -#define VM_SLEEP 0x00000000 /* same as KM_SLEEP */ -#define VM_NOSLEEP 0x00000001 /* same as KM_NOSLEEP */ -#define VM_PANIC 0x00000002 /* same as KM_PANIC */ -#define VM_PUSHPAGE 0x00000004 /* same as KM_PUSHPAGE */ -#define VM_KMFLAGS 0x000000ff /* flags that must match KM_* flags */ - -#define VM_BESTFIT 0x00000100 -#define VM_FIRSTFIT 0x00000200 -#define VM_NEXTFIT 0x00000400 - -/* - * The following flags are restricted for use only within the kernel. - * VM_MEMLOAD is for use by the HAT to avoid infinite recursion. - * VM_NORELOC is used by the kernel when static VA->PA mappings are required. - */ -#define VM_MEMLOAD 0x00000800 -#define VM_NORELOC 0x00001000 -/* - * VM_ABORT requests that vmem_alloc() *ignore* the VM_SLEEP/VM_NOSLEEP flags - * and forgo reaping if the allocation or attempted import, fails. This - * flag is a segkmem-specific flag, and should not be used by anyone else. - */ -#define VM_ABORT 0x00002000 - -#define VM_FLAGS 0x0000FFFF - -/* - * Arena creation flags - */ -#define VMC_POPULATOR 0x00010000 -#define VMC_NO_QCACHE 0x00020000 /* cannot use quantum caches */ -#define VMC_IDENTIFIER 0x00040000 /* not backed by memory */ -/* - * internal use only; the import function uses the vmem_ximport_t interface - * and may increase the request size if it so desires - */ -#define VMC_XALLOC 0x00080000 -#define VMC_FLAGS 0xFFFF0000 - -/* - * Public segment types - */ -#define VMEM_ALLOC 0x01 -#define VMEM_FREE 0x02 - -/* - * Implementation-private segment types - */ -#define VMEM_SPAN 0x10 -#define VMEM_ROTOR 0x20 -#define VMEM_WALKER 0x40 - -/* - * VMEM_REENTRANT indicates to vmem_walk() that the callback routine may - * call back into the arena being walked, so vmem_walk() must drop the - * arena lock before each callback. The caveat is that since the arena - * isn't locked, its state can change. Therefore it is up to the callback - * routine to handle cases where the segment isn't of the expected type. - * For example, we use this to walk heap_arena when generating a crash dump; - * see segkmem_dump() for sample usage. - */ -#define VMEM_REENTRANT 0x80000000 - -typedef struct vmem vmem_t; -typedef void *(vmem_alloc_t)(vmem_t *, size_t, int); -typedef void (vmem_free_t)(vmem_t *, void *, size_t); - -/* - * Alternate import style; the requested size is passed in a pointer, - * which can be increased by the import function if desired. - */ -typedef void *(vmem_ximport_t)(vmem_t *, size_t *, int); - -#if 0 -extern vmem_t *vmem_init(const char *, void *, size_t, size_t, - vmem_alloc_t *, vmem_free_t *); -extern void vmem_update(void *); -extern int vmem_is_populator(); -extern size_t vmem_seg_size; -#endif - -extern vmem_t *vmem_create(const char *, void *, size_t, size_t, - vmem_alloc_t *, vmem_free_t *, vmem_t *, size_t, int); -extern vmem_t *vmem_xcreate(const char *, void *, size_t, size_t, - vmem_ximport_t *, vmem_free_t *, vmem_t *, size_t, int); -extern void vmem_destroy(vmem_t *); -extern void *vmem_alloc(vmem_t *, size_t, int); -extern void *vmem_xalloc(vmem_t *, size_t, size_t, size_t, size_t, - void *, void *, int); -extern void vmem_free(vmem_t *, void *, size_t); -extern void vmem_xfree(vmem_t *, void *, size_t); -extern void *vmem_add(vmem_t *, void *, size_t, int); -extern int vmem_contains(vmem_t *, void *, size_t); -extern void vmem_walk(vmem_t *, int, void (*)(void *, void *, size_t), void *); -extern size_t vmem_size(vmem_t *, int); - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_VMEM_H */ diff --git a/zfs/lib/libumem/sys/vmem_impl_user.h b/zfs/lib/libumem/sys/vmem_impl_user.h index c7dd5cc46..cc9da6679 100644 --- a/zfs/lib/libumem/sys/vmem_impl_user.h +++ b/zfs/lib/libumem/sys/vmem_impl_user.h @@ -23,30 +23,17 @@ * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ #ifndef _SYS_VMEM_IMPL_USER_H #define _SYS_VMEM_IMPL_USER_H -/* #pragma ident "@(#)vmem_impl_user.h 1.2 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#if HAVE_SYS_KSTAT #include <sys/kstat.h> -#endif -#ifndef _WIN32 #include <sys/time.h> -#endif #include <sys/vmem.h> -#if HAVE_THREAD_H #include <thread.h> -#else -# include "sol_compat.h" -#endif -#if HAVE_SYNC_H #include <synch.h> -#endif #ifdef __cplusplus extern "C" { diff --git a/zfs/lib/libumem/umem.c b/zfs/lib/libumem/umem.c index 635c19e1a..a3eb0b8e6 100644 --- a/zfs/lib/libumem/umem.c +++ b/zfs/lib/libumem/umem.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,47 +18,15 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)umem.c 1.11 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -/*! - * \mainpage Main Page - * - * \section README - * - * \include README - * - * \section Nuances - * - * There is a nuance in the behaviour of the umem port compared - * with umem on Solaris. - * - * On Linux umem will not return memory back to the OS until umem fails - * to allocate a chunk. On failure, umem_reap() will be called automatically, - * to return memory to the OS. If your code is going to be running - * for a long time on Linux and mixes calls to different memory allocators - * (e.g.: malloc()) and umem, your code will need to call - * umem_reap() periodically. - * - * This doesn't happen on Solaris, because malloc is replaced - * with umem calls, meaning that umem_reap() is called automatically. - * - * \section References - * - * http://docs.sun.com/app/docs/doc/816-5173/6mbb8advq?a=view - * - * http://access1.sun.com/techarticles/libumem.html - * - * \section Overview - * - * \code +/* * based on usr/src/uts/common/os/kmem.c r1.64 from 2001/12/18 * * The slab allocator, as described in the following two papers: @@ -88,6 +55,7 @@ * * * KM_SLEEP v.s. UMEM_NOFAIL * + * * lock ordering * * 2. Initialization * ----------------- @@ -362,41 +330,51 @@ * If a constructor callback _does_ do a UMEM_NOFAIL allocation, and * the nofail callback does a non-local exit, we will leak the * partially-constructed buffer. - * \endcode + * + * + * 6. Lock Ordering + * ---------------- + * umem has a few more locks than kmem does, mostly in the update path. The + * overall lock ordering (earlier locks must be acquired first) is: + * + * umem_init_lock + * + * vmem_list_lock + * vmem_nosleep_lock.vmpl_mutex + * vmem_t's: + * vm_lock + * sbrk_lock + * + * umem_cache_lock + * umem_update_lock + * umem_flags_lock + * umem_cache_t's: + * cache_cpu[*].cc_lock + * cache_depot_lock + * cache_lock + * umem_log_header_t's: + * lh_cpu[*].clh_lock + * lh_lock */ -#include "config.h" -/* #include "mtlib.h" */ #include <umem_impl.h> #include <sys/vmem_impl_user.h> #include "umem_base.h" #include "vmem_base.h" -#if HAVE_SYS_PROCESSOR_H #include <sys/processor.h> -#endif -#if HAVE_SYS_SYSMACROS_H #include <sys/sysmacros.h> -#endif -#if HAVE_ALLOCA_H #include <alloca.h> -#endif #include <errno.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#if HAVE_STRINGS_H #include <strings.h> -#endif #include <signal.h> -#if HAVE_UNISTD_H #include <unistd.h> -#endif -#if HAVE_ATOMIC_H #include <atomic.h> -#endif #include "misc.h" @@ -413,8 +391,12 @@ size_t pagesize; * bytes, so that it will be 64-byte aligned. For all multiples of 64, * the next kmem_cache_size greater than or equal to it must be a * multiple of 64. + * + * This table must be in sorted order, from smallest to highest. The + * highest slot must be UMEM_MAXBUF, and every slot afterwards must be + * zero. */ -static const int umem_alloc_sizes[] = { +static int umem_alloc_sizes[] = { #ifdef _LP64 1 * 8, 1 * 16, @@ -433,17 +415,19 @@ static const int umem_alloc_sizes[] = { P2ALIGN(8192 / 7, 64), P2ALIGN(8192 / 6, 64), P2ALIGN(8192 / 5, 64), - P2ALIGN(8192 / 4, 64), + P2ALIGN(8192 / 4, 64), 2304, P2ALIGN(8192 / 3, 64), - P2ALIGN(8192 / 2, 64), - P2ALIGN(8192 / 1, 64), + P2ALIGN(8192 / 2, 64), 4544, + P2ALIGN(8192 / 1, 64), 9216, 4096 * 3, - 8192 * 2, + UMEM_MAXBUF, /* = 8192 * 2 */ + /* 24 slots for user expansion */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }; #define NUM_ALLOC_SIZES (sizeof (umem_alloc_sizes) / sizeof (*umem_alloc_sizes)) -#define UMEM_MAXBUF 16384 - static umem_magtype_t umem_magtype[] = { { 1, 8, 3200, 65536 }, { 3, 16, 256, 32768 }, @@ -480,21 +464,21 @@ size_t umem_minfirewall; /* hardware-enforced redzone threshold */ uint_t umem_flags = 0; -mutex_t umem_init_lock = DEFAULTMUTEX; /* locks initialization */ -cond_t umem_init_cv = DEFAULTCV; /* initialization CV */ +mutex_t umem_init_lock; /* locks initialization */ +cond_t umem_init_cv; /* initialization CV */ thread_t umem_init_thr; /* thread initializing */ int umem_init_env_ready; /* environ pre-initted */ int umem_ready = UMEM_READY_STARTUP; static umem_nofail_callback_t *nofail_callback; -static mutex_t umem_nofail_exit_lock = DEFAULTMUTEX; +static mutex_t umem_nofail_exit_lock; static thread_t umem_nofail_exit_thr; static umem_cache_t *umem_slab_cache; static umem_cache_t *umem_bufctl_cache; static umem_cache_t *umem_bufctl_audit_cache; -mutex_t umem_flags_lock = DEFAULTMUTEX; +mutex_t umem_flags_lock; static vmem_t *heap_arena; static vmem_alloc_t *heap_alloc; @@ -517,15 +501,7 @@ umem_log_header_t *umem_content_log; umem_log_header_t *umem_failure_log; umem_log_header_t *umem_slab_log; -extern thread_t _thr_self(void); -#if defined(__MACH__) || defined(__FreeBSD__) -# define CPUHINT() ((int)(_thr_self())) -#endif - -#ifndef CPUHINT -#define CPUHINT() (_thr_self()) -#endif - +#define CPUHINT() (thr_self()) #define CPUHINT_MAX() INT_MAX #define CPU(mask) (umem_cpus + (CPUHINT() & (mask))) @@ -547,12 +523,12 @@ volatile thread_t umem_st_update_thr; /* only used when single-thd */ thr_self() == umem_st_update_thr) #define IN_REAP() IN_UPDATE() -mutex_t umem_update_lock = DEFAULTMUTEX; /* cache_u{next,prev,flags} */ -cond_t umem_update_cv = DEFAULTCV; +mutex_t umem_update_lock; /* cache_u{next,prev,flags} */ +cond_t umem_update_cv; volatile hrtime_t umem_reap_next; /* min hrtime of next reap */ -mutex_t umem_cache_lock = DEFAULTMUTEX; /* inter-cache linkage only */ +mutex_t umem_cache_lock; /* inter-cache linkage only */ #ifdef UMEM_STANDALONE umem_cache_t umem_null_cache; @@ -625,12 +601,6 @@ caddr_t umem_min_stack; caddr_t umem_max_stack; -/* - * we use the _ versions, since we don't want to be cancelled. - * Actually, this is automatically taken care of by including "mtlib.h". - */ -extern int _cond_wait(cond_t *cv, mutex_t *mutex); - #define UMERR_MODIFIED 0 /* buffer modified while on freelist */ #define UMERR_REDZONE 1 /* redzone violation (write past end of buf) */ #define UMERR_DUPFREE 2 /* freed a buffer twice */ @@ -757,6 +727,8 @@ umem_remove_updates(umem_cache_t *cp) * Get it out of the active state */ while (cp->cache_uflags & UMU_ACTIVE) { + int cancel_state; + ASSERT(cp->cache_unext == NULL); cp->cache_uflags |= UMU_NOTIFY; @@ -768,7 +740,10 @@ umem_remove_updates(umem_cache_t *cp) ASSERT(umem_update_thr != thr_self() && umem_st_update_thr != thr_self()); - (void) _cond_wait(&umem_update_cv, &umem_update_lock); + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, + &cancel_state); + (void) cond_wait(&umem_update_cv, &umem_update_lock); + (void) pthread_setcancelstate(cancel_state, NULL); } /* * Get it out of the Work Requested state @@ -1097,7 +1072,7 @@ umem_log_enter(umem_log_header_t *lhp, void *data, size_t size) { void *logspace; umem_cpu_log_header_t *clhp = - &(lhp->lh_cpu[CPU(umem_cpu_mask)->cpu_number]); + &lhp->lh_cpu[CPU(umem_cpu_mask)->cpu_number]; if (lhp == NULL || umem_logging == 0) return (NULL); @@ -1659,9 +1634,7 @@ umem_cpu_reload(umem_cpu_cache_t *ccp, umem_magazine_t *mp, int rounds) /* * Allocate a constructed object from cache cp. */ -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_cache_alloc = _umem_cache_alloc -#endif void * _umem_cache_alloc(umem_cache_t *cp, int umflag) { @@ -1779,9 +1752,7 @@ retry: /* * Free a constructed object to cache cp. */ -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_cache_free = _umem_cache_free -#endif void _umem_cache_free(umem_cache_t *cp, void *buf) { @@ -1886,9 +1857,7 @@ _umem_cache_free(umem_cache_t *cp, void *buf) umem_slab_free(cp, buf); } -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_zalloc = _umem_zalloc -#endif void * _umem_zalloc(size_t size, int umflag) { @@ -1916,9 +1885,7 @@ retry: return (buf); } -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_alloc = _umem_alloc -#endif void * _umem_alloc(size_t size, int umflag) { @@ -1954,9 +1921,7 @@ umem_alloc_retry: return (buf); } -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_alloc_align = _umem_alloc_align -#endif void * _umem_alloc_align(size_t size, size_t align, int umflag) { @@ -1986,9 +1951,7 @@ umem_alloc_align_retry: return (buf); } -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_free = _umem_free -#endif void _umem_free(void *buf, size_t size) { @@ -2026,9 +1989,7 @@ _umem_free(void *buf, size_t size) } } -#ifndef NO_WEAK_SYMBOLS #pragma weak umem_free_align = _umem_free_align -#endif void _umem_free_align(void *buf, size_t size) { @@ -2382,7 +2343,6 @@ umem_reap(void) (void) mutex_unlock(&umem_update_lock); return; } - umem_reaping = UMEM_REAP_ADDING; /* lock out other reaps */ (void) mutex_unlock(&umem_update_lock); @@ -2770,6 +2730,88 @@ umem_cache_destroy(umem_cache_t *cp) vmem_free(umem_cache_arena, cp, UMEM_CACHE_SIZE(umem_max_ncpus)); } +void +umem_alloc_sizes_clear(void) +{ + int i; + + umem_alloc_sizes[0] = UMEM_MAXBUF; + for (i = 1; i < NUM_ALLOC_SIZES; i++) + umem_alloc_sizes[i] = 0; +} + +void +umem_alloc_sizes_add(size_t size_arg) +{ + int i, j; + size_t size = size_arg; + + if (size == 0) { + log_message("size_add: cannot add zero-sized cache\n", + size, UMEM_MAXBUF); + return; + } + + if (size > UMEM_MAXBUF) { + log_message("size_add: %ld > %d, cannot add\n", size, + UMEM_MAXBUF); + return; + } + + if (umem_alloc_sizes[NUM_ALLOC_SIZES - 1] != 0) { + log_message("size_add: no space in alloc_table for %d\n", + size); + return; + } + + if (P2PHASE(size, UMEM_ALIGN) != 0) { + size = P2ROUNDUP(size, UMEM_ALIGN); + log_message("size_add: rounding %d up to %d\n", size_arg, + size); + } + + for (i = 0; i < NUM_ALLOC_SIZES; i++) { + int cur = umem_alloc_sizes[i]; + if (cur == size) { + log_message("size_add: %ld already in table\n", + size); + return; + } + if (cur > size) + break; + } + + for (j = NUM_ALLOC_SIZES - 1; j > i; j--) + umem_alloc_sizes[j] = umem_alloc_sizes[j-1]; + umem_alloc_sizes[i] = size; +} + +void +umem_alloc_sizes_remove(size_t size) +{ + int i; + + if (size == UMEM_MAXBUF) { + log_message("size_remove: cannot remove %ld\n", size); + return; + } + + for (i = 0; i < NUM_ALLOC_SIZES; i++) { + int cur = umem_alloc_sizes[i]; + if (cur == size) + break; + else if (cur > size || cur == 0) { + log_message("size_remove: %ld not found in table\n", + size); + return; + } + } + + for (; i + 1 < NUM_ALLOC_SIZES; i++) + umem_alloc_sizes[i] = umem_alloc_sizes[i+1]; + umem_alloc_sizes[i] = 0; +} + static int umem_cache_init(void) { @@ -2862,6 +2904,10 @@ umem_cache_init(void) for (i = 0; i < NUM_ALLOC_SIZES; i++) { size_t cache_size = umem_alloc_sizes[i]; size_t align = 0; + + if (cache_size == 0) + break; /* 0 terminates the list */ + /* * If they allocate a multiple of the coherency granularity, * they get a coherency-granularity-aligned address. @@ -2889,6 +2935,9 @@ umem_cache_init(void) for (i = 0; i < NUM_ALLOC_SIZES; i++) { size_t cache_size = umem_alloc_sizes[i]; + if (cache_size == 0) + break; /* 0 terminates the list */ + cp = umem_alloc_caches[i]; while (size <= cache_size) { @@ -2896,6 +2945,7 @@ umem_cache_init(void) size += UMEM_ALIGN; } } + ASSERT(size - UMEM_ALIGN == UMEM_MAXBUF); return (1); } @@ -2903,16 +2953,15 @@ umem_cache_init(void) * umem_startup() is called early on, and must be called explicitly if we're * the standalone version. */ -static void -umem_startup() __attribute__((constructor)); - +#ifdef UMEM_STANDALONE void -umem_startup() +#else +#pragma init(umem_startup) +static void +#endif +umem_startup(caddr_t start, size_t len, size_t pagesize, caddr_t minstack, + caddr_t maxstack) { - caddr_t start = NULL; - size_t len = 0; - size_t pagesize = 0; - #ifdef UMEM_STANDALONE int idx; /* Standalone doesn't fork */ @@ -2995,9 +3044,16 @@ umem_init(void) * someone else beat us to initializing umem. Wait * for them to complete, then return. */ - while (umem_ready == UMEM_READY_INITING) - (void) _cond_wait(&umem_init_cv, + while (umem_ready == UMEM_READY_INITING) { + int cancel_state; + + (void) pthread_setcancelstate( + PTHREAD_CANCEL_DISABLE, &cancel_state); + (void) cond_wait(&umem_init_cv, &umem_init_lock); + (void) pthread_setcancelstate( + cancel_state, NULL); + } ASSERT(umem_ready == UMEM_READY || umem_ready == UMEM_READY_INIT_FAILED); (void) mutex_unlock(&umem_init_lock); @@ -3199,10 +3255,3 @@ fail: (void) mutex_unlock(&umem_init_lock); return (0); } - -size_t -umem_cache_get_bufsize(umem_cache_t *cache) -{ - return cache->cache_bufsize; -} - diff --git a/zfs/lib/libumem/umem_agent_support.c b/zfs/lib/libumem/umem_agent_support.c index 55db5e6eb..d604b5e0c 100644 --- a/zfs/lib/libumem/umem_agent_support.c +++ b/zfs/lib/libumem/umem_agent_support.c @@ -23,18 +23,13 @@ * Copyright 2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)umem_agent_support.c 1.2 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" #include "umem_base.h" #define AGENT_STACK_SIZE 4096 -#if 0 char __umem_agent_stack_beg[AGENT_STACK_SIZE]; char *__umem_agent_stack_end = __umem_agent_stack_beg + AGENT_STACK_SIZE; @@ -46,5 +41,3 @@ __umem_agent_free_bp(umem_cache_t *cp, void *buf) _umem_cache_free(cp, buf); _breakpoint(); } -#endif - diff --git a/zfs/lib/libumem/umem_fail.c b/zfs/lib/libumem/umem_fail.c index 2bafd2682..8e315b76c 100644 --- a/zfs/lib/libumem/umem_fail.c +++ b/zfs/lib/libumem/umem_fail.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,26 +18,20 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ - -/* #pragma ident "@(#)umem_fail.c 1.4 05/06/08 SMI" */ /* * Failure routines for libumem (not standalone) */ -#include "config.h" #include <sys/types.h> #include <signal.h> #include <stdarg.h> #include <string.h> -#include <stdio.h> #include "misc.h" @@ -74,31 +67,14 @@ firstexit(int type) static void __NORETURN umem_do_abort(void) { -#ifdef _WIN32 - abort(); -#else - if (firstexit(UMEM_EXIT_ABORT)) { + if (firstexit(UMEM_EXIT_ABORT)) (void) raise(SIGABRT); - } for (;;) { -#if defined(__FreeBSD__) - sigset_t set; - struct sigaction sa; - - sa.sa_handler = SIG_DFL; - (void) sigaction(SIGABRT, &sa, NULL); - (void) sigemptyset (&set); - (void) sigaddset (&set, SIGABRT); - (void) sigprocmask (SIG_UNBLOCK, &set, NULL); - (void) raise (SIGABRT); -#else (void) signal(SIGABRT, SIG_DFL); (void) sigrelse(SIGABRT); (void) raise(SIGABRT); -#endif } -#endif } #define SKIP_FRAMES 1 /* skip the panic frame */ @@ -137,12 +113,6 @@ umem_panic(const char *format, ...) if (format[strlen(format)-1] != '\n') umem_error_enter("\n"); -#ifdef ECELERITY - va_start(va, format); - ec_debug_vprintf(DCRITICAL, DMEM, format, va); - va_end(va); -#endif - print_stacktrace(); umem_do_abort(); @@ -171,6 +141,6 @@ __umem_assert_failed(const char *assertion, const char *file, int line) { umem_panic("Assertion failed: %s, file %s, line %d\n", assertion, file, line); - umem_do_abort(); /*NOTREACHED*/ + return (0); } diff --git a/zfs/lib/libumem/umem_fork.c b/zfs/lib/libumem/umem_fork.c index 2f701026d..4cbe81dfe 100644 --- a/zfs/lib/libumem/umem_fork.c +++ b/zfs/lib/libumem/umem_fork.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,26 +18,22 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)umem_fork.c 1.3 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" -/* #include "mtlib.h" */ #include "umem_base.h" #include "vmem_base.h" -#ifndef _WIN32 #include <unistd.h> /* - * The following functions are for pre- and post-fork1(2) handling. + * The following functions are for pre- and post-fork1(2) handling. See + * "Lock Ordering" in lib/libumem/common/umem.c for the lock ordering used. */ static void @@ -108,6 +103,10 @@ umem_lockup(void) (void) umem_init(); (void) mutex_lock(&umem_init_lock); } + + vmem_lockup(); + vmem_sbrk_lockup(); + (void) mutex_lock(&umem_cache_lock); (void) mutex_lock(&umem_update_lock); (void) mutex_lock(&umem_flags_lock); @@ -124,46 +123,30 @@ umem_lockup(void) (void) cond_broadcast(&umem_update_cv); - vmem_sbrk_lockup(); - vmem_lockup(); } static void -umem_release(void) -{ - umem_cache_t *cp; - - vmem_release(); - vmem_sbrk_release(); - - umem_release_log_header(umem_slab_log); - umem_release_log_header(umem_failure_log); - umem_release_log_header(umem_content_log); - umem_release_log_header(umem_transaction_log); - - for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; - cp = cp->cache_next) - umem_release_cache(cp); - umem_release_cache(&umem_null_cache); - - (void) mutex_unlock(&umem_flags_lock); - (void) mutex_unlock(&umem_update_lock); - (void) mutex_unlock(&umem_cache_lock); - (void) mutex_unlock(&umem_init_lock); -} - -static void -umem_release_child(void) +umem_do_release(int as_child) { umem_cache_t *cp; + int cleanup_update = 0; /* - * Clean up the update state + * Clean up the update state if we are the child process and + * another thread was processing updates. */ - umem_update_thr = 0; + if (as_child) { + if (umem_update_thr != thr_self()) { + umem_update_thr = 0; + cleanup_update = 1; + } + if (umem_st_update_thr != thr_self()) { + umem_st_update_thr = 0; + cleanup_update = 1; + } + } - if (umem_st_update_thr != thr_self()) { - umem_st_update_thr = 0; + if (cleanup_update) { umem_reaping = UMEM_REAP_DONE; for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; @@ -196,19 +179,45 @@ umem_release_child(void) } } - umem_release(); + umem_release_log_header(umem_slab_log); + umem_release_log_header(umem_failure_log); + umem_release_log_header(umem_content_log); + umem_release_log_header(umem_transaction_log); + + for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; + cp = cp->cache_next) + umem_release_cache(cp); + umem_release_cache(&umem_null_cache); + + (void) mutex_unlock(&umem_flags_lock); + (void) mutex_unlock(&umem_update_lock); + (void) mutex_unlock(&umem_cache_lock); + + vmem_sbrk_release(); + vmem_release(); + + (void) mutex_unlock(&umem_init_lock); +} + +static void +umem_release(void) +{ + umem_do_release(0); +} + +static void +umem_release_child(void) +{ + umem_do_release(1); } -#endif void umem_forkhandler_init(void) { -#ifndef _WIN32 /* * There is no way to unregister these atfork functions, * but we don't need to. The dynamic linker and libc take * care of unregistering them if/when the library is unloaded. */ (void) pthread_atfork(umem_lockup, umem_release, umem_release_child); -#endif } diff --git a/zfs/lib/libumem/umem_update_thread.c b/zfs/lib/libumem/umem_update_thread.c index 033d606be..178c6e733 100644 --- a/zfs/lib/libumem/umem_update_thread.c +++ b/zfs/lib/libumem/umem_update_thread.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,30 +18,22 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)umem_update_thread.c 1.2 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" #include "umem_base.h" #include "vmem_base.h" #include <signal.h> -/* - * we use the _ version, since we don't want to be cancelled. - */ -extern int _cond_timedwait(cond_t *cv, mutex_t *mutex, const timespec_t *delay); - /*ARGSUSED*/ -static THR_RETURN -THR_API umem_update_thread(void *arg) +static void * +umem_update_thread(void *arg) { struct timeval now; int in_update = 0; @@ -110,12 +101,16 @@ THR_API umem_update_thread(void *arg) * next update, or someone wakes us. */ if (umem_null_cache.cache_unext == &umem_null_cache) { + int cancel_state; timespec_t abs_time; abs_time.tv_sec = umem_update_next.tv_sec; abs_time.tv_nsec = umem_update_next.tv_usec * 1000; - (void) _cond_timedwait(&umem_update_cv, + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, + &cancel_state); + (void) cond_timedwait(&umem_update_cv, &umem_update_lock, &abs_time); + (void) pthread_setcancelstate(cancel_state, NULL); } } /* LINTED no return statement */ @@ -124,30 +119,47 @@ THR_API umem_update_thread(void *arg) int umem_create_update_thread(void) { -#ifndef _WIN32 sigset_t sigmask, oldmask; -#endif + thread_t newthread; ASSERT(MUTEX_HELD(&umem_update_lock)); ASSERT(umem_update_thr == 0); -#ifndef _WIN32 /* * The update thread handles no signals */ (void) sigfillset(&sigmask); (void) thr_sigsetmask(SIG_BLOCK, &sigmask, &oldmask); -#endif - if (thr_create(NULL, 0, umem_update_thread, NULL, - THR_BOUND | THR_DAEMON | THR_DETACHED, &umem_update_thr) == 0) { -#ifndef _WIN32 + + /* + * drop the umem_update_lock; we cannot hold locks acquired in + * pre-fork handler while calling thr_create or thr_continue(). + */ + + (void) mutex_unlock(&umem_update_lock); + + if (thr_create(NULL, NULL, umem_update_thread, NULL, + THR_BOUND | THR_DAEMON | THR_DETACHED | THR_SUSPENDED, + &newthread) == 0) { (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); -#endif + + (void) mutex_lock(&umem_update_lock); + /* + * due to the locking in umem_reap(), only one thread can + * ever call umem_create_update_thread() at a time. This + * must be the case for this code to work. + */ + + ASSERT(umem_update_thr == 0); + umem_update_thr = newthread; + (void) mutex_unlock(&umem_update_lock); + (void) thr_continue(newthread); + (void) mutex_lock(&umem_update_lock); + return (1); + } else { /* thr_create failed */ + (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); + (void) mutex_lock(&umem_update_lock); } - umem_update_thr = 0; -#ifndef _WIN32 - (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); -#endif return (0); } diff --git a/zfs/lib/libumem/vmem.c b/zfs/lib/libumem/vmem.c index 1b8981a91..040517a78 100644 --- a/zfs/lib/libumem/vmem.c +++ b/zfs/lib/libumem/vmem.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,13 +18,12 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* #pragma ident "@(#)vmem.c 1.10 05/06/08 SMI" */ - /* * For a more complete description of the main ideas, see: * @@ -37,7 +35,7 @@ * Proceedings of the 2001 Usenix Conference. * Available as /shared/sac/PSARC/2000/550/materials/vmem.pdf. * - * For the "Big Theory Statement", see usr/src/common/os/vmem.c + * For the "Big Theory Statement", see usr/src/uts/common/os/vmem.c * * 1. Overview of changes * ------------------------------ @@ -108,22 +106,12 @@ * sorted in address order. */ -#include "config.h" -/* #include "mtlib.h" */ #include <sys/vmem_impl_user.h> -#if HAVE_ALLOCA_H #include <alloca.h> -#endif -#ifdef HAVE_SYS_SYSMACROS_H #include <sys/sysmacros.h> -#endif #include <stdio.h> -#if HAVE_STRINGS_H #include <strings.h> -#endif -#if HAVE_ATOMIC_H #include <atomic.h> -#endif #include "vmem_base.h" #include "umem_base.h" @@ -210,12 +198,9 @@ static uint32_t vmem_id; static uint32_t vmem_populators; static vmem_seg_t vmem_seg0[VMEM_SEG_INITIAL]; static vmem_seg_t *vmem_segfree; -static mutex_t vmem_list_lock = DEFAULTMUTEX; -static mutex_t vmem_segfree_lock = DEFAULTMUTEX; -static vmem_populate_lock_t vmem_nosleep_lock = { - DEFAULTMUTEX, - 0 -}; +static mutex_t vmem_list_lock; +static mutex_t vmem_segfree_lock; +static vmem_populate_lock_t vmem_nosleep_lock; #define IN_POPULATE() (vmem_nosleep_lock.vmpl_thr == thr_self()) static vmem_t *vmem_list; static vmem_t *vmem_internal_arena; @@ -231,12 +216,6 @@ uint32_t vmem_mtbf; /* mean time between failures [default: off] */ size_t vmem_seg_size = sizeof (vmem_seg_t); /* - * we use the _ version, since we don't want to be cancelled. - * Actually, this is automatically taken care of by including "mtlib.h". - */ -extern int _cond_wait(cond_t *cv, mutex_t *mutex); - -/* * Insert/delete from arena list (type 'a') or next-of-kin list (type 'k'). */ #define VMEM_INSERT(vprev, vsp, type) \ @@ -775,6 +754,8 @@ vmem_nextfit_alloc(vmem_t *vmp, size_t size, int vmflag) break; vsp = vsp->vs_anext; if (vsp == rotor) { + int cancel_state; + /* * We've come full circle. One possibility is that the * there's actually enough space, but the rotor itself @@ -799,7 +780,10 @@ vmem_nextfit_alloc(vmem_t *vmp, size_t size, int vmflag) 0, 0, NULL, NULL, vmflag & VM_UMFLAGS)); } vmp->vm_kstat.vk_wait++; - (void) _cond_wait(&vmp->vm_cv, &vmp->vm_lock); + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, + &cancel_state); + (void) cond_wait(&vmp->vm_cv, &vmp->vm_lock); + (void) pthread_setcancelstate(cancel_state, NULL); vsp = rotor->vs_anext; } } @@ -867,6 +851,8 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase, (void) mutex_lock(&vmp->vm_lock); for (;;) { + int cancel_state; + if (vmp->vm_nsegfree < VMEM_MINFREE && !vmem_populate(vmp, vmflag)) break; @@ -930,7 +916,7 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase, start = MAX(vsp->vs_start, (uintptr_t)minaddr); end = MIN(vsp->vs_end - 1, (uintptr_t)maxaddr - 1) + 1; taddr = P2PHASEUP(start, align, phase); - if (P2CROSS(taddr, taddr + size - 1, nocross)) + if (P2BOUNDARY(taddr, size, nocross)) taddr += P2ROUNDUP(P2NPHASE(taddr, nocross), align); if ((taddr - start) + size > end - start || @@ -986,7 +972,10 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase, if (vmflag & VM_NOSLEEP) break; vmp->vm_kstat.vk_wait++; - (void) _cond_wait(&vmp->vm_cv, &vmp->vm_lock); + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, + &cancel_state); + (void) cond_wait(&vmp->vm_cv, &vmp->vm_lock); + (void) pthread_setcancelstate(cancel_state, NULL); } if (vbest != NULL) { ASSERT(vbest->vs_type == VMEM_FREE); @@ -994,7 +983,7 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase, (void) vmem_seg_alloc(vmp, vbest, addr, size); (void) mutex_unlock(&vmp->vm_lock); ASSERT(P2PHASE(addr, align) == phase); - ASSERT(!P2CROSS(addr, addr + size - 1, nocross)); + ASSERT(!P2BOUNDARY(addr, size, nocross)); ASSERT(addr >= (uintptr_t)minaddr); ASSERT(addr + size - 1 <= (uintptr_t)maxaddr - 1); return ((void *)addr); diff --git a/zfs/lib/libumem/vmem_base.c b/zfs/lib/libumem/vmem_base.c index d43ecded4..6b1c07e1b 100644 --- a/zfs/lib/libumem/vmem_base.c +++ b/zfs/lib/libumem/vmem_base.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,15 +18,14 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* #pragma ident "@(#)vmem_base.c 1.6 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -/* #include "mtlib.h" */ -#include "config.h" #include "vmem_base.h" #include "umem_base.h" diff --git a/zfs/lib/libumem/vmem_mmap.c b/zfs/lib/libumem/vmem_mmap.c index f59e48dc1..41c1ee5e7 100644 --- a/zfs/lib/libumem/vmem_mmap.c +++ b/zfs/lib/libumem/vmem_mmap.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,29 +18,18 @@ * * CDDL HEADER END */ + /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)vmem_mmap.c 1.2 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" -#include "config.h" +#include <unistd.h> #include <errno.h> - -#if HAVE_SYS_MMAN_H #include <sys/mman.h> -#endif - -#ifdef HAVE_SYS_SYSMACROS_H #include <sys/sysmacros.h> -#endif - -#include <unistd.h> - #include "vmem_base.h" #define ALLOC_PROT PROT_READ | PROT_WRITE | PROT_EXEC @@ -50,11 +38,7 @@ #define ALLOC_FLAGS MAP_PRIVATE | MAP_ANON #define FREE_FLAGS MAP_PRIVATE | MAP_ANON | MAP_NORESERVE -#ifdef MAP_ALIGN #define CHUNKSIZE (64*1024) /* 64 kilobytes */ -#else -static size_t CHUNKSIZE; -#endif static vmem_t *mmap_heap; @@ -65,12 +49,9 @@ vmem_mmap_alloc(vmem_t *src, size_t size, int vmflags) int old_errno = errno; ret = vmem_alloc(src, size, vmflags); -#ifndef _WIN32 - if (ret != NULL - && + if (ret != NULL && mmap(ret, size, ALLOC_PROT, ALLOC_FLAGS | MAP_FIXED, -1, 0) == - MAP_FAILED - ) { + MAP_FAILED) { vmem_free(src, ret, size); vmem_reap(); @@ -78,7 +59,6 @@ vmem_mmap_alloc(vmem_t *src, size_t size, int vmflags) errno = old_errno; return (NULL); } -#endif errno = old_errno; return (ret); @@ -88,11 +68,7 @@ static void vmem_mmap_free(vmem_t *src, void *addr, size_t size) { int old_errno = errno; -#ifdef _WIN32 - VirtualFree(addr, size, MEM_RELEASE); -#else (void) mmap(addr, size, FREE_PROT, FREE_FLAGS | MAP_FIXED, -1, 0); -#endif vmem_free(src, addr, size); errno = old_errno; } @@ -113,22 +89,8 @@ vmem_mmap_top_alloc(vmem_t *src, size_t size, int vmflags) /* * Need to grow the heap */ -#ifdef _WIN32 - buf = VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - if (buf == NULL) buf = MAP_FAILED; -#else - buf = mmap( -#ifdef MAP_ALIGN - (void *)CHUNKSIZE, -#else - 0, -#endif - size, FREE_PROT, FREE_FLAGS -#ifdef MAP_ALIGN - | MAP_ALIGN -#endif - , -1, 0); -#endif + buf = mmap((void *)CHUNKSIZE, size, FREE_PROT, FREE_FLAGS | MAP_ALIGN, + -1, 0); if (buf != MAP_FAILED) { ret = _vmem_extend_alloc(src, buf, size, size, vmflags); @@ -154,24 +116,10 @@ vmem_mmap_top_alloc(vmem_t *src, size_t size, int vmflags) vmem_t * vmem_mmap_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) { -#ifdef _WIN32 - SYSTEM_INFO info; - size_t pagesize; -#else - size_t pagesize = _sysconf(_SC_PAGESIZE); -#endif - -#ifdef _WIN32 - GetSystemInfo(&info); - pagesize = info.dwPageSize; - CHUNKSIZE = info.dwAllocationGranularity; -#elif !defined(MAP_ALIGN) - CHUNKSIZE = pagesize; -#endif - + size_t pagesize = sysconf(_SC_PAGESIZE); + if (mmap_heap == NULL) { - mmap_heap = vmem_init("mmap_top", - CHUNKSIZE, + mmap_heap = vmem_init("mmap_top", CHUNKSIZE, vmem_mmap_top_alloc, vmem_free, "mmap_heap", NULL, 0, pagesize, vmem_mmap_alloc, vmem_mmap_free); diff --git a/zfs/lib/libumem/vmem_sbrk.c b/zfs/lib/libumem/vmem_sbrk.c index a7c91bbbd..20bfb7345 100644 --- a/zfs/lib/libumem/vmem_sbrk.c +++ b/zfs/lib/libumem/vmem_sbrk.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,15 +18,13 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Portions Copyright 2006 OmniTI, Inc. - */ -/* #pragma ident "@(#)vmem_sbrk.c 1.4 05/06/08 SMI" */ +#pragma ident "%Z%%M% %I% %E% SMI" /* * The structure of the sbrk backend: @@ -54,13 +51,9 @@ * before calling sbrk(). */ -#include "config.h" -/* #include "mtlib.h" */ #include <errno.h> #include <limits.h> -#ifdef HAVE_SYS_SYSMACROS_H #include <sys/sysmacros.h> -#endif #include <sys/mman.h> #include <unistd.h> @@ -70,7 +63,8 @@ size_t vmem_sbrk_pagesize = 0; /* the preferred page size of the heap */ -#define MIN_ALLOC (64*1024) +#define VMEM_SBRK_MINALLOC (64 * 1024) +size_t vmem_sbrk_minalloc = VMEM_SBRK_MINALLOC; /* minimum allocation */ static size_t real_pagesize; static vmem_t *sbrk_heap; @@ -92,59 +86,6 @@ static sbrk_fail_t sbrk_fails = { static mutex_t sbrk_faillock = DEFAULTMUTEX; /* - * _sbrk_grow_aligned() aligns the old break to a low_align boundry, - * adds min_size, aligns to a high_align boundry, and calls _brk_unlocked() - * to set the new break. The low_aligned-aligned value is returned, and - * the actual space allocated is returned through actual_size. - * - * Unlike sbrk(2), _sbrk_grow_aligned takes an unsigned size, and does - * not allow shrinking the heap. - */ -void * -_sbrk_grow_aligned(size_t min_size, size_t low_align, size_t high_align, - size_t *actual_size) -{ - uintptr_t old_brk; - uintptr_t ret_brk; - uintptr_t high_brk; - uintptr_t new_brk; - int brk_result; - -#define ALIGNSZ 16 -#define BRKALIGN(x) (caddr_t)P2ROUNDUP((uintptr_t)(x), ALIGNSZ) - - if ((low_align & (low_align - 1)) != 0 || - (high_align & (high_align - 1)) != 0) { - errno = EINVAL; - return ((void *)-1); - } - low_align = MAX(low_align, ALIGNSZ); - high_align = MAX(high_align, ALIGNSZ); - - old_brk = (uintptr_t)BRKALIGN(sbrk(0)); - ret_brk = P2ROUNDUP(old_brk, low_align); - high_brk = ret_brk + min_size; - new_brk = P2ROUNDUP(high_brk, high_align); - - /* - * Check for overflow - */ - if (ret_brk < old_brk || high_brk < ret_brk || new_brk < high_brk) { - errno = ENOMEM; - return ((void *)-1); - } - - brk_result = brk((void *)new_brk); - - if (brk_result != 0) - return ((void *)-1); - - if (actual_size != NULL) - *actual_size = (new_brk - ret_brk); - return ((void *)ret_brk); -} - -/* * Try to extend src with [pos, pos + size). * * If it fails, add the block to the sbrk_fails list. @@ -234,7 +175,7 @@ vmem_sbrk_alloc(vmem_t *src, size_t size, int vmflags) (ret = vmem_sbrk_tryfail(src, size, vmflags)) != NULL) return (ret); - buf_size = MAX(size, MIN_ALLOC); + buf_size = MAX(size, vmem_sbrk_minalloc); /* * buf_size gets overwritten with the actual allocated size @@ -293,7 +234,6 @@ vmem_sbrk_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) if (heap_size <= real_pagesize) { heap_size = real_pagesize; } else { -#ifdef MHA_MAPSIZE_BSSBRK struct memcntl_mha mha; mha.mha_cmd = MHA_MAPSIZE_BSSBRK; mha.mha_flags = 0; @@ -305,12 +245,14 @@ vmem_sbrk_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) "0x%p\n", heap_size); heap_size = real_pagesize; } -#else - heap_size = real_pagesize; -#endif } vmem_sbrk_pagesize = heap_size; + /* validate vmem_sbrk_minalloc */ + if (vmem_sbrk_minalloc < VMEM_SBRK_MINALLOC) + vmem_sbrk_minalloc = VMEM_SBRK_MINALLOC; + vmem_sbrk_minalloc = P2ROUNDUP(vmem_sbrk_minalloc, heap_size); + sbrk_heap = vmem_init("sbrk_top", real_pagesize, vmem_sbrk_alloc, vmem_free, "sbrk_heap", NULL, 0, real_pagesize, diff --git a/zfs/lib/libumem/vmem_stand.c b/zfs/lib/libumem/vmem_stand.c new file mode 100644 index 000000000..da19043df --- /dev/null +++ b/zfs/lib/libumem/vmem_stand.c @@ -0,0 +1,164 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Standalone-specific vmem routines + * + * The standalone allocator operates on a pre-existing blob of memory, the + * location and dimensions of which are set using vmem_stand_setsize(). We + * then hand out CHUNKSIZE-sized pieces of this blob, until we run out. + */ + +#define DEF_CHUNKSIZE (64 * 1024) /* 64K */ + +#define DEF_NREGIONS 2 + +#include <errno.h> +#include <limits.h> +#include <sys/sysmacros.h> +#include <sys/mman.h> +#include <unistd.h> +#include <strings.h> + +#include "vmem_base.h" +#include "misc.h" + +static vmem_t *stand_heap; + +static size_t stand_chunksize; + +typedef struct stand_region { + caddr_t sr_base; + caddr_t sr_curtop; + size_t sr_left; +} stand_region_t; + +static stand_region_t stand_regions[DEF_NREGIONS]; +static int stand_nregions; + +extern void membar_producer(void); + +void +vmem_stand_init(void) +{ + stand_chunksize = MAX(DEF_CHUNKSIZE, pagesize); + + stand_nregions = 0; +} + +int +vmem_stand_add(caddr_t base, size_t len) +{ + stand_region_t *sr = &stand_regions[stand_nregions]; + + ASSERT(pagesize != 0); + + if (stand_nregions == DEF_NREGIONS) { + errno = ENOSPC; + return (-1); /* we don't have room -- throw it back */ + } + + /* + * We guarantee that only one call to `vmem_stand_add' will be + * active at a time, but we can't ensure that the allocator won't be + * in use while this function is being called. As such, we have to + * ensure that sr is populated and visible to other processors before + * allowing the allocator to access the new region. + */ + sr->sr_base = base; + sr->sr_curtop = (caddr_t)P2ROUNDUP((ulong_t)base, stand_chunksize); + sr->sr_left = P2ALIGN(len - (size_t)(sr->sr_curtop - sr->sr_base), + stand_chunksize); + membar_producer(); + + stand_nregions++; + + return (0); +} + +static void * +stand_parent_alloc(vmem_t *src, size_t size, int vmflags) +{ + int old_errno = errno; + stand_region_t *sr; + size_t chksize; + void *ret; + int i; + + if ((ret = vmem_alloc(src, size, VM_NOSLEEP)) != NULL) { + errno = old_errno; + return (ret); + } + + /* We need to allocate another chunk */ + chksize = roundup(size, stand_chunksize); + + for (sr = stand_regions, i = 0; i < stand_nregions; i++, sr++) { + if (sr->sr_left >= chksize) + break; + } + + if (i == stand_nregions) { + /* + * We don't have enough in any of our regions to satisfy the + * request. + */ + errno = old_errno; + return (NULL); + } + + if ((ret = _vmem_extend_alloc(src, sr->sr_curtop, chksize, size, + vmflags)) == NULL) { + errno = old_errno; + return (NULL); + } + + bzero(sr->sr_curtop, chksize); + + sr->sr_curtop += chksize; + sr->sr_left -= chksize; + + return (ret); +} + +vmem_t * +vmem_stand_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) +{ + ASSERT(stand_nregions == 1); + + stand_heap = vmem_init("stand_parent", stand_chunksize, + stand_parent_alloc, vmem_free, + "stand_heap", NULL, 0, pagesize, vmem_alloc, vmem_free); + + if (a_out != NULL) + *a_out = vmem_alloc; + if (f_out != NULL) + *f_out = vmem_free; + + return (stand_heap); +} |