mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-25 18:59:33 +03:00
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
|
||||
* to write less space or free more, but we don't want to write more or free
|
||||
* 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
|
||||
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;
|
||||
uint64_t est_used;
|
||||
|
||||
mutex_enter(&dd->dd_lock);
|
||||
if (space > 0)
|
||||
dd->dd_space_towrite[tx->tx_txg & TXG_MASK] += space;
|
||||
do {
|
||||
mutex_enter(&dd->dd_lock);
|
||||
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;
|
||||
parent_space = parent_delta(dd, est_used, space);
|
||||
mutex_exit(&dd->dd_lock);
|
||||
est_used = dsl_dir_space_towrite(dd) +
|
||||
dd->dd_phys->dd_used_bytes;
|
||||
parent_space = parent_delta(dd, est_used, space);
|
||||
mutex_exit(&dd->dd_lock);
|
||||
|
||||
/* Make sure that we clean up dd_space_to* */
|
||||
dsl_dir_dirty(dd, tx);
|
||||
/* Make sure that we clean up dd_space_to* */
|
||||
dsl_dir_dirty(dd, tx);
|
||||
|
||||
/* XXX this is potentially expensive and unnecessary... */
|
||||
if (parent_space && dd->dd_parent)
|
||||
dsl_dir_willuse_space(dd->dd_parent, parent_space, tx);
|
||||
dd = dd->dd_parent;
|
||||
space = parent_space;
|
||||
} while (space && dd);
|
||||
}
|
||||
|
||||
/* call from syncing context when we actually write/free space for this dd */
|
||||
|
Loading…
Reference in New Issue
Block a user