Skip to content

Commit 5e8cd5d

Browse files
Arne Jansenbehlendorf
authored andcommitted
Illumos 5981 - Deadlock in dmu_objset_find_dp
5981 Deadlock in dmu_objset_find_dp Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Dan McDonald <danmcd@omniti.com> Approved by: Robert Mustacchi <rm@joyent.com> References: https://www.illumos.org/issues/5981 illumos/illumos-gate@1d3f896 Ported-by: kernelOfTruth kerneloftruth@gmail.com Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3553
1 parent 71e2fe4 commit 5e8cd5d

File tree

5 files changed

+40
-4
lines changed

5 files changed

+40
-4
lines changed

include/sys/dsl_pool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ void dsl_pool_mos_diduse_space(dsl_pool_t *dp,
156156
int64_t used, int64_t comp, int64_t uncomp);
157157
boolean_t dsl_pool_need_dirty_delay(dsl_pool_t *dp);
158158
void dsl_pool_config_enter(dsl_pool_t *dp, void *tag);
159+
void dsl_pool_config_enter_prio(dsl_pool_t *dp, void *tag);
159160
void dsl_pool_config_exit(dsl_pool_t *dp, void *tag);
160161
boolean_t dsl_pool_config_held(dsl_pool_t *dp);
161162
boolean_t dsl_pool_config_held_writer(dsl_pool_t *dp);

include/sys/rrwlock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ void rrw_init(rrwlock_t *rrl, boolean_t track_all);
7272
void rrw_destroy(rrwlock_t *rrl);
7373
void rrw_enter(rrwlock_t *rrl, krw_t rw, void *tag);
7474
void rrw_enter_read(rrwlock_t *rrl, void *tag);
75+
void rrw_enter_read_prio(rrwlock_t *rrl, void *tag);
7576
void rrw_enter_write(rrwlock_t *rrl);
7677
void rrw_exit(rrwlock_t *rrl, void *tag);
7778
boolean_t rrw_held(rrwlock_t *rrl, krw_t rw);

module/zfs/dmu_objset.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1784,7 +1784,15 @@ dmu_objset_find_dp_cb(void *arg)
17841784
dmu_objset_find_ctx_t *dcp = arg;
17851785
dsl_pool_t *dp = dcp->dc_dp;
17861786

1787-
dsl_pool_config_enter(dp, FTAG);
1787+
/*
1788+
* We need to get a pool_config_lock here, as there are several
1789+
* asssert(pool_config_held) down the stack. Getting a lock via
1790+
* dsl_pool_config_enter is risky, as it might be stalled by a
1791+
* pending writer. This would deadlock, as the write lock can
1792+
* only be granted when our parent thread gives up the lock.
1793+
* The _prio interface gives us priority over a pending writer.
1794+
*/
1795+
dsl_pool_config_enter_prio(dp, FTAG);
17881796

17891797
dmu_objset_find_dp_impl(dcp);
17901798

module/zfs/dsl_pool.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,13 @@ dsl_pool_config_enter(dsl_pool_t *dp, void *tag)
10501050
rrw_enter(&dp->dp_config_rwlock, RW_READER, tag);
10511051
}
10521052

1053+
void
1054+
dsl_pool_config_enter_prio(dsl_pool_t *dp, void *tag)
1055+
{
1056+
ASSERT(!rrw_held(&dp->dp_config_rwlock, RW_READER));
1057+
rrw_enter_read_prio(&dp->dp_config_rwlock, tag);
1058+
}
1059+
10531060
void
10541061
dsl_pool_config_exit(dsl_pool_t *dp, void *tag)
10551062
{

module/zfs/rrwlock.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ rrw_destroy(rrwlock_t *rrl)
159159
refcount_destroy(&rrl->rr_linked_rcount);
160160
}
161161

162-
void
163-
rrw_enter_read(rrwlock_t *rrl, void *tag)
162+
static void
163+
rrw_enter_read_impl(rrwlock_t *rrl, boolean_t prio, void *tag)
164164
{
165165
mutex_enter(&rrl->rr_lock);
166166
#if !defined(DEBUG) && defined(_KERNEL)
@@ -176,7 +176,7 @@ rrw_enter_read(rrwlock_t *rrl, void *tag)
176176
ASSERT(refcount_count(&rrl->rr_anon_rcount) >= 0);
177177

178178
while (rrl->rr_writer != NULL || (rrl->rr_writer_wanted &&
179-
refcount_is_zero(&rrl->rr_anon_rcount) &&
179+
refcount_is_zero(&rrl->rr_anon_rcount) && !prio &&
180180
rrn_find(rrl) == NULL))
181181
cv_wait(&rrl->rr_cv, &rrl->rr_lock);
182182

@@ -191,6 +191,25 @@ rrw_enter_read(rrwlock_t *rrl, void *tag)
191191
mutex_exit(&rrl->rr_lock);
192192
}
193193

194+
void
195+
rrw_enter_read(rrwlock_t *rrl, void *tag)
196+
{
197+
rrw_enter_read_impl(rrl, B_FALSE, tag);
198+
}
199+
200+
/*
201+
* take a read lock even if there are pending write lock requests. if we want
202+
* to take a lock reentrantly, but from different threads (that have a
203+
* relationship to each other), the normal detection mechanism to overrule
204+
* the pending writer does not work, so we have to give an explicit hint here.
205+
*/
206+
void
207+
rrw_enter_read_prio(rrwlock_t *rrl, void *tag)
208+
{
209+
rrw_enter_read_impl(rrl, B_TRUE, tag);
210+
}
211+
212+
194213
void
195214
rrw_enter_write(rrwlock_t *rrl)
196215
{

0 commit comments

Comments
 (0)