diff --git a/lib/config.py b/lib/config.py
index f34aa9e75aa634ffaadca856572b62ef4200d3b3..9884d9242969c8bc9d63d9f507328136412f7efe 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -227,10 +227,13 @@ class ConfigWriter:
 
     return result
 
-  @locking.ssynchronized(_config_lock, shared=1)
-  def VerifyConfig(self):
+  def _UnlockedVerifyConfig(self):
     """Verify function.
 
+    @rtype: list
+    @return: a list of error messages; a non-empty list signifies
+        configuration errors
+
     """
     result = []
     seen_macs = []
@@ -290,13 +293,33 @@ class ConfigWriter:
     if not data.nodes[data.cluster.master_node].master_candidate:
       result.append("Master node is not a master candidate")
 
+    # master candidate checks
     mc_now, mc_max = self._UnlockedGetMasterCandidateStats()
     if mc_now < mc_max:
       result.append("Not enough master candidates: actual %d, target %d" %
                     (mc_now, mc_max))
 
+    # drbd minors check
+    d_map, duplicates = self._UnlockedComputeDRBDMap()
+    for node, minor, instance_a, instance_b in duplicates:
+      result.append("DRBD minor %d on node %s is assigned twice to instances"
+                    " %s and %s" % (minor, node, instance_a, instance_b))
+
     return result
 
+  @locking.ssynchronized(_config_lock, shared=1)
+  def VerifyConfig(self):
+    """Verify function.
+
+    This is just a wrapper over L{_UnlockedVerifyConfig}.
+
+    @rtype: list
+    @return: a list of error messages; a non-empty list signifies
+        configuration errors
+
+    """
+    return self._UnlockedVerifyConfig()
+
   def _UnlockedSetDiskID(self, disk, node_name):
     """Convert the unique ID to the ID needed on the target nodes.
 
@@ -392,34 +415,41 @@ class ConfigWriter:
   def _UnlockedComputeDRBDMap(self):
     """Compute the used DRBD minor/nodes.
 
+    @rtype: (dict, list)
     @return: dictionary of node_name: dict of minor: instance_name;
         the returned dict will have all the nodes in it (even if with
-        an empty list).
+        an empty list), and a list of duplicates; if the duplicates
+        list is not empty, the configuration is corrupted and its caller
+        should raise an exception
 
     """
     def _AppendUsedPorts(instance_name, disk, used):
+      duplicates = []
       if disk.dev_type == constants.LD_DRBD8 and len(disk.logical_id) >= 5:
         nodeA, nodeB, dummy, minorA, minorB = disk.logical_id[:5]
         for node, port in ((nodeA, minorA), (nodeB, minorB)):
-          assert node in used, "Instance node not found in node list"
+          assert node in used, ("Node '%s' of instance '%s' not found"
+                                " in node list" % (node, instance_name))
           if port in used[node]:
-            raise errors.ProgrammerError("DRBD minor already used:"
-                                         " %s/%s, %s/%s" %
-                                         (node, port, instance_name,
-                                          used[node][port]))
-
-          used[node][port] = instance_name
+            duplicates.append((node, port, instance_name, used[node][port]))
+          else:
+            used[node][port] = instance_name
       if disk.children:
         for child in disk.children:
-          _AppendUsedPorts(instance_name, child, used)
+          duplicates.extend(_AppendUsedPorts(instance_name, child, used))
+      return duplicates
 
+    duplicates = []
     my_dict = dict((node, {}) for node in self._config_data.nodes)
     for (node, minor), instance in self._temporary_drbds.iteritems():
-      my_dict[node][minor] = instance
+      if minor in my_dict[node]:
+        duplicates.append((node, minor, instance, my_dict[node][minor]))
+      else:
+        my_dict[node][minor] = instance
     for instance in self._config_data.instances.itervalues():
       for disk in instance.disks:
-        _AppendUsedPorts(instance.name, disk, my_dict)
-    return my_dict
+        duplicates.extend(_AppendUsedPorts(instance.name, disk, my_dict))
+    return my_dict, duplicates
 
   @locking.ssynchronized(_config_lock)
   def ComputeDRBDMap(self):
@@ -432,7 +462,11 @@ class ConfigWriter:
         an empty list).
 
     """
-    return self._UnlockedComputeDRBDMap()
+    d_map, duplicates = self._UnlockedComputeDRBDMap()
+    if duplicates:
+      raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" %
+                                      str(duplicates))
+    return d_map
 
   @locking.ssynchronized(_config_lock)
   def AllocateDRBDMinor(self, nodes, instance):
@@ -448,9 +482,12 @@ class ConfigWriter:
 
     """
     assert isinstance(instance, basestring), \
-           "Invalid argument passed to AllocateDRBDMinor"
+           "Invalid argument '%s' passed to AllocateDRBDMinor" % instance
 
-    d_map = self._UnlockedComputeDRBDMap()
+    d_map, duplicates = self._UnlockedComputeDRBDMap()
+    if duplicates:
+      raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" %
+                                      str(duplicates))
     result = []
     for nname in nodes:
       ndata = d_map[nname]
@@ -469,11 +506,20 @@ class ConfigWriter:
         minor = keys[-1] + 1
       else:
         minor = ffree
-      result.append(minor)
+      # double-check minor against current instances
+      assert minor not in d_map[nname], \
+             ("Attempt to reuse allocated DRBD minor %d on node %s,"
+              " already allocated to instance %s" %
+              (minor, nname, d_map[nname][minor]))
       ndata[minor] = instance
-      assert (nname, minor) not in self._temporary_drbds, \
-             "Attempt to reuse reserved DRBD minor"
-      self._temporary_drbds[(nname, minor)] = instance
+      # double-check minor against reservation
+      r_key = (nname, minor)
+      assert r_key not in self._temporary_drbds, \
+             ("Attempt to reuse reserved DRBD minor %d on node %s,"
+              " reserved for instance %s" %
+              (minor, nname, self._temporary_drbds[r_key]))
+      self._temporary_drbds[r_key] = instance
+      result.append(minor)
     logging.debug("Request to allocate drbd minors, input: %s, returning %s",
                   nodes, result)
     return result
@@ -973,6 +1019,11 @@ class ConfigWriter:
     """Write the configuration data to persistent storage.
 
     """
+    config_errors = self._UnlockedVerifyConfig()
+    if config_errors:
+      raise errors.ConfigurationError("Configuration data is not"
+                                      " consistent: %s" %
+                                      (", ".join(config_errors)))
     if destination is None:
       destination = self._cfg_file
     self._BumpSerialNo()
diff --git a/test/ganeti.config_unittest.py b/test/ganeti.config_unittest.py
index eb3ebc79753dab78f8ea9f892d701444a3b8fd9d..24c9491ca435724f8613cc845e2a3615ac3aa448 100755
--- a/test/ganeti.config_unittest.py
+++ b/test/ganeti.config_unittest.py
@@ -79,15 +79,17 @@ class TestConfigRunner(unittest.TestCase):
     master_node_config = objects.Node(name=me.name,
                                       primary_ip=me.ip,
                                       secondary_ip=ip,
-                                      serial_no=1)
+                                      serial_no=1,
+                                      master_candidate=True)
 
     bootstrap.InitConfig(constants.CONFIG_VERSION,
                          cluster_config, master_node_config, self.cfg_file)
 
   def _create_instance(self):
     """Create and return an instance object"""
-    inst = objects.Instance(name="test.example.com", disks=[],
-                            disk_template=constants.DT_DISKLESS)
+    inst = objects.Instance(name="test.example.com", disks=[], nics=[],
+                            disk_template=constants.DT_DISKLESS,
+                            primary_node=self._get_object().GetMasterNode())
     return inst
 
   def testEmpty(self):
diff --git a/test/mocks.py b/test/mocks.py
index bea8dd399cfc5bea7e0b2ef433f05e6f90a0990a..249cd72527d1f6713ea2d402c558c90e006d7c06 100644
--- a/test/mocks.py
+++ b/test/mocks.py
@@ -42,9 +42,6 @@ class FakeConfig:
     def GetNodeList(self):
         return ["a", "b", "c"]
 
-    def GetMaster(self):
-        return utils.HostInfo().name
-
     def GetHostKey(self):
         return FAKE_CLUSTER_KEY
 
@@ -71,4 +68,3 @@ class FakeContext:
         self.cfg = FakeConfig()
         # TODO: decide what features a mock Ganeti Lock Manager must have
         self.GLM = None
-