Skip to content
Snippets Groups Projects
Commit 197478f2 authored by René Nussbaumer's avatar René Nussbaumer
Browse files

Use free space in vg instead of biggest free pv space for a snapshot


Even for snapshot we looked at the biggest free pv space even though
the vg might have fit the snapshot we aborted if one of the pvs was too
small. This patch fixes this by looking at the vg size instead of the pv
size.

Signed-off-by: default avatarRené Nussbaumer <rn@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parent f0ca837f
No related branches found
No related tags found
No related merge requests found
...@@ -418,7 +418,40 @@ class LogicalVolume(BlockDev): ...@@ -418,7 +418,40 @@ class LogicalVolume(BlockDev):
return LogicalVolume(unique_id, children, size) return LogicalVolume(unique_id, children, size)
@staticmethod @staticmethod
def GetPVInfo(vg_names, filter_allocatable=True): def _GetVolumeInfo(lvm_cmd, fields):
"""Returns LVM Volumen infos using lvm_cmd
@param lvm_cmd: Should be one of "pvs", "vgs" or "lvs"
@param fields: Fields to return
@return: A list of dicts each with the parsed fields
"""
if not fields:
raise errors.ProgrammerError("No fields specified")
sep = "|"
cmd = [lvm_cmd, "--noheadings", "--nosuffix", "--units=m", "--unbuffered",
"--separator=%s" % sep, "-o%s" % ",".join(fields)]
result = utils.RunCmd(cmd)
if result.failed:
raise errors.CommandError("Can't get the volume information: %s - %s" %
(result.fail_reason, result.output))
data = []
for line in result.stdout.splitlines():
splitted_fields = line.strip().split(sep)
if len(fields) != len(splitted_fields):
raise errors.CommandError("Can't parse %s output: line '%s'" %
(lvm_cmd, line))
data.append(splitted_fields)
return data
@classmethod
def GetPVInfo(cls, vg_names, filter_allocatable=True):
"""Get the free space info for PVs in a volume group. """Get the free space info for PVs in a volume group.
@param vg_names: list of volume group names, if empty all will be returned @param vg_names: list of volume group names, if empty all will be returned
...@@ -428,28 +461,51 @@ class LogicalVolume(BlockDev): ...@@ -428,28 +461,51 @@ class LogicalVolume(BlockDev):
@return: list of tuples (free_space, name) with free_space in mebibytes @return: list of tuples (free_space, name) with free_space in mebibytes
""" """
sep = "|" try:
command = ["pvs", "--noheadings", "--nosuffix", "--units=m", info = cls._GetVolumeInfo("pvs", ["pv_name", "vg_name", "pv_free",
"-opv_name,vg_name,pv_free,pv_attr", "--unbuffered", "pv_attr"])
"--separator=%s" % sep ] except errors.GenericError, err:
result = utils.RunCmd(command) logging.error("Can't get PV information: %s", err)
if result.failed:
logging.error("Can't get the PV information: %s - %s",
result.fail_reason, result.output)
return None return None
data = [] data = []
for line in result.stdout.splitlines(): for pv_name, vg_name, pv_free, pv_attr in info:
fields = line.strip().split(sep)
if len(fields) != 4:
logging.error("Can't parse pvs output: line '%s'", line)
return None
# (possibly) skip over pvs which are not allocatable # (possibly) skip over pvs which are not allocatable
if filter_allocatable and fields[3][0] != 'a': if filter_allocatable and pv_attr[0] != "a":
continue continue
# (possibly) skip over pvs which are not in the right volume group(s) # (possibly) skip over pvs which are not in the right volume group(s)
if vg_names and fields[1] not in vg_names: if vg_names and vg_name not in vg_names:
continue continue
data.append((float(fields[2]), fields[0], fields[1])) data.append((float(pv_free), pv_name, vg_name))
return data
@classmethod
def GetVGInfo(cls, vg_names, filter_readonly=True):
"""Get the free space info for specific VGs.
@param vg_names: list of volume group names, if empty all will be returned
@param filter_readonly: whether to skip over readonly VGs
@rtype: list
@return: list of tuples (free_space, name) with free_space in mebibytes
"""
try:
info = cls._GetVolumeInfo("vgs", ["vg_name", "vg_free", "vg_attr"])
except errors.GenericError, err:
logging.error("Can't get VG information: %s", err)
return None
data = []
for vg_name, vg_free, vg_attr in info:
# (possibly) skip over vgs which are not writable
if filter_readonly and vg_attr[0] == "r":
continue
# (possibly) skip over vgs which are not in the right volume group(s)
if vg_names and vg_name not in vg_names:
continue
data.append((float(vg_free), vg_name))
return data return data
...@@ -643,12 +699,10 @@ class LogicalVolume(BlockDev): ...@@ -643,12 +699,10 @@ class LogicalVolume(BlockDev):
snap = LogicalVolume((self._vg_name, snap_name), None, size) snap = LogicalVolume((self._vg_name, snap_name), None, size)
_IgnoreError(snap.Remove) _IgnoreError(snap.Remove)
pvs_info = self.GetPVInfo([self._vg_name]) vg_info = self.GetVGInfo([self._vg_name])
if not pvs_info: if not vg_info:
_ThrowError("Can't compute PV info for vg %s", self._vg_name) _ThrowError("Can't compute VG info for vg %s", self._vg_name)
pvs_info.sort() free_size, _ = vg_info[0]
pvs_info.reverse()
free_size, _, _ = pvs_info[0]
if free_size < size: if free_size < size:
_ThrowError("Not enough free space: required %s," _ThrowError("Not enough free space: required %s,"
" available %s", size, free_size) " available %s", size, free_size)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment