diff options
author | Brian Behlendorf <[email protected]> | 2014-09-25 15:15:45 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2014-09-30 10:46:55 -0700 |
commit | aa0ac7caa438bf3981456c559d4224be104ccc7d (patch) | |
tree | f3ddd427d47ad3d28535be3067bbdc4c9f239970 | |
parent | cb08f063074a5363810a39775fd90a4d214c5d87 (diff) |
Make user stack limit configurable
To aid in detecting and debugging stack overflow issues make the
user space stack limit configurable via a new ZFS_STACK_SIZE
environment variable. The value assigned to ZFS_STACK_SIZE will
be used as the default stack size in bytes.
Because this is mainly useful as a debugging aid in conjunction
with ztest the stack limit is disabled by default. See the ztest(1)
man page for additional details on using the ZFS_STACK_SIZE
environment variable.
Signed-off-by: Brian Behlendorf <[email protected]>
Signed-off-by: Ned Bass <[email protected]>
Closes #2743
Issue #2293
-rw-r--r-- | include/sys/zfs_context.h | 13 | ||||
-rw-r--r-- | lib/libzpool/kernel.c | 48 | ||||
-rw-r--r-- | man/man1/ztest.1 | 16 |
3 files changed, 47 insertions, 30 deletions
diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index bbb8a0463..f26c827dc 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -203,16 +203,17 @@ extern void vpanic(const char *, va_list); #else #define SET_ERROR(err) (err) #endif + /* - * Threads + * Threads. TS_STACK_MIN is dictated by the minimum allowed pthread stack + * size. While TS_STACK_MAX is somewhat arbitrary, it was selected to be + * large enough for the expected stack depth while small enough to avoid + * exhausting address space with high thread counts. */ #define TS_MAGIC 0x72f158ab4261e538ull #define TS_RUN 0x00000002 -#ifdef __linux__ -#define STACK_SIZE 8192 /* Linux x86 and amd64 */ -#else -#define STACK_SIZE 24576 /* Solaris */ -#endif +#define TS_STACK_MIN PTHREAD_STACK_MIN +#define TS_STACK_MAX (256 * 1024) /* in libzpool, p0 exists only to have its address taken */ typedef struct proc { diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 03fbe3dd0..5adcfa617 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -146,41 +146,41 @@ zk_thread_create(caddr_t stk, size_t stksize, thread_func_t func, void *arg, { kthread_t *kt; pthread_attr_t attr; - size_t stack; + char *stkstr; - ASSERT3S(state & ~TS_RUN, ==, 0); + ASSERT0(state & ~TS_RUN); kt = umem_zalloc(sizeof (kthread_t), UMEM_NOFAIL); kt->t_func = func; kt->t_arg = arg; + VERIFY0(pthread_attr_init(&attr)); + VERIFY0(pthread_attr_setdetachstate(&attr, detachstate)); + /* - * The Solaris kernel stack size is 24k for x86/x86_64. - * The Linux kernel stack size is 8k for x86/x86_64. - * - * We reduce the default stack size in userspace, to ensure - * we observe stack overruns in user space as well as in - * kernel space. In practice we can't set the userspace stack - * size to 8k because differences in stack usage between kernel - * space and userspace could lead to spurious stack overflows - * (especially when debugging is enabled). Nevertheless, we try - * to set it to the lowest value that works (currently 8k*4). - * PTHREAD_STACK_MIN is the minimum stack required for a NULL - * procedure in user space and is added in to the stack - * requirements. + * We allow the default stack size in user space to be specified by + * setting the ZFS_STACK_SIZE environment variable. This allows us + * the convenience of observing and debugging stack overruns in + * user space. Explicitly specified stack sizes will be honored. + * The usage of ZFS_STACK_SIZE is discussed further in the + * ENVIRONMENT VARIABLES sections of the ztest(1) man page. */ + if (stksize == 0) { + stkstr = getenv("ZFS_STACK_SIZE"); - stack = PTHREAD_STACK_MIN + MAX(stksize, STACK_SIZE) * 4; - - VERIFY3S(pthread_attr_init(&attr), ==, 0); - VERIFY3S(pthread_attr_setstacksize(&attr, stack), ==, 0); - VERIFY3S(pthread_attr_setguardsize(&attr, PAGESIZE), ==, 0); - VERIFY3S(pthread_attr_setdetachstate(&attr, detachstate), ==, 0); + if (stkstr == NULL) + stksize = TS_STACK_MAX; + else + stksize = MAX(atoi(stkstr), TS_STACK_MIN); + } - VERIFY3S(pthread_create(&kt->t_tid, &attr, &zk_thread_helper, kt), - ==, 0); + VERIFY3S(stksize, >, 0); + stksize = P2ROUNDUP(MAX(stksize, TS_STACK_MIN), PAGESIZE); + VERIFY0(pthread_attr_setstacksize(&attr, stksize)); + VERIFY0(pthread_attr_setguardsize(&attr, PAGESIZE)); - VERIFY3S(pthread_attr_destroy(&attr), ==, 0); + VERIFY0(pthread_create(&kt->t_tid, &attr, &zk_thread_helper, kt)); + VERIFY0(pthread_attr_destroy(&attr)); return (kt); } diff --git a/man/man1/ztest.1 b/man/man1/ztest.1 index 961a5b0de..f798bcfcb 100644 --- a/man/man1/ztest.1 +++ b/man/man1/ztest.1 @@ -144,6 +144,22 @@ Maybe you'd like to run ztest for longer? To do so simply use the -T option and specify the runlength in seconds like so: .IP ztest -f / -V -T 120 + +.SH "ENVIRONMENT VARIABLES" +.TP +.B "ZFS_STACK_SIZE=stacksize" +Limit the default stack size to \fBstacksize\fR bytes for the purpose of +detecting and debugging kernel stack overflows. For x86_64 platforms this +value should be set as follows to simulate these platforms: \fB8192\fR +(Linux), \fB20480\fR (Illumos), \fB16384\fR (FreeBSD). + +In practice you may need to set these value slightly higher because +differences in stack usage between kernel and user space can lead to spurious +stack overflows (especially when debugging is enabled). The specified value +will be rounded up to a floor of PTHREAD_STACK_MIN which is the minimum stack +required for a NULL procedure in user space. + +By default the stack size is limited to 256K. .SH "SEE ALSO" .BR "zpool (1)" "," .BR "zfs (1)" "," |