summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r--drivers/block/drbd/drbd_nl.c21
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);