Fix NODE/NODE_RES locking in LUInstanceCreate
authorThomas Thrainer <thomasth@google.com>
Mon, 25 Nov 2013 10:37:06 +0000 (11:37 +0100)
committerThomas Thrainer <thomasth@google.com>
Wed, 27 Nov 2013 12:44:30 +0000 (13:44 +0100)
Both NODE and NODE_RES locks were acquired opportunistically if so
requested by the user. LUInstanceCreate requires, however, that the
actually locked elements on NODE and NODE_RES level are the same.

This patch changes the locking of NODE_RES such that those locks are not
acquired opportunistically any more. Instead, the mandatory locks are
set to the acquired NODE locks once they are actually granted.

This fixes issue 622.

Signed-off-by: Thomas Thrainer <thomasth@google.com>
Reviewed-by: Petr Pudlak <pudlak@google.com>

lib/cmdlib/instance.py

index c0c3070..12340e8 100644 (file)
@@ -524,7 +524,6 @@ class LUInstanceCreate(LogicalUnit):
 
       if self.op.opportunistic_locking:
         self.opportunistic_locks[locking.LEVEL_NODE] = True
-        self.opportunistic_locks[locking.LEVEL_NODE_RES] = True
     else:
       self.op.pnode = ExpandNodeName(self.cfg, self.op.pnode)
       nodelist = [self.op.pnode]
@@ -560,6 +559,14 @@ class LUInstanceCreate(LogicalUnit):
     self.needed_locks[locking.LEVEL_NODE_RES] = \
       CopyLockList(self.needed_locks[locking.LEVEL_NODE])
 
+  def DeclareLocks(self, level):
+    if level == locking.LEVEL_NODE_RES and \
+      self.opportunistic_locks[locking.LEVEL_NODE]:
+      # Even when using opportunistic locking, we require the same set of
+      # NODE_RES locks as we got NODE locks
+      self.needed_locks[locking.LEVEL_NODE_RES] = \
+        self.owned_locks(locking.LEVEL_NODE)
+
   def _RunAllocator(self):
     """Run the allocator based on input opcode.
 
@@ -1873,7 +1880,6 @@ class LUInstanceMultiAlloc(NoHooksLU):
 
       if self.op.opportunistic_locking:
         self.opportunistic_locks[locking.LEVEL_NODE] = True
-        self.opportunistic_locks[locking.LEVEL_NODE_RES] = True
     else:
       nodeslist = []
       for inst in self.op.instances:
@@ -1888,6 +1894,14 @@ class LUInstanceMultiAlloc(NoHooksLU):
       # prevent accidential modification)
       self.needed_locks[locking.LEVEL_NODE_RES] = list(nodeslist)
 
+  def DeclareLocks(self, level):
+    if level == locking.LEVEL_NODE_RES and \
+      self.opportunistic_locks[locking.LEVEL_NODE]:
+      # Even when using opportunistic locking, we require the same set of
+      # NODE_RES locks as we got NODE locks
+      self.needed_locks[locking.LEVEL_NODE_RES] = \
+        self.owned_locks(locking.LEVEL_NODE)
+
   def CheckPrereq(self):
     """Check prerequisite.