Merge branch 'condvar'
Auditing the code to verify that all instances of cv_signal() and cv_broadcast() are called under the proper associated mutex turned up several races. None of these have been conclusively seen in the wild but the following patch set resolves them. For reference, from the cv_signal(9F) man page: cv_signal() signals the condition and wakes one blocked thread. All blocked threads can be unblocked by calling cv_broadcast(). You must acquire the mutex passed into cv_wait() before calling cv_signal() or cv_broadcast() Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #1048
This commit is contained in:
commit
82f46731fd
|
@ -481,14 +481,13 @@ zfs_zevent_drain_all(int *count)
|
|||
static void
|
||||
zfs_zevent_insert(zevent_t *ev)
|
||||
{
|
||||
mutex_enter(&zevent_lock);
|
||||
ASSERT(MUTEX_HELD(&zevent_lock));
|
||||
list_insert_head(&zevent_list, ev);
|
||||
|
||||
if (zevent_len_cur >= zfs_zevent_len_max)
|
||||
zfs_zevent_drain(list_tail(&zevent_list));
|
||||
else
|
||||
zevent_len_cur++;
|
||||
|
||||
mutex_exit(&zevent_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -528,8 +527,11 @@ zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
|
|||
ev->ev_nvl = nvl;
|
||||
ev->ev_detector = detector;
|
||||
ev->ev_cb = cb;
|
||||
|
||||
mutex_enter(&zevent_lock);
|
||||
zfs_zevent_insert(ev);
|
||||
cv_broadcast(&zevent_cv);
|
||||
mutex_exit(&zevent_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1520,9 +1522,10 @@ fm_fini(void)
|
|||
int count;
|
||||
|
||||
zfs_zevent_drain_all(&count);
|
||||
cv_broadcast(&zevent_cv);
|
||||
|
||||
mutex_enter(&zevent_lock);
|
||||
cv_broadcast(&zevent_cv);
|
||||
|
||||
zevent_flags |= ZEVENT_SHUTDOWN;
|
||||
while (zevent_waiters > 0) {
|
||||
mutex_exit(&zevent_lock);
|
||||
|
|
|
@ -486,7 +486,7 @@ zfs_range_unlock_reader(znode_t *zp, rl_t *remove, list_t *free_list)
|
|||
*/
|
||||
if (remove->r_cnt == 1) {
|
||||
avl_remove(tree, remove);
|
||||
mutex_exit(&zp->z_range_lock);
|
||||
|
||||
if (remove->r_write_wanted)
|
||||
cv_broadcast(&remove->r_wr_cv);
|
||||
|
||||
|
@ -530,7 +530,6 @@ zfs_range_unlock_reader(znode_t *zp, rl_t *remove, list_t *free_list)
|
|||
}
|
||||
}
|
||||
|
||||
mutex_exit(&zp->z_range_lock);
|
||||
kmem_free(remove, sizeof (rl_t));
|
||||
}
|
||||
}
|
||||
|
@ -554,7 +553,6 @@ zfs_range_unlock(rl_t *rl)
|
|||
if (rl->r_type == RL_WRITER) {
|
||||
/* writer locks can't be shared or split */
|
||||
avl_remove(&zp->z_range_avl, rl);
|
||||
mutex_exit(&zp->z_range_lock);
|
||||
if (rl->r_write_wanted)
|
||||
cv_broadcast(&rl->r_wr_cv);
|
||||
|
||||
|
@ -569,6 +567,7 @@ zfs_range_unlock(rl_t *rl)
|
|||
*/
|
||||
zfs_range_unlock_reader(zp, rl, &free_list);
|
||||
}
|
||||
mutex_exit(&zp->z_range_lock);
|
||||
|
||||
while ((free_rl = list_head(&free_list)) != NULL) {
|
||||
list_remove(&free_list, free_rl);
|
||||
|
@ -599,11 +598,13 @@ zfs_range_reduce(rl_t *rl, uint64_t off, uint64_t len)
|
|||
mutex_enter(&zp->z_range_lock);
|
||||
rl->r_off = off;
|
||||
rl->r_len = len;
|
||||
mutex_exit(&zp->z_range_lock);
|
||||
|
||||
if (rl->r_write_wanted)
|
||||
cv_broadcast(&rl->r_wr_cv);
|
||||
if (rl->r_read_wanted)
|
||||
cv_broadcast(&rl->r_rd_cv);
|
||||
|
||||
mutex_exit(&zp->z_range_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1560,13 +1560,14 @@ zil_commit(zilog_t *zilog, uint64_t foid)
|
|||
zil_commit_writer(zilog);
|
||||
zilog->zl_com_batch = mybatch;
|
||||
zilog->zl_writer = B_FALSE;
|
||||
mutex_exit(&zilog->zl_lock);
|
||||
|
||||
/* wake up one thread to become the next writer */
|
||||
cv_signal(&zilog->zl_cv_batch[(mybatch+1) & 1]);
|
||||
|
||||
/* wake up all threads waiting for this batch to be committed */
|
||||
cv_broadcast(&zilog->zl_cv_batch[mybatch & 1]);
|
||||
|
||||
mutex_exit(&zilog->zl_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue