summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_state.c
diff options
context:
space:
mode:
authorLars Ellenberg2011-04-27 10:25:28 +0200
committerPhilipp Reisner2012-11-08 16:49:08 +0100
commitd9cc6e231897a9ab1a94e6cfe12d71bfec0b7a81 (patch)
treef0ab01f5319972d672160f5ba1e1233f8bafbeb1 /drivers/block/drbd/drbd_state.c
parentdrbd: remove useless kobject_uevent from drbd_adm_connect (diff)
downloadkernel-qcow2-linux-d9cc6e231897a9ab1a94e6cfe12d71bfec0b7a81.tar.gz
kernel-qcow2-linux-d9cc6e231897a9ab1a94e6cfe12d71bfec0b7a81.tar.xz
kernel-qcow2-linux-d9cc6e231897a9ab1a94e6cfe12d71bfec0b7a81.zip
drbd: fix various disconnecting races
If an admin requests disconnect at a time when the state handling already disconnects/reconnects, there have been some races. Make sure to always really stop the network threads before returning success for disconnect. Do not pretend successfull forced disconnect, if the state handling returned an error. Return success from drbd_adm_down() only after all threads are finished. 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.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 05628b45cf03..8b0f31b6808a 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -604,21 +604,27 @@ is_valid_soft_transition(union drbd_state os, union drbd_state ns)
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;
}