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 ]) diff --git a/lib/libzpool/include/sys/zfs_context.h b/lib/libzpool/include/sys/zfs_context.h index fad26f3e94..3f5a078ecc 100644 --- a/lib/libzpool/include/sys/zfs_context.h +++ b/lib/libzpool/include/sys/zfs_context.h @@ -211,6 +211,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 a4252c6310..b657d124c3 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -162,8 +162,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);