summaryrefslogtreecommitdiffstats
path: root/module/zfs/bpobj.c
diff options
context:
space:
mode:
authorMatthew Ahrens <[email protected]>2017-02-09 10:19:12 -0800
committerBrian Behlendorf <[email protected]>2017-02-09 10:19:12 -0800
commitdf7eeccc7597980efd3cb1efd9377ad5e0483042 (patch)
tree019acfbccd405cdc2ee0f41b0ba0fdafd3aeea42 /module/zfs/bpobj.c
parentb0eac56a4d69c6f2ae7cb1937cf59e05c52e3a60 (diff)
panic in bpobj_space(): null pointer dereference
This is a race condition in the deadlist code. A thread executing an administrative command that uses dsl_deadlist_space_range() holds the lock of the whole deadlist_t to protect the access of all its entries that the deadlist contains in an avl tree. Sync threads trying to insert a new entry in the deadlist (through dsl_deadlist_insert() -> dle_enqueue()) do not hold the deadlist lock at that moment. If the dle_bpobj is the empty bpobj (our sentinel value), we close and reopen it. Between these two operations, it is possible for the dsl_deadlist_space_range() thread to dereference that bpobj which is NULL during that window. Threads should hold the a deadlist's dl_lock when they manipulate its internal data so scenarios like the one above are avoided. Reviewed-by: Matthew Ahrens <[email protected]> Reviewed-by: Dan Kimmel <[email protected]> Reviewed-by: George Melikov <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Matthew Ahrens <[email protected]> Closes #5762
Diffstat (limited to 'module/zfs/bpobj.c')
-rw-r--r--module/zfs/bpobj.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/module/zfs/bpobj.c b/module/zfs/bpobj.c
index 17d98c36e..5f2aff453 100644
--- a/module/zfs/bpobj.c
+++ b/module/zfs/bpobj.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
*/
#include <sys/bpobj.h>
@@ -395,6 +395,7 @@ bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx)
return;
}
+ mutex_enter(&bpo->bpo_lock);
dmu_buf_will_dirty(bpo->bpo_dbuf, tx);
if (bpo->bpo_phys->bpo_subobjs == 0) {
bpo->bpo_phys->bpo_subobjs = dmu_object_alloc(bpo->bpo_os,
@@ -405,7 +406,6 @@ bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx)
ASSERT0(dmu_object_info(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, &doi));
ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ_SUBOBJ);
- mutex_enter(&bpo->bpo_lock);
dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs,
bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj),
sizeof (subobj), &subobj, tx);