commit be9150ea394217572add47a29bd2d293484962db
Author: Bernardo Dal Seno <bdalseno@google.com>
Date:   Thu Jun 27 18:08:15 2013 +0200

    Limit the PVs used for disk growth with exclusive storage
    
    The exclusive storage flag is passed along in the backend functions for
    disk growth. LVM volumes handles the flag by reusing the same PVs, as disks
    are constrained by the number of their spindles.
    
    Signed-off-by: Bernardo Dal Seno <bdalseno@google.com>
    Reviewed-by: Klaus Aehlig <aehlig@google.com>

diff --git a/lib/backend.py b/lib/backend.py
index a89c55a..ecc37d4 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -2853,7 +2853,7 @@ def DiagnoseExtStorage(top_dirs=None):
   return result
 
 
-def BlockdevGrow(disk, amount, dryrun, backingstore):
+def BlockdevGrow(disk, amount, dryrun, backingstore, excl_stor):
   """Grow a stack of block devices.
 
   This function is called recursively, with the childrens being the
@@ -2870,6 +2870,8 @@ def BlockdevGrow(disk, amount, dryrun, backingstore):
       only, or on "logical" storage only; e.g. DRBD is logical storage,
       whereas LVM, file, RBD are backing storage
   @rtype: (status, result)
+  @type excl_stor: boolean
+  @param excl_stor: Whether exclusive_storage is active
   @return: a tuple with the status of the operation (True/False), and
       the errors message if status is False
 
@@ -2879,7 +2881,7 @@ def BlockdevGrow(disk, amount, dryrun, backingstore):
     _Fail("Cannot find block device %s", disk)
 
   try:
-    r_dev.Grow(amount, dryrun, backingstore)
+    r_dev.Grow(amount, dryrun, backingstore, excl_stor)
   except errors.BlockDeviceError, err:
     _Fail("Failed to grow block device: %s", err, exc=True)
 
diff --git a/lib/server/noded.py b/lib/server/noded.py
index 861e01c..ba3123e 100644
--- a/lib/server/noded.py
+++ b/lib/server/noded.py
@@ -368,7 +368,8 @@ class NodeRequestHandler(http.server.HttpServerHandler):
     amount = params[1]
     dryrun = params[2]
     backingstore = params[3]
-    return backend.BlockdevGrow(cfbd, amount, dryrun, backingstore)
+    excl_stor = params[4]
+    return backend.BlockdevGrow(cfbd, amount, dryrun, backingstore, excl_stor)
 
   @staticmethod
   def perspective_blockdev_close(params):
diff --git a/lib/storage/base.py b/lib/storage/base.py
index 5f58b6e..8769530 100644
--- a/lib/storage/base.py
+++ b/lib/storage/base.py
@@ -298,7 +298,7 @@ class BlockDev(object):
     for child in self._children:
       child.SetInfo(text)
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Grow the block device.
 
     @type amount: integer
@@ -309,6 +309,8 @@ class BlockDev(object):
     @param backingstore: whether to execute the operation on backing storage
         only, or on "logical" storage only; e.g. DRBD is logical storage,
         whereas LVM, file, RBD are backing storage
+    @type excl_stor: boolean
+    @param excl_stor: Whether exclusive_storage is active
 
     """
     raise NotImplementedError
diff --git a/lib/storage/bdev.py b/lib/storage/bdev.py
index dfb1acc..6d0a3ec 100644
--- a/lib/storage/bdev.py
+++ b/lib/storage/bdev.py
@@ -753,7 +753,7 @@ class LogicalVolume(base.BlockDev):
 
     _CheckResult(utils.RunCmd(["lvchange", "--addtag", text, self.dev_path]))
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Grow the logical volume.
 
     """
@@ -771,12 +771,19 @@ class LogicalVolume(base.BlockDev):
     cmd = ["lvextend", "-L", "+%dk" % amount]
     if dryrun:
       cmd.append("--test")
+    if excl_stor:
+      # Disk growth doesn't grow the number of spindles, so we must stay within
+      # our assigned volumes
+      pvlist = list(self.pv_names)
+    else:
+      pvlist = []
     # we try multiple algorithms since the 'best' ones might not have
     # space available in the right place, but later ones might (since
     # they have less constraints); also note that only recent LVM
     # supports 'cling'
     for alloc_policy in "contiguous", "cling", "normal":
-      result = utils.RunCmd(cmd + ["--alloc", alloc_policy, self.dev_path])
+      result = utils.RunCmd(cmd + ["--alloc", alloc_policy, self.dev_path] +
+                            pvlist)
       if not result.failed:
         return
     base.ThrowError("Can't grow LV %s: %s", self.dev_path, result.output)
@@ -867,7 +874,7 @@ class FileStorage(base.BlockDev):
     # TODO: implement rename for file-based storage
     base.ThrowError("Rename is not supported for file-based storage")
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Grow the file
 
     @param amount: the amount (in mebibytes) to grow with
@@ -1055,7 +1062,7 @@ class PersistentBlockDevice(base.BlockDev):
     """
     pass
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Grow the logical volume.
 
     """
@@ -1382,7 +1389,7 @@ class RADOSBlockDevice(base.BlockDev):
     """
     pass
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Grow the Volume.
 
     @type amount: integer
@@ -1545,7 +1552,7 @@ class ExtStorageDevice(base.BlockDev):
     """
     pass
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Grow the Volume.
 
     @type amount: integer
diff --git a/lib/storage/drbd.py b/lib/storage/drbd.py
index 14f1a1f..4b62e86 100644
--- a/lib/storage/drbd.py
+++ b/lib/storage/drbd.py
@@ -950,7 +950,7 @@ class DRBD8Dev(base.BlockDev):
     """
     raise errors.ProgrammerError("Can't rename a drbd device")
 
-  def Grow(self, amount, dryrun, backingstore):
+  def Grow(self, amount, dryrun, backingstore, excl_stor):
     """Resize the DRBD device and its backing storage.
 
     See L{BlockDev.Grow} for parameter description.
@@ -960,7 +960,7 @@ class DRBD8Dev(base.BlockDev):
       base.ThrowError("drbd%d: Grow called while not attached", self._aminor)
     if len(self._children) != 2 or None in self._children:
       base.ThrowError("drbd%d: cannot grow diskless device", self.minor)
-    self._children[0].Grow(amount, dryrun, backingstore)
+    self._children[0].Grow(amount, dryrun, backingstore, excl_stor)
     if dryrun or backingstore:
       # DRBD does not support dry-run mode and is not backing storage,
       # so we'll return here
