From 421d95b3eae80b18666761c3d97d2f6f3a2994b8 Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Thu, 29 Jul 2010 16:28:34 -0700 Subject: [PATCH 1/8] Remove declarations in VERIFY3_IMPL to save stack This has a minor impact on stack usage of individual functions, but the VERIFY macros are used so frequently that their overhead may add up. This macro declared two new local variables to cast its argument types. Doing the typecast inline eliminates the need for these variables. Signed-off-by: Brian Behlendorf --- lib/libspl/include/assert.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/libspl/include/assert.h b/lib/libspl/include/assert.h index 7f145b89a3..ace72fb35b 100644 --- a/lib/libspl/include/assert.h +++ b/lib/libspl/include/assert.h @@ -65,13 +65,11 @@ extern void __assert(const char *, const char *, int); /* BEGIN CSTYLED */ #define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE) do { \ - const TYPE __left = (TYPE)(LEFT); \ - const TYPE __right = (TYPE)(RIGHT); \ - if (!(__left OP __right)) { \ + if (!((TYPE)(LEFT) OP (TYPE)(RIGHT))) { \ char *__buf = alloca(256); \ (void) snprintf(__buf, 256, "%s %s %s (0x%llx %s 0x%llx)", \ #LEFT, #OP, #RIGHT, \ - (u_longlong_t)__left, #OP, (u_longlong_t)__right); \ + (u_longlong_t)(LEFT), #OP, (u_longlong_t)(RIGHT)); \ __assert(__buf, __FILE__, __LINE__); \ } \ } while (0) From bb20b030606457a0a76bcef64c2e35a218857a33 Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Wed, 28 Jul 2010 18:46:45 -0700 Subject: [PATCH 2/8] Move ztest_od_t structures to the heap A number of ztest functions create one or more 312B ztest_od_t data structures. To conserve stack usage, this commit moves all of these data structures to the heap. However, I am still seeing ztest segfaults due to heavy stack usage of the dbuf_findbp() -> dbuf_hold_impl() recursion. Signed-off-by: Brian Behlendorf --- cmd/ztest/ztest.c | 155 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 48 deletions(-) diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index f090295e9a..cac284d1ab 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -3199,6 +3199,7 @@ out: umem_free(snap3name, MAXNAMELEN); } +#undef OD_ARRAY_SIZE #define OD_ARRAY_SIZE 4 /* @@ -3232,14 +3233,21 @@ ztest_dmu_object_alloc_free(ztest_ds_t *zd, uint64_t id) umem_free(od, size); } +#undef OD_ARRAY_SIZE +#define OD_ARRAY_SIZE 2 + /* * Verify that dmu_{read,write} work as expected. */ void ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) { + int size; + ztest_od_t *od; + objset_t *os = zd->zd_os; - ztest_od_t od[2]; + size = sizeof(ztest_od_t) * OD_ARRAY_SIZE; + od = umem_alloc(size, UMEM_NOFAIL); dmu_tx_t *tx; int i, freeit, error; uint64_t n, s, txg; @@ -3278,11 +3286,13 @@ ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) /* * Read the directory info. If it's the first time, set things up. */ - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, chunksize); - ztest_od_init(&od[1], id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, chunksize); + ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, chunksize); + ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, chunksize); - if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0) + if (ztest_object_init(zd, od, size, B_FALSE) != 0) { + umem_free(od, size); return; + } bigobj = od[0].od_object; packobj = od[1].od_object; @@ -3346,6 +3356,7 @@ ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) if (txg == 0) { umem_free(packbuf, packsize); umem_free(bigbuf, bigsize); + umem_free(od, size); return; } @@ -3446,6 +3457,7 @@ ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) umem_free(packbuf, packsize); umem_free(bigbuf, bigsize); + umem_free(od, size); } void @@ -3497,14 +3509,18 @@ compare_and_update_pbbufs(uint64_t s, bufwad_t *packbuf, bufwad_t *bigbuf, } } +#undef OD_ARRAY_SIZE +#define OD_ARRAY_SIZE 2 + void ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; - ztest_od_t od[2]; + ztest_od_t *od; dmu_tx_t *tx; uint64_t i; int error; + int size; uint64_t n, s, txg; bufwad_t *packbuf, *bigbuf; uint64_t packobj, packoff, packsize, bigobj, bigoff, bigsize; @@ -3517,6 +3533,9 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) arc_buf_t **bigbuf_arcbufs; dmu_object_info_t doi; + size = sizeof(ztest_od_t) * OD_ARRAY_SIZE; + od = umem_alloc(size, UMEM_NOFAIL); + /* * This test uses two objects, packobj and bigobj, that are always * updated together (i.e. in the same tx) so that their contents are @@ -3536,11 +3555,14 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) /* * Read the directory info. If it's the first time, set things up. */ - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0); - ztest_od_init(&od[1], id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, chunksize); + ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0); + ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, chunksize); - if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0) + + if (ztest_object_init(zd, od, size, B_FALSE) != 0) { + umem_free(od, size); return; + } bigobj = od[0].od_object; packobj = od[1].od_object; @@ -3626,6 +3648,7 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) } } umem_free(bigbuf_arcbufs, 2 * s * sizeof (arc_buf_t *)); + umem_free(od, size); dmu_buf_rele(bonus_db, FTAG); return; } @@ -3722,13 +3745,16 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) umem_free(packbuf, packsize); umem_free(bigbuf, bigsize); umem_free(bigbuf_arcbufs, 2 * s * sizeof (arc_buf_t *)); + umem_free(od, size); } /* ARGSUSED */ void ztest_dmu_write_parallel(ztest_ds_t *zd, uint64_t id) { - ztest_od_t od[1]; + ztest_od_t *od; + + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); uint64_t offset = (1ULL << (ztest_random(20) + 43)) + (ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT); @@ -3737,47 +3763,56 @@ ztest_dmu_write_parallel(ztest_ds_t *zd, uint64_t id) * to verify that parallel writes to an object -- even to the * same blocks within the object -- doesn't cause any trouble. */ - ztest_od_init(&od[0], ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0); + ztest_od_init(od, ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0); - if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0) + if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) return; while (ztest_random(10) != 0) - ztest_io(zd, od[0].od_object, offset); + ztest_io(zd, od->od_object, offset); + + umem_free(od, sizeof(ztest_od_t)); } void ztest_dmu_prealloc(ztest_ds_t *zd, uint64_t id) { - ztest_od_t od[1]; + ztest_od_t *od; uint64_t offset = (1ULL << (ztest_random(4) + SPA_MAXBLOCKSHIFT)) + (ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT); uint64_t count = ztest_random(20) + 1; uint64_t blocksize = ztest_random_blocksize(); void *data; - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0); + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); - if (ztest_object_init(zd, od, sizeof (od), !ztest_random(2)) != 0) + ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0); + + if (ztest_object_init(zd, od, sizeof (ztest_od_t), !ztest_random(2)) != 0) { + umem_free(od, sizeof(ztest_od_t)); return; + } - if (ztest_truncate(zd, od[0].od_object, offset, count * blocksize) != 0) + if (ztest_truncate(zd, od->od_object, offset, count * blocksize) != 0) { + umem_free(od, sizeof(ztest_od_t)); return; + } - ztest_prealloc(zd, od[0].od_object, offset, count * blocksize); + ztest_prealloc(zd, od->od_object, offset, count * blocksize); data = umem_zalloc(blocksize, UMEM_NOFAIL); while (ztest_random(count) != 0) { uint64_t randoff = offset + (ztest_random(count) * blocksize); - if (ztest_write(zd, od[0].od_object, randoff, blocksize, + if (ztest_write(zd, od->od_object, randoff, blocksize, data) != 0) break; while (ztest_random(4) != 0) - ztest_io(zd, od[0].od_object, randoff); + ztest_io(zd, od->od_object, randoff); } umem_free(data, blocksize); + umem_free(od, sizeof(ztest_od_t)); } /* @@ -3791,7 +3826,7 @@ void ztest_zap(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; - ztest_od_t od[1]; + ztest_od_t *od; uint64_t object; uint64_t txg, last_txg; uint64_t value[ZTEST_ZAP_MAX_INTS]; @@ -3802,12 +3837,14 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) int error; char *hc[2] = { "s.acl.h", ".s.open.h.hyLZlg" }; - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0); + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); + ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0); - if (ztest_object_init(zd, od, sizeof (od), !ztest_random(2)) != 0) - return; + if (ztest_object_init(zd, od, sizeof (ztest_od_t), + !ztest_random(2)) != 0) + goto out; - object = od[0].od_object; + object = od->od_object; /* * Generate a known hash collision, and verify that @@ -3817,7 +3854,7 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) dmu_tx_hold_zap(tx, object, B_TRUE, NULL); txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG); if (txg == 0) - return; + goto out; for (i = 0; i < 2; i++) { value[i] = i; VERIFY3U(0, ==, zap_add(os, object, hc[i], sizeof (uint64_t), @@ -3885,7 +3922,7 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) dmu_tx_hold_zap(tx, object, B_TRUE, NULL); txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG); if (txg == 0) - return; + goto out; if (last_txg > txg) fatal(0, "zap future leak: old %llu new %llu", last_txg, txg); @@ -3910,7 +3947,7 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) error = zap_length(os, object, txgname, &zl_intsize, &zl_ints); if (error == ENOENT) - return; + goto out; ASSERT3U(error, ==, 0); @@ -3918,10 +3955,12 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) dmu_tx_hold_zap(tx, object, B_TRUE, NULL); txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG); if (txg == 0) - return; + goto out; VERIFY3U(0, ==, zap_remove(os, object, txgname, tx)); VERIFY3U(0, ==, zap_remove(os, object, propname, tx)); dmu_tx_commit(tx); +out: + umem_free(od, sizeof(ztest_od_t)); } /* @@ -3931,15 +3970,16 @@ void ztest_fzap(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; - ztest_od_t od[1]; + ztest_od_t *od; uint64_t object, txg; - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0); + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); + ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0); - if (ztest_object_init(zd, od, sizeof (od), !ztest_random(2)) != 0) - return; - - object = od[0].od_object; + if (ztest_object_init(zd, od, sizeof (ztest_od_t), + !ztest_random(2)) != 0) + goto out; + object = od->od_object; /* * Add entries to this ZAP and make sure it spills over @@ -3959,12 +3999,14 @@ ztest_fzap(ztest_ds_t *zd, uint64_t id) dmu_tx_hold_zap(tx, object, B_TRUE, name); txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG); if (txg == 0) - return; + goto out; error = zap_add(os, object, name, sizeof (uint64_t), 1, &value, tx); ASSERT(error == 0 || error == EEXIST); dmu_tx_commit(tx); } +out: + umem_free(od, sizeof(ztest_od_t)); } /* ARGSUSED */ @@ -3972,7 +4014,7 @@ void ztest_zap_parallel(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; - ztest_od_t od[1]; + ztest_od_t *od; uint64_t txg, object, count, wsize, wc, zl_wsize, zl_wc; dmu_tx_t *tx; int i, namelen, error; @@ -3980,12 +4022,15 @@ ztest_zap_parallel(ztest_ds_t *zd, uint64_t id) char name[20], string_value[20]; void *data; - ztest_od_init(&od[0], ID_PARALLEL, FTAG, micro, DMU_OT_ZAP_OTHER, 0, 0); + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); + ztest_od_init(od, ID_PARALLEL, FTAG, micro, DMU_OT_ZAP_OTHER, 0, 0); - if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0) + if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) { + umem_free(od, sizeof(ztest_od_t)); return; + } - object = od[0].od_object; + object = od->od_object; /* * Generate a random name of the form 'xxx.....' where each @@ -4074,6 +4119,8 @@ ztest_zap_parallel(ztest_ds_t *zd, uint64_t id) if (tx != NULL) dmu_tx_commit(tx); + + umem_free(od, sizeof(ztest_od_t)); } /* @@ -4163,23 +4210,26 @@ void ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; - ztest_od_t od[1]; + ztest_od_t *od; dmu_tx_t *tx; ztest_cb_data_t *cb_data[3], *tmp_cb; uint64_t old_txg, txg; int i, error; - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0); + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); + ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0); - if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0) + if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) { + umem_free(od, sizeof(ztest_od_t)); return; + } tx = dmu_tx_create(os); cb_data[0] = ztest_create_cb_data(os, 0); dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[0]); - dmu_tx_hold_write(tx, od[0].od_object, 0, sizeof (uint64_t)); + dmu_tx_hold_write(tx, od->od_object, 0, sizeof (uint64_t)); /* Every once in a while, abort the transaction on purpose */ if (ztest_random(100) == 0) @@ -4213,6 +4263,7 @@ ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id) umem_free(cb_data[i], sizeof (ztest_cb_data_t)); } + umem_free(od, sizeof(ztest_od_t)); return; } @@ -4222,14 +4273,14 @@ ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id) /* * Read existing data to make sure there isn't a future leak. */ - VERIFY(0 == dmu_read(os, od[0].od_object, 0, sizeof (uint64_t), + VERIFY(0 == dmu_read(os, od->od_object, 0, sizeof (uint64_t), &old_txg, DMU_READ_PREFETCH)); if (old_txg > txg) fatal(0, "future leak: got %" PRIu64 ", open txg is %" PRIu64, old_txg, txg); - dmu_write(os, od[0].od_object, 0, sizeof (uint64_t), &txg, tx); + dmu_write(os, od->od_object, 0, sizeof (uint64_t), &txg, tx); (void) mutex_enter(&zcl.zcl_callbacks_lock); @@ -4281,6 +4332,8 @@ ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id) (void) mutex_exit(&zcl.zcl_callbacks_lock); dmu_tx_commit(tx); + + umem_free(od, sizeof(ztest_od_t)); } /* ARGSUSED */ @@ -4630,7 +4683,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) ztest_shared_t *zs = ztest_shared; spa_t *spa = zs->zs_spa; objset_t *os = zd->zd_os; - ztest_od_t od[1]; + ztest_od_t *od; uint64_t object, blocksize, txg, pattern, psize; enum zio_checksum checksum = spa_dedup_checksum(spa); dmu_buf_t *db; @@ -4642,10 +4695,13 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) blocksize = ztest_random_blocksize(); blocksize = MIN(blocksize, 2048); /* because we write so many */ - ztest_od_init(&od[0], id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0); + od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL); + ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0); - if (ztest_object_init(zd, od, sizeof (od), B_FALSE) != 0) + if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) { + umem_free(od, sizeof(ztest_od_t)); return; + } /* * Take the name lock as writer to prevent anyone else from changing @@ -4658,6 +4714,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_COPIES, 1, B_FALSE) != 0) { (void) rw_exit(&zs->zs_name_lock); + umem_free(od, sizeof(ztest_od_t)); return; } @@ -4672,6 +4729,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) txg = ztest_tx_assign(tx, TXG_WAIT, FTAG); if (txg == 0) { (void) rw_exit(&zs->zs_name_lock); + umem_free(od, sizeof(ztest_od_t)); return; } @@ -4716,6 +4774,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) zio_buf_free(buf, psize); (void) rw_exit(&zs->zs_name_lock); + umem_free(od, sizeof(ztest_od_t)); } /* From a8a452d74b05cc73006adfc03d0358486cf21ef8 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Mon, 2 Aug 2010 13:44:56 -0700 Subject: [PATCH 3/8] Initial commit for fix-stack-inline topic branch --- .topdeps | 1 + .topmsg | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 .topdeps create mode 100644 .topmsg diff --git a/.topdeps b/.topdeps new file mode 100644 index 0000000000..1f7391f92b --- /dev/null +++ b/.topdeps @@ -0,0 +1 @@ +master diff --git a/.topmsg b/.topmsg new file mode 100644 index 0000000000..45849cfa12 --- /dev/null +++ b/.topmsg @@ -0,0 +1,8 @@ +From: Brian Behlendorf +Subject: [PATCH] fix stack inline + +Decrease stack usage for various call paths by forcing certain +functions to be inlined. By inlining the functions the overhead +of a new stack frame is removed at the cost of increased code size. + +Signed-off-by: Brian Behlendorf From ca5262f03091d6359ebdd4b985d169c208053a70 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Fri, 30 Jul 2010 13:34:50 -0700 Subject: [PATCH 4/8] Reduce stack by inlining spa_impl_load The spa_load function may call itself recursively through the spa_load_impl function. This call path of spa_load-> spa_load_impl->spa_load->spa_load_impl takes 640 bytes of stack. By forcing spa_load_impl to be inlined as part of spa_load the can be reduced to 448 bytes, for a savings of 192 bytes, --- module/zfs/spa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/zfs/spa.c b/module/zfs/spa.c index d7c5de0d35..9a8503e303 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -1652,7 +1652,8 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type, * Load an existing storage pool, using the pool's builtin spa_config as a * source of configuration information. */ -static int +__attribute__((always_inline)) +static inline int spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config, spa_load_state_t state, spa_import_type_t type, boolean_t mosconfig, char **ereport) From dd72f3d647bae11d9fd5c3aa45ae6972de8cb319 Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Thu, 29 Jul 2010 13:37:44 -0700 Subject: [PATCH 5/8] Inline zio_notify_parent() to reduce stack use Deep recursive call chains are contributing to segfaults in ztest due to heavy stack use. Inlining zio_notify_parent() helps reduce the stack depth of the zio_notify_parent() -> zio_execute() -> zio_done() recursive cycle. I am no longer seeing ztest segfaults in this code path with this change combined with the zio_done() stack reduction in the previous commit. Signed-off-by: Brian Behlendorf --- module/zfs/zio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 88d80af4e9..75807bd30e 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -435,7 +435,8 @@ zio_wait_for_children(zio_t *zio, enum zio_child child, enum zio_wait_type wait) return (waiting); } -static void +__attribute__((always_inline)) +static inline void zio_notify_parent(zio_t *pio, zio_t *zio, enum zio_wait_type wait) { uint64_t *countp = &pio->io_children[zio->io_child_type][wait]; From 526d004cf5b8bf0456650508116713bf6bb9fa61 Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Thu, 29 Jul 2010 13:35:56 -0700 Subject: [PATCH 6/8] Inline dbuf_findbp() to reduce stack use Deep recursive call chains are contributing to segfaults in ztest due to heavy stack use. Inlining dbuf_findbp() helps reduce the stack depth of the dbuf_findbp() -> dbuf_hold_impl() cycle. However, segfaults are still occurring in this code path, so further reductions are still needed. Signed-off-by: Brian Behlendorf --- module/zfs/dbuf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 42ae439972..248bee18bf 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -1490,7 +1490,8 @@ dbuf_clear(dmu_buf_impl_t *db) dbuf_rele(parent, db); } -static int +__attribute__((always_inline)) +static inline int dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse, dmu_buf_impl_t **parentp, blkptr_t **bpp) { From 411dd65af1a3f931cee72adc6b9817187ae112cf Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Fri, 30 Jul 2010 15:23:29 -0700 Subject: [PATCH 7/8] Inline zio_execute() to reduce stack use Deep recursive call chains are contributing to segfaults in ztest due to heavy stack use. Inlining zio_execute() helps reduce the stack depth of the zio_notify_parent() -> zio_execute() -> zio_wait() recursive cycle. I am no longer seeing ztest segfaults in this code path with this change. Signed-off-by: Brian Behlendorf --- module/zfs/zio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 75807bd30e..cf9b99e56f 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -1119,7 +1119,8 @@ zio_interrupt(zio_t *zio) */ static zio_pipe_stage_t *zio_pipeline[]; -void +__attribute__((always_inline)) +inline void zio_execute(zio_t *zio) { zio->io_executor = curthread; From 084b700b9254790d45233c14839eb184a1683275 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Mon, 2 Aug 2010 13:49:02 -0700 Subject: [PATCH 8/8] New TopGit dependency: fix-stack-inline --- .topdeps | 1 + 1 file changed, 1 insertion(+) diff --git a/.topdeps b/.topdeps index d11ec85c73..dd74283adf 100644 --- a/.topdeps +++ b/.topdeps @@ -23,3 +23,4 @@ fix-stack-vn_open fix-stack-traverse_impl fix-stack-traverse_visitbp fix-stack-ztest +fix-stack-inline