]> granicus.if.org Git - zfs/commitdiff
Make user stack limit configurable
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 25 Sep 2014 22:15:45 +0000 (15:15 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 30 Sep 2014 17:46:55 +0000 (10:46 -0700)
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 <behlendorf1@llnl.gov>
Signed-off-by: Ned Bass <bass6@llnl.gov>
Closes #2743
Issue #2293

include/sys/zfs_context.h
lib/libzpool/kernel.c
man/man1/ztest.1

index bbb8a0463d9375e57a67758d13ec15e5366edb7d..f26c827dc76dbe5be94a542d15523997514054b0 100644 (file)
@@ -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 {
index 03fbe3dd0c304530ba9c40c113d7555d77da9887..5adcfa617ab89cbb574d257a04ee0ec848cc9eb2 100644 (file)
@@ -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);
 }
index 961a5b0de4045ef3d1080b19f375e300afe5dcc7..f798bcfcb8e8152493423b5b6dc41074dac7317f 100644 (file)
@@ -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)" ","