From 7d585316707fe23af93c111be71f5b120a7528b2 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Fri, 9 Jan 2009 15:34:25 +0000
Subject: [PATCH] Work around a DRBD sync speed race condition

This is modified forward-port of commit 1544 on the 1.2 branch:

  When DRBD is doing its dance to establish a connection with its
  peer, it also sends the synchronization speed over the wire. In
  some cases setting the sync speed only after setting up both
  sides can race with DRBD connecting, hence we set it here before
  telling DRBD anything about its peer.

  Reviewed-by: iustinp

The modification we make is that we split SetSyncSpeed in two so that we
don't need to modify our minor temporarily, and the fact that we call
this function from within _AssembleNet (right before enabling network),
instead of Assemble()/Attach().

Original-Author: imsnah
---
 lib/bdev.py | 45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/lib/bdev.py b/lib/bdev.py
index 21d79dbdb..d609f1025 100644
--- a/lib/bdev.py
+++ b/lib/bdev.py
@@ -1056,6 +1056,14 @@ class DRBD8(BaseDRBD):
       # sure its shutdown
       return cls._ShutdownNet(minor)
 
+    # Workaround for a race condition. When DRBD is doing its dance to
+    # establish a connection with its peer, it also sends the
+    # synchronization speed over the wire. In some cases setting the
+    # sync speed only after setting up both sides can race with DRBD
+    # connecting, hence we set it here before telling DRBD anything
+    # about its peer.
+    cls._SetMinorSyncSpeed(minor, constants.SYNC_SPEED)
+
     args = ["drbdsetup", cls._DevPath(minor), "net",
             "%s:%s" % (lhost, lport), "%s:%s" % (rhost, rport), protocol,
             "-A", "discard-zero-changes",
@@ -1145,20 +1153,41 @@ class DRBD8(BaseDRBD):
       raise errors.BlockDeviceError("Can't detach from local storage")
     self._children = []
 
-  def SetSyncSpeed(self, kbytes):
+  @classmethod
+  def _SetMinorSyncSpeed(cls, minor, kbytes):
     """Set the speed of the DRBD syncer.
 
+    This is the low-level implementation.
+
+    @type minor: int
+    @param minor: the drbd minor whose settings we change
+    @type kbytes: int
+    @param kbytes: the speed in kbytes/second
+    @rtype: boolean
+    @return: the success of the operation
+
     """
-    children_result = super(DRBD8, self).SetSyncSpeed(kbytes)
-    if self.minor is None:
-      logging.info("Instance not attached to a device")
-      return False
-    result = utils.RunCmd(["drbdsetup", self.dev_path, "syncer", "-r", "%d" %
-                           kbytes])
+    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "syncer",
+                           "-r", "%d" % kbytes, "--create-device"])
     if result.failed:
       logging.error("Can't change syncer rate: %s - %s",
                     result.fail_reason, result.output)
-    return not result.failed and children_result
+    return not result.failed
+
+  def SetSyncSpeed(self, kbytes):
+    """Set the speed of the DRBD syncer.
+
+    @type kbytes: int
+    @param kbytes: the speed in kbytes/second
+    @rtype: boolean
+    @return: the success of the operation
+
+    """
+    if self.minor is None:
+      logging.info("Not attached during SetSyncSpeed")
+      return False
+    children_result = super(DRBD8, self).SetSyncSpeed(kbytes)
+    return self._SetMinorSyncSpeed(self.minor, kbytes) and children_result
 
   def GetProcStatus(self):
     """Return device data from /proc.
-- 
GitLab