diff options
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 1a8fb7a0db5..a16089ce0a5 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2075,10 +2075,9 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for enum drbd_state_rv rv; if (force) { spin_lock_irq(&tconn->req_lock); - if (tconn->cstate >= C_WF_CONNECTION) - _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); + rv = _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); spin_unlock_irq(&tconn->req_lock); - return SS_SUCCESS; + return rv; } rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0); @@ -2137,10 +2136,12 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) if (rv < SS_SUCCESS) goto fail; + /* No one else can reconfigure the network while I am here. + * The state handling only uses drbd_thread_stop_nowait(), + * we want to really wait here until the receiver is no more. */ + drbd_thread_stop(&tconn->receiver); if (wait_event_interruptible(tconn->ping_wait, - tconn->cstate != C_DISCONNECTING)) { - /* Do not test for mdev->state.conn == C_STANDALONE, since - someone else might connect us in the mean time! */ + tconn->cstate == C_STANDALONE)) { retcode = ERR_INTR; goto fail; } @@ -3043,6 +3044,10 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } + /* Make sure the network threads have actually stopped, + * state handling only does drbd_thread_stop_nowait(). */ + drbd_thread_stop(&adm_ctx.tconn->receiver); + /* detach */ idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) { rv = adm_detach(mdev); @@ -3066,11 +3071,9 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) } } - /* stop all threads */ - conn_reconfig_done(adm_ctx.tconn); - /* delete connection */ if (conn_lowest_minor(adm_ctx.tconn) < 0) { + drbd_thread_stop(&adm_ctx.tconn->worker); list_del(&adm_ctx.tconn->all_tconn); kref_put(&adm_ctx.tconn->kref, &conn_destroy); |