diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2011-05-02 11:47:18 +0200 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 16:53:00 +0100 |
commit | 992d6e91d3654c11c2e4d8d5933ffbf82a0440f0 (patch) | |
tree | b97d1371d9a0a93d539174ecdd8cfe205b56cf43 /drivers/block/drbd/drbd_state.c | |
parent | f3dfa40a67c354a5886c5ae53a9c5d3a2c6fd06e (diff) |
drbd: fix thread stop deadlock
There are races where the receiver may be exiting,
but still need the worker to process some stuff.
Do not wait for the receiver to die from an exiting worker.
The receiver must already be dead in case the worker decides to exit.
If the receiver was still alive, it may still want to queue work, and do
drbd_flush_workqueue() from it's disconnect cleanup code,
which would no longer be processed by an exiting worker.
This also would deadlock,
if the worker was to synchornously wait for the receiver to die.
Do not implicitly stop the worker.
The worker will only be stopped from configuration context, from
conn_reconfig_done(), drbd_adm_down() or drbd_adm_delete_connection(),
after making sure the receiver is already stopped.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_state.c')
-rw-r--r-- | drivers/block/drbd/drbd_state.c | 14 |
1 files changed, 0 insertions, 14 deletions
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 0512bbb952e..523ec094067 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -40,7 +40,6 @@ struct after_state_chg_work { static int w_after_state_ch(struct drbd_work *w, int unused); static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); -static void after_all_state_ch(struct drbd_tconn *tconn); static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state); static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); @@ -1380,8 +1379,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, resume_next_sg(mdev); } - after_all_state_ch(mdev->tconn); - drbd_md_sync(mdev); } @@ -1393,12 +1390,6 @@ struct after_conn_state_chg_work { enum chg_state_flags flags; }; -static void after_all_state_ch(struct drbd_tconn *tconn) -{ - if (conn_all_vols_unconf(tconn)) - drbd_thread_stop_nowait(&tconn->worker); -} - static int w_after_conn_state_ch(struct drbd_work *w, int unused) { struct after_conn_state_chg_work *acscw = @@ -1461,12 +1452,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused) spin_unlock_irq(&tconn->req_lock); } } - - - //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms)); - after_all_state_ch(tconn); kref_put(&tconn->kref, &conn_destroy); - return 0; } |