mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-29 03:45:02 +01:00
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 <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: ZhengYuan Huang <[email protected]> Co-authored-by: gality369 <[email protected]> Closes #18472
This commit is contained in:
1 parent
968f4db039
commit
d50f5b6d0b
1 file changed
+18
-11
+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);
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user