From 16a9f681372ef42c0a29fb0fb82f19eab8c3f61f Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Wed, 21 Jul 2010 18:53:14 -0700 Subject: [PATCH 1/2] Autoconf check for buggy stack guard region Some buggy NPTL threading implementations include the guard area within the stack size allocations. In this case we need to allocate an extra page to account for the guard area since we only have two pages of usable stack on Linux. Added an autoconf test that detects such implementations by running a test program designed to segfault if the bug is present. Set a flag NPTL_GUARD_WITHIN_STACK that is tested to decide if extra stack space must be allocated for the guard area. Signed-off-by: Brian Behlendorf --- config/user-nptl_guard_within_stack.m4 | 56 ++++++++++++++++++++++++++ config/user.m4 | 1 + 2 files changed, 57 insertions(+) create mode 100644 config/user-nptl_guard_within_stack.m4 diff --git a/config/user-nptl_guard_within_stack.m4 b/config/user-nptl_guard_within_stack.m4 new file mode 100644 index 0000000000..d094da7332 --- /dev/null +++ b/config/user-nptl_guard_within_stack.m4 @@ -0,0 +1,56 @@ +dnl # +dnl # Check if the glibc NPTL threading implementation includes the guard area +dnl # within the stack size allocation, rather than allocating extra space at +dnl # the end of the stack, as POSIX.1 requires. +dnl # +AC_DEFUN([ZFS_AC_CONFIG_USER_STACK_GUARD], [ + + AC_MSG_CHECKING([whether pthread stack includes guard]) + + saved_CFLAGS="$CFLAGS" + CFLAGS="-fstack-check" + saved_LDFLAGS="$LDFLAGS" + LDFLAGS="-lpthread" + + AC_RUN_IFELSE(AC_LANG_PROGRAM( + [ + #include + #include + #include + #include + + #define PAGESIZE (sysconf(_SC_PAGESIZE)) + #define STACK_SIZE 8192 + #define BUFSIZE 4096 + + void * func(void *arg) + { + char buf[[[BUFSIZE]]]; + } + ], + [ + pthread_t tid; + pthread_attr_t attr; + struct rlimit l; + + l.rlim_cur = 0; + l.rlim_max = 0; + setrlimit(RLIMIT_CORE, &l); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + STACK_SIZE); + pthread_attr_setguardsize(&attr, PAGESIZE); + pthread_create(&tid, &attr, func, NULL); + pthread_join(tid, NULL); + ]), + [ + AC_MSG_RESULT([no]) + ], + [ + AC_DEFINE([NPTL_GUARD_WITHIN_STACK], 1, + [Define to 1 if NPTL threading implementation includes + guard area in stack allocation]) + AC_MSG_RESULT([yes]) + ]) + CFLAGS="$saved_CFLAGS" + LDFLAGS="$saved_LDFLAGS" +]) diff --git a/config/user.m4 b/config/user.m4 index 2f9825ce0d..bc68808f80 100644 --- a/config/user.m4 +++ b/config/user.m4 @@ -9,4 +9,5 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [ ZFS_AC_CONFIG_USER_LIBUUID ZFS_AC_CONFIG_USER_LIBBLKID ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN + ZFS_AC_CONFIG_USER_STACK_GUARD ]) From be92edb218960bca9af582e1e8476610e4d1057e Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Wed, 21 Jul 2010 18:53:14 -0700 Subject: [PATCH 2/2] Add extra guard space if needed Some buggy NPTL threading implementations include the guard area within the stack size allocations. In this case we need to allocate an extra page to account for the guard area since we only have two pages of usable stack on Linux. Added an autoconf test that detects such implementations by running a test program designed to segfault if the bug is present. Set a flag NPTL_GUARD_WITHIN_STACK that is tested to decide if extra stack space must be allocated for the guard area. Signed-off-by: Brian Behlendorf --- lib/libzpool/include/sys/zfs_context.h | 6 ++++++ lib/libzpool/kernel.c | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/libzpool/include/sys/zfs_context.h b/lib/libzpool/include/sys/zfs_context.h index f837440c06..e211286c6b 100644 --- a/lib/libzpool/include/sys/zfs_context.h +++ b/lib/libzpool/include/sys/zfs_context.h @@ -205,6 +205,12 @@ _NOTE(CONSTCOND) } while (0) #define STACK_SIZE 24576 /* Solaris */ #endif +#ifdef NPTL_GUARD_WITHIN_STACK +#define EXTRA_GUARD_BYTES PAGESIZE +#else +#define EXTRA_GUARD_BYTES 0 +#endif + /* in libzpool, p0 exists only to have its address taken */ typedef struct proc { uintptr_t this_is_never_used_dont_dereference_it; diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 2c9d32be82..04f4bf3548 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -163,8 +163,16 @@ zk_thread_create(caddr_t stk, size_t stksize, thread_func_t func, void *arg, * kernel space. PTHREAD_STACK_MIN is the minimum stack * required for a NULL procedure in user space and is added * in to the stack requirements. + * + * Some buggy NPTL threading implementations include the + * guard area within the stack size allocations. In + * this case we allocate an extra page to account for the + * guard area since we only have two pages of usable stack + * on Linux. */ - stack = PTHREAD_STACK_MIN + MAX(stksize, STACK_SIZE); + + stack = PTHREAD_STACK_MIN + MAX(stksize, STACK_SIZE) + + EXTRA_GUARD_BYTES; VERIFY3S(pthread_attr_init(&attr), ==, 0); VERIFY3S(pthread_attr_setstacksize(&attr, stack), ==, 0);