diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2012-03-26 10:47:11 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-05-09 09:16:55 -0400 |
commit | 197296ffed71b7d5056d8618a07fec145b040303 (patch) | |
tree | 7ee407b7f0536fb2cf7911ab0d7e48acce81cd4e /drivers/block | |
parent | 46385c84acd6654d3a38c9c7af1921dbded74aa2 (diff) |
drbd: Delay/reject other state changes while establishing a connection
Changes to the role and disk state should be delayed or rejected
while we establish a connection.
This is necessary, since the peer will base its resync decision
on the UUIDs and the state we sent in the drbd_connect() function.
The most prominent example for this race is becoming primary after
sending state and UUIDs and before the state changes to C_WF_CONNECTION.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 1 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 13 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 2 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 10 |
4 files changed, 24 insertions, 2 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 746f7933bf86..f215ad430bb8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -850,6 +850,7 @@ enum { | |||
850 | NEW_CUR_UUID, /* Create new current UUID when thawing IO */ | 850 | NEW_CUR_UUID, /* Create new current UUID when thawing IO */ |
851 | AL_SUSPENDED, /* Activity logging is currently suspended. */ | 851 | AL_SUSPENDED, /* Activity logging is currently suspended. */ |
852 | AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ | 852 | AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ |
853 | STATE_SENT, /* Do not change state/UUIDs while this is set */ | ||
853 | }; | 854 | }; |
854 | 855 | ||
855 | struct drbd_bitmap; /* opaque for drbd_conf */ | 856 | struct drbd_bitmap; /* opaque for drbd_conf */ |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 519f286a4299..deccff3af774 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -841,6 +841,13 @@ is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, | |||
841 | if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS) | 841 | if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS) |
842 | rv = SS_IN_TRANSIENT_STATE; | 842 | rv = SS_IN_TRANSIENT_STATE; |
843 | 843 | ||
844 | /* While establishing a connection only allow cstate to change. | ||
845 | Delay/refuse role changes, detach attach etc... */ | ||
846 | if (test_bit(STATE_SENT, &mdev->flags) && | ||
847 | !(os.conn == C_WF_REPORT_PARAMS || | ||
848 | (ns.conn == C_WF_REPORT_PARAMS && os.conn == C_WF_CONNECTION))) | ||
849 | rv = SS_IN_TRANSIENT_STATE; | ||
850 | |||
844 | if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) | 851 | if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) |
845 | rv = SS_NEED_CONNECTION; | 852 | rv = SS_NEED_CONNECTION; |
846 | 853 | ||
@@ -1668,6 +1675,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1668 | if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) | 1675 | if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) |
1669 | drbd_send_state(mdev, ns); | 1676 | drbd_send_state(mdev, ns); |
1670 | 1677 | ||
1678 | /* Wake up role changes, that were delayed because of connection establishing */ | ||
1679 | if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS) { | ||
1680 | clear_bit(STATE_SENT, &mdev->flags); | ||
1681 | wake_up(&mdev->state_wait); | ||
1682 | } | ||
1683 | |||
1671 | /* This triggers bitmap writeout of potentially still unwritten pages | 1684 | /* This triggers bitmap writeout of potentially still unwritten pages |
1672 | * if the resync finished cleanly, or aborted because of peer disk | 1685 | * if the resync finished cleanly, or aborted because of peer disk |
1673 | * failure, or because of connection loss. | 1686 | * failure, or because of connection loss. |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 1bbbad302ae7..308beb8c0c1e 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -289,7 +289,7 @@ static int _try_outdate_peer_async(void *data) | |||
289 | */ | 289 | */ |
290 | spin_lock_irq(&mdev->req_lock); | 290 | spin_lock_irq(&mdev->req_lock); |
291 | ns = mdev->state; | 291 | ns = mdev->state; |
292 | if (ns.conn < C_WF_REPORT_PARAMS) { | 292 | if (ns.conn < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &mdev->flags)) { |
293 | ns.pdsk = nps; | 293 | ns.pdsk = nps; |
294 | _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); | 294 | _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); |
295 | } | 295 | } |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index d601501c336a..9db93ff11c02 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -751,6 +751,7 @@ static int drbd_connect(struct drbd_conf *mdev) | |||
751 | { | 751 | { |
752 | struct socket *s, *sock, *msock; | 752 | struct socket *s, *sock, *msock; |
753 | int try, h, ok; | 753 | int try, h, ok; |
754 | enum drbd_state_rv rv; | ||
754 | 755 | ||
755 | D_ASSERT(!mdev->data.socket); | 756 | D_ASSERT(!mdev->data.socket); |
756 | 757 | ||
@@ -897,6 +898,7 @@ retry: | |||
897 | 898 | ||
898 | if (drbd_send_protocol(mdev) == -1) | 899 | if (drbd_send_protocol(mdev) == -1) |
899 | return -1; | 900 | return -1; |
901 | set_bit(STATE_SENT, &mdev->flags); | ||
900 | drbd_send_sync_param(mdev, &mdev->sync_conf); | 902 | drbd_send_sync_param(mdev, &mdev->sync_conf); |
901 | drbd_send_sizes(mdev, 0, 0); | 903 | drbd_send_sizes(mdev, 0, 0); |
902 | drbd_send_uuids(mdev); | 904 | drbd_send_uuids(mdev); |
@@ -904,7 +906,13 @@ retry: | |||
904 | clear_bit(USE_DEGR_WFC_T, &mdev->flags); | 906 | clear_bit(USE_DEGR_WFC_T, &mdev->flags); |
905 | clear_bit(RESIZE_PENDING, &mdev->flags); | 907 | clear_bit(RESIZE_PENDING, &mdev->flags); |
906 | 908 | ||
907 | if (drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) | 909 | spin_lock_irq(&mdev->req_lock); |
910 | rv = _drbd_set_state(_NS(mdev, conn, C_WF_REPORT_PARAMS), CS_VERBOSE, NULL); | ||
911 | if (mdev->state.conn != C_WF_REPORT_PARAMS) | ||
912 | clear_bit(STATE_SENT, &mdev->flags); | ||
913 | spin_unlock_irq(&mdev->req_lock); | ||
914 | |||
915 | if (rv < SS_SUCCESS) | ||
908 | return 0; | 916 | return 0; |
909 | 917 | ||
910 | drbd_thread_start(&mdev->asender); | 918 | drbd_thread_start(&mdev->asender); |