diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2014-11-10 19:21:11 +0300 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-11-10 19:27:35 +0300 |
commit | a88215312c5ed74697973f6c9f0fce718bcf18ad (patch) | |
tree | 831cef10aa7728cff1fe109ba5f6ee8dad4e3225 /drivers/block/drbd/drbd_state.h | |
parent | f221f4bcc5f40e2967e4596ef167bdbc987c8e9d (diff) | |
download | linux-a88215312c5ed74697973f6c9f0fce718bcf18ad.tar.xz |
drbd: fix race between role change and handshake
Symptoms:
If DRBD was "cleanly shut down" (all in sync, both Secondary before
disconnect, identical data generation uuids), and then one side was
promoted *during* the next connection handshake, the role change
could confuse the handshake.
The Primary would get stuck in WFBitmapS, the Secondary would log
unexpected cstate (Connected) in receive_bitmap
and get stuck in WFBitmapT.
Fix:
The test in is_valid_soft_transition wrong. It works because
the not allowed actions (promote/attach) do not touch the
cstate. The previous condition failed to demand a cstate change
in one clause.
In order to avoid deadlocks give up the state_mutex while waiting
for the transient state to go away.
Conflicts:
drbd/drbd_state.c
drbd/drbd_state.h
drbd/drbd_wrappers.h
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block/drbd/drbd_state.h')
-rw-r--r-- | drivers/block/drbd/drbd_state.h | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index cc41605ba21c..7f53c40823cd 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h @@ -117,6 +117,11 @@ extern enum drbd_state_rv _drbd_request_state(struct drbd_device *, union drbd_state, union drbd_state, enum chg_state_flags); + +extern enum drbd_state_rv +_drbd_request_state_holding_state_mutex(struct drbd_device *, union drbd_state, + union drbd_state, enum chg_state_flags); + extern enum drbd_state_rv __drbd_set_state(struct drbd_device *, union drbd_state, enum chg_state_flags, struct completion *done); |