diff options
author | George Melikov <[email protected]> | 2017-01-27 01:43:28 +0300 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-01-26 14:43:28 -0800 |
commit | 39efbde7c551ae0edcd57db3aab28fd7f2d29d18 (patch) | |
tree | 037a7a6404e3c86e6a24878f9b6e21e09ce09bf3 /module/zfs/dbuf.c | |
parent | aeacdefedc31b498cfccc0026b83be0bab197a3b (diff) |
OpenZFS 6676 - Race between unique_insert() and unique_remove() causes ZFS fsid change
Authored by: Josef 'Jeff' Sipek <[email protected]>
Reviewed by: Saso Kiselkov <[email protected]>
Reviewed by: Sanjay Nadkarni <[email protected]>
Reviewed by: Dan Vatca <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: George Wilson <[email protected]>
Reviewed by: Sebastien Roy <[email protected]>
Approved by: Robert Mustacchi <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Ported-by: George Melikov <[email protected]>
OpenZFS-issue: https://www.illumos.org/issues/6676
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/40510e8
Closes #5667
Diffstat (limited to 'module/zfs/dbuf.c')
-rw-r--r-- | module/zfs/dbuf.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index ca1a44303..907a84941 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -85,7 +85,9 @@ static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx); #ifndef __lint extern inline void dmu_buf_init_user(dmu_buf_user_t *dbu, - dmu_buf_evict_func_t *evict_func, dmu_buf_t **clear_on_evict_dbufp); + dmu_buf_evict_func_t *evict_func_sync, + dmu_buf_evict_func_t *evict_func_async, + dmu_buf_t **clear_on_evict_dbufp); #endif /* ! __lint */ /* @@ -385,6 +387,7 @@ static void dbuf_evict_user(dmu_buf_impl_t *db) { dmu_buf_user_t *dbu = db->db_user; + boolean_t has_async; ASSERT(MUTEX_HELD(&db->db_mtx)); @@ -400,11 +403,24 @@ dbuf_evict_user(dmu_buf_impl_t *db) #endif /* - * Invoke the callback from a taskq to avoid lock order reversals - * and limit stack depth. + * There are two eviction callbacks - one that we call synchronously + * and one that we invoke via a taskq. The async one is useful for + * avoiding lock order reversals and limiting stack depth. + * + * Note that if we have a sync callback but no async callback, + * it's likely that the sync callback will free the structure + * containing the dbu. In that case we need to take care to not + * dereference dbu after calling the sync evict func. */ - taskq_dispatch_ent(dbu_evict_taskq, dbu->dbu_evict_func, dbu, 0, - &dbu->dbu_tqent); + has_async = (dbu->dbu_evict_func_async != NULL); + + if (dbu->dbu_evict_func_sync != NULL) + dbu->dbu_evict_func_sync(dbu); + + if (has_async) { + taskq_dispatch_ent(dbu_evict_taskq, dbu->dbu_evict_func_async, + dbu, 0, &dbu->dbu_tqent); + } } boolean_t |