aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2012-03-26 10:47:11 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-05-09 09:16:55 -0400
commit197296ffed71b7d5056d8618a07fec145b040303 (patch)
tree7ee407b7f0536fb2cf7911ab0d7e48acce81cd4e /drivers/block
parent46385c84acd6654d3a38c9c7af1921dbded74aa2 (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.h1
-rw-r--r--drivers/block/drbd/drbd_main.c13
-rw-r--r--drivers/block/drbd/drbd_nl.c2
-rw-r--r--drivers/block/drbd/drbd_receiver.c10
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
855struct drbd_bitmap; /* opaque for drbd_conf */ 856struct 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);