diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 335b11dc2ff..e88de3dbdfd 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -2304,22 +2304,29 @@ dsl_dir_snap_cmtime_update(dsl_dir_t *dd, dmu_tx_t *tx) { dsl_pool_t *dp = dmu_tx_pool(tx); inode_timespec_t t; + + ASSERT(dsl_pool_sync_context(dp)); gethrestime(&t); mutex_enter(&dd->dd_lock); dd->dd_snap_cmtime = t; - if (spa_feature_is_enabled(dp->dp_spa, - SPA_FEATURE_EXTENSIBLE_DATASET)) { - objset_t *mos = dd->dd_pool->dp_meta_objset; - uint64_t ddobj = dd->dd_object; - dsl_dir_zapify(dd, tx); - VERIFY0(zap_update(mos, ddobj, - DD_FIELD_SNAPSHOTS_CHANGED, - sizeof (uint64_t), - sizeof (inode_timespec_t) / sizeof (uint64_t), - &t, tx)); - } mutex_exit(&dd->dd_lock); + + if (!spa_feature_is_enabled(dp->dp_spa, + SPA_FEATURE_EXTENSIBLE_DATASET)) { + return; + } + + objset_t *mos = dd->dd_pool->dp_meta_objset; + + /* + * dsl_dir_zapify() and zap_update() may dirty buffers and recurse + * into space accounting, so do not call them with dd_lock held. + */ + dsl_dir_zapify(dd, tx); + VERIFY0(zap_update(mos, dd->dd_object, DD_FIELD_SNAPSHOTS_CHANGED, + sizeof (uint64_t), + sizeof (inode_timespec_t) / sizeof (uint64_t), &t, tx)); } void