dsl_dir: avoid dd_lock during snapshots_changed updates
Avoid holding dd_lock while updating the on-disk snapshots_changed timestamp. Both dsl_dir_zapify() and zap_update() may dirty buffers and recurse into space accounting, which can take dd_lock. Holding dd_lock across either operation can therefore preserve the lock-order inversion reported by lockdep. Only protect the in-memory dd_snap_cmtime update with dd_lock. Perform the zapify and ZAP update without dd_lock held, and retry the on-disk write if another updater advanced dd_snap_cmtime while the write was in progress. Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: ZhengYuan Huang <gality369@gmail.com> Co-authored-by: gality369 <gality369@example.com> Closes #18472
This commit is contained in:
+18
-11
@@ -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);
|
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||||
inode_timespec_t t;
|
inode_timespec_t t;
|
||||||
|
|
||||||
|
ASSERT(dsl_pool_sync_context(dp));
|
||||||
gethrestime(&t);
|
gethrestime(&t);
|
||||||
|
|
||||||
mutex_enter(&dd->dd_lock);
|
mutex_enter(&dd->dd_lock);
|
||||||
dd->dd_snap_cmtime = t;
|
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);
|
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
|
void
|
||||||
|
|||||||
Reference in New Issue
Block a user