aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2012-11-22 11:06:00 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-12-06 07:00:33 -0500
commit13c76aba7846647f86d479293ae0a0adc1ca840a (patch)
treea729c2b6f77403829c712f118d3cc1ff65d901b7
parent691631c0652bc47e6d20b0d981e23a9025fd794e (diff)
drbd: close race between drbd_set_role and drbd_connect
drbd_set_role(, R_PRIMARY, ) does the state change to Primary, some more housekeeping, and possibly generates a new UUID set. All of this holding the "state_mutex". The connection handshake involves sending of various state information, including the current data generation UUID set, and two connection state changes from C_WF_CONNECTION to C_WF_REPORT_PARAMS further to a number of different outcomes, resync being one of them. If the connection handshake happens between the state change to Primary and the generation of the new UUIDs, the resync decision based on the old UUID set may be confused, depending on circumstances. Make sure that, before we do the handshake, any promotion to Primary role will either be complete (including the housekeeping stuff), or can see, and serialize with, the ongoing handshake, based on the "STATE_SENT" bit, which is set when we start the handshake, and cleared only when we leave C_WF_REPORT_PARAMS again. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r--drivers/block/drbd/drbd_receiver.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 1599a1a6f1f7..a9eccfc6079b 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1037,6 +1037,16 @@ randomize:
1037 rcu_read_lock(); 1037 rcu_read_lock();
1038 idr_for_each_entry(&tconn->volumes, mdev, vnr) { 1038 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1039 kref_get(&mdev->kref); 1039 kref_get(&mdev->kref);
1040 /* Prevent a race between resync-handshake and
1041 * being promoted to Primary.
1042 *
1043 * Grab and release the state mutex, so we know that any current
1044 * drbd_set_role() is finished, and any incoming drbd_set_role
1045 * will see the STATE_SENT flag, and wait for it to be cleared.
1046 */
1047 mutex_lock(mdev->state_mutex);
1048 mutex_unlock(mdev->state_mutex);
1049
1040 rcu_read_unlock(); 1050 rcu_read_unlock();
1041 1051
1042 if (discard_my_data) 1052 if (discard_my_data)