Remove recursion from dsl_dir_willuse_space()
Remove recursion from dsl_dir_willuse_space() to reduce stack usage. Issues with stack overflow were observed in zfs recv of zvols, likelihood of an overflow is proportional to the depth of the dataset as dsl_dir_willuse_space() recurses to parent datasets. Signed-off-by: Andrew Barnes <barnes333@gmail.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #2069
This commit is contained in:
parent
0ad85ed91e
commit
1ba1615925
|
@ -808,6 +808,10 @@ dsl_dir_tempreserve_clear(void *tr_cookie, dmu_tx_t *tx)
|
||||||
* or free space, for example when dirtying data. Be conservative; it's okay
|
* or free space, for example when dirtying data. Be conservative; it's okay
|
||||||
* to write less space or free more, but we don't want to write more or free
|
* to write less space or free more, but we don't want to write more or free
|
||||||
* less than the amount specified.
|
* less than the amount specified.
|
||||||
|
*
|
||||||
|
* NOTE: The behavior of this function is identical to the Illumos / FreeBSD
|
||||||
|
* version however it has been adjusted to use an iterative rather then
|
||||||
|
* recursive algorithm to minimize stack usage.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
|
dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
|
||||||
|
@ -815,20 +819,22 @@ dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
|
||||||
int64_t parent_space;
|
int64_t parent_space;
|
||||||
uint64_t est_used;
|
uint64_t est_used;
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
do {
|
||||||
if (space > 0)
|
mutex_enter(&dd->dd_lock);
|
||||||
dd->dd_space_towrite[tx->tx_txg & TXG_MASK] += space;
|
if (space > 0)
|
||||||
|
dd->dd_space_towrite[tx->tx_txg & TXG_MASK] += space;
|
||||||
|
|
||||||
est_used = dsl_dir_space_towrite(dd) + dd->dd_phys->dd_used_bytes;
|
est_used = dsl_dir_space_towrite(dd) +
|
||||||
parent_space = parent_delta(dd, est_used, space);
|
dd->dd_phys->dd_used_bytes;
|
||||||
mutex_exit(&dd->dd_lock);
|
parent_space = parent_delta(dd, est_used, space);
|
||||||
|
mutex_exit(&dd->dd_lock);
|
||||||
|
|
||||||
/* Make sure that we clean up dd_space_to* */
|
/* Make sure that we clean up dd_space_to* */
|
||||||
dsl_dir_dirty(dd, tx);
|
dsl_dir_dirty(dd, tx);
|
||||||
|
|
||||||
/* XXX this is potentially expensive and unnecessary... */
|
dd = dd->dd_parent;
|
||||||
if (parent_space && dd->dd_parent)
|
space = parent_space;
|
||||||
dsl_dir_willuse_space(dd->dd_parent, parent_space, tx);
|
} while (space && dd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call from syncing context when we actually write/free space for this dd */
|
/* call from syncing context when we actually write/free space for this dd */
|
||||||
|
|
Loading…
Reference in New Issue