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);
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;
}
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);
}
}
- /* 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);
static enum drbd_state_rv
is_valid_conn_transition(enum drbd_conns oc, enum drbd_conns nc)
{
- enum drbd_state_rv rv = SS_SUCCESS;
+ /* no change -> nothing to do, at least for the connection part */
+ if (oc == nc)
+ return SS_NOTHING_TO_DO;
- /* Disallow Network errors to configure a device's network part */
- if ((nc >= C_TIMEOUT && nc <= C_TEAR_DOWN) && oc <= C_DISCONNECTING)
- rv = SS_NEED_CONNECTION;
+ /* disconnect of an unconfigured connection does not make sense */
+ if (oc == C_STANDALONE && nc == C_DISCONNECTING)
+ return SS_ALREADY_STANDALONE;
+
+ /* from C_STANDALONE, we start with C_UNCONNECTED */
+ if (oc == C_STANDALONE && nc != C_UNCONNECTED)
+ return SS_NEED_CONNECTION;
/* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */
if (oc >= C_TIMEOUT && oc <= C_TEAR_DOWN && nc != C_UNCONNECTED && nc != C_DISCONNECTING)
- rv = SS_IN_TRANSIENT_STATE;
+ return SS_IN_TRANSIENT_STATE;
/* After C_DISCONNECTING only C_STANDALONE may follow */
if (oc == C_DISCONNECTING && nc != C_STANDALONE)
- rv = SS_IN_TRANSIENT_STATE;
+ return SS_IN_TRANSIENT_STATE;
- return rv;
+ return SS_SUCCESS;
}