Fix scn_queue races on very old pools
Code for pools before version 11 uses dmu_objset_find_dp() to scan for children datasets/clones. It calls enqueue_clones_cb() and enqueue_cb() callbacks in parallel from multiple taskq threads. It ends up bad for scan_ds_queue_insert(), corrupting scn_queue AVL-tree. Fix it by introducing a mutex to protect those two scan_ds_queue_insert() calls. All other calls are done from the sync thread and so serialized. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Alexander Motin <mav@FreeBSD.org> Sponsored by: iXsystems, Inc. Closes #16162
This commit is contained in:
parent
a0f3c8aaf1
commit
af5dbed319
|
@ -173,6 +173,7 @@ typedef struct dsl_scan {
|
||||||
dsl_scan_phys_t scn_phys; /* on disk representation of scan */
|
dsl_scan_phys_t scn_phys; /* on disk representation of scan */
|
||||||
dsl_scan_phys_t scn_phys_cached;
|
dsl_scan_phys_t scn_phys_cached;
|
||||||
avl_tree_t scn_queue; /* queue of datasets to scan */
|
avl_tree_t scn_queue; /* queue of datasets to scan */
|
||||||
|
kmutex_t scn_queue_lock; /* serializes scn_queue inserts */
|
||||||
uint64_t scn_queues_pending; /* outstanding data to issue */
|
uint64_t scn_queues_pending; /* outstanding data to issue */
|
||||||
/* members needed for syncing error scrub status to disk */
|
/* members needed for syncing error scrub status to disk */
|
||||||
dsl_errorscrub_phys_t errorscrub_phys;
|
dsl_errorscrub_phys_t errorscrub_phys;
|
||||||
|
|
|
@ -491,6 +491,7 @@ dsl_scan_init(dsl_pool_t *dp, uint64_t txg)
|
||||||
|
|
||||||
avl_create(&scn->scn_queue, scan_ds_queue_compare, sizeof (scan_ds_t),
|
avl_create(&scn->scn_queue, scan_ds_queue_compare, sizeof (scan_ds_t),
|
||||||
offsetof(scan_ds_t, sds_node));
|
offsetof(scan_ds_t, sds_node));
|
||||||
|
mutex_init(&scn->scn_queue_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
avl_create(&scn->scn_prefetch_queue, scan_prefetch_queue_compare,
|
avl_create(&scn->scn_prefetch_queue, scan_prefetch_queue_compare,
|
||||||
sizeof (scan_prefetch_issue_ctx_t),
|
sizeof (scan_prefetch_issue_ctx_t),
|
||||||
offsetof(scan_prefetch_issue_ctx_t, spic_avl_node));
|
offsetof(scan_prefetch_issue_ctx_t, spic_avl_node));
|
||||||
|
@ -646,6 +647,7 @@ dsl_scan_fini(dsl_pool_t *dp)
|
||||||
|
|
||||||
scan_ds_queue_clear(scn);
|
scan_ds_queue_clear(scn);
|
||||||
avl_destroy(&scn->scn_queue);
|
avl_destroy(&scn->scn_queue);
|
||||||
|
mutex_destroy(&scn->scn_queue_lock);
|
||||||
scan_ds_prefetch_queue_clear(scn);
|
scan_ds_prefetch_queue_clear(scn);
|
||||||
avl_destroy(&scn->scn_prefetch_queue);
|
avl_destroy(&scn->scn_prefetch_queue);
|
||||||
|
|
||||||
|
@ -2723,8 +2725,10 @@ enqueue_clones_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg)
|
||||||
return (err);
|
return (err);
|
||||||
ds = prev;
|
ds = prev;
|
||||||
}
|
}
|
||||||
|
mutex_enter(&scn->scn_queue_lock);
|
||||||
scan_ds_queue_insert(scn, ds->ds_object,
|
scan_ds_queue_insert(scn, ds->ds_object,
|
||||||
dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
||||||
|
mutex_exit(&scn->scn_queue_lock);
|
||||||
dsl_dataset_rele(ds, FTAG);
|
dsl_dataset_rele(ds, FTAG);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -2915,8 +2919,10 @@ enqueue_cb(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg)
|
||||||
ds = prev;
|
ds = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_enter(&scn->scn_queue_lock);
|
||||||
scan_ds_queue_insert(scn, ds->ds_object,
|
scan_ds_queue_insert(scn, ds->ds_object,
|
||||||
dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
||||||
|
mutex_exit(&scn->scn_queue_lock);
|
||||||
dsl_dataset_rele(ds, FTAG);
|
dsl_dataset_rele(ds, FTAG);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue