DRBD: check for in-use minor during Create
authorIustin Pop <iustin@google.com>
Tue, 20 Jan 2009 11:18:31 +0000 (11:18 +0000)
committerIustin Pop <iustin@google.com>
Tue, 20 Jan 2009 11:18:31 +0000 (11:18 +0000)
In order to prevent errors with old, in-use DRBD minors, we check and
abort at create time if our minor is already in use. For this we need to
also modify DRBD8Status to be able to parse cs:Unconfigured devices.

Reviewed-by: ultrotter

lib/bdev.py
test/ganeti.bdev_unittest.py

index f1ade2e..9207e2c 100644 (file)
@@ -540,20 +540,28 @@ class DRBD8Status(object):
   Note that this doesn't support unconfigured devices (cs:Unconfigured).
 
   """
+  UNCONF_RE = re.compile(r"\s*[0-9]+:\s*cs:Unconfigured$")
   LINE_RE = re.compile(r"\s*[0-9]+:\s*cs:(\S+)\s+st:([^/]+)/(\S+)"
                        "\s+ds:([^/]+)/(\S+)\s+.*$")
   SYNC_RE = re.compile(r"^.*\ssync'ed:\s*([0-9.]+)%.*"
                        "\sfinish: ([0-9]+):([0-9]+):([0-9]+)\s.*$")
 
   def __init__(self, procline):
-    m = self.LINE_RE.match(procline)
-    if not m:
-      raise errors.BlockDeviceError("Can't parse input data '%s'" % procline)
-    self.cstatus = m.group(1)
-    self.lrole = m.group(2)
-    self.rrole = m.group(3)
-    self.ldisk = m.group(4)
-    self.rdisk = m.group(5)
+    u = self.UNCONF_RE.match(procline)
+    if u:
+      self.cstatus = "Unconfigured"
+      self.lrole = self.rrole = self.ldisk = self.rdisk = None
+    else:
+      m = self.LINE_RE.match(procline)
+      if not m:
+        raise errors.BlockDeviceError("Can't parse input data '%s'" % procline)
+      self.cstatus = m.group(1)
+      self.lrole = m.group(2)
+      self.rrole = m.group(3)
+      self.ldisk = m.group(4)
+      self.rdisk = m.group(5)
+
+    # end reading of data from the LINE_RE or UNCONF_RE
 
     self.is_standalone = self.cstatus == "StandAlone"
     self.is_wfconn = self.cstatus == "WFConnection"
@@ -568,7 +576,8 @@ class DRBD8Status(object):
     self.is_diskless = self.ldisk == "Diskless"
     self.is_disk_uptodate = self.ldisk == "UpToDate"
 
-    self.is_in_resync = self.cstatus in ('SyncSource', 'SyncTarget')
+    self.is_in_resync = self.cstatus in ("SyncSource", "SyncTarget")
+    self.is_in_use = self.cstatus != "Unconfigured"
 
     m = self.SYNC_RE.match(procline)
     if m:
@@ -1525,6 +1534,17 @@ class DRBD8(BaseDRBD):
     """
     if len(children) != 2:
       raise errors.ProgrammerError("Invalid setup for the drbd device")
+    # check that the minor is unused
+    aminor = unique_id[4]
+    proc_info = cls._MassageProcData(cls._GetProcData())
+    if aminor in proc_info:
+      status = DRBD8Status(proc_info[aminor])
+      in_use = status.is_in_use
+    else:
+      in_use = False
+    if in_use:
+      raise errors.BlockDeviceError("DRBD minor %d already in use at"
+                                    " Create() time" % aminor)
     meta = children[1]
     meta.Assemble()
     if not meta.Attach():
index 04823eb..6b71768 100755 (executable)
@@ -117,18 +117,26 @@ class TestDRBD8Status(testutils.GanetiTestCase):
   def testMinor0(self):
     """Test connected, primary device"""
     stats = bdev.DRBD8Status(self.mass_data[0])
+    self.failUnless(stats.is_in_use)
     self.failUnless(stats.is_connected and stats.is_primary and
                     stats.peer_secondary and stats.is_disk_uptodate)
 
   def testMinor1(self):
     """Test connected, secondary device"""
     stats = bdev.DRBD8Status(self.mass_data[1])
+    self.failUnless(stats.is_in_use)
     self.failUnless(stats.is_connected and stats.is_secondary and
                     stats.peer_primary and stats.is_disk_uptodate)
 
+  def testMinor2(self):
+    """Test unconfigured device"""
+    stats = bdev.DRBD8Status(self.mass_data[2])
+    self.failIf(stats.is_in_use)
+
   def testMinor4(self):
     """Test WFconn device"""
     stats = bdev.DRBD8Status(self.mass_data[4])
+    self.failUnless(stats.is_in_use)
     self.failUnless(stats.is_wfconn and stats.is_primary and
                     stats.rrole == 'Unknown' and
                     stats.is_disk_uptodate)
@@ -136,12 +144,14 @@ class TestDRBD8Status(testutils.GanetiTestCase):
   def testMinor6(self):
     """Test diskless device"""
     stats = bdev.DRBD8Status(self.mass_data[6])
+    self.failUnless(stats.is_in_use)
     self.failUnless(stats.is_connected and stats.is_secondary and
                     stats.peer_primary and stats.is_diskless)
 
   def testMinor8(self):
     """Test standalone device"""
     stats = bdev.DRBD8Status(self.mass_data[8])
+    self.failUnless(stats.is_in_use)
     self.failUnless(stats.is_standalone and
                     stats.rrole == 'Unknown' and
                     stats.is_disk_uptodate)