From fc1dc9d77ea15e8dc07199d9f361ce13f62810d7 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Tue, 6 Nov 2007 17:00:38 +0000 Subject: [PATCH] Allow DRBD8 operation without backing storage This patch adds the following functionality: - DRBD8 devices can assemble without local storage (done by allowing None in the list of children, and making DRBD8 to ignore all children if any is None) - DRBD8 devices can attach (i.e. identify a device) which is not connected to backing storage but to the correct network ports; this is a rare case in normal operation (it's what would happen if one manually detaches the local disk, and the backing LV still exists) Reviewed-by: imsnah --- lib/backend.py | 14 +++++++++++++- lib/bdev.py | 8 +++++++- lib/objects.py | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/backend.py b/lib/backend.py index 479cea256..f85ecba95 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -722,8 +722,20 @@ def _RecursiveAssembleBD(disk, owner, as_primary): """ children = [] if disk.children: + mcn = disk.ChildrenNeeded() + if mcn == -1: + mcn = 0 # max number of Nones allowed + else: + mcn = len(disk.children) - mcn # max number of Nones for chld_disk in disk.children: - children.append(_RecursiveAssembleBD(chld_disk, owner, as_primary)) + try: + cdev = _RecursiveAssembleBD(chld_disk, owner, as_primary) + except errors.BlockDeviceError, err: + if children.count(None) > mcn: + raise + cdev = None + logger.Debug("Error in child activation: %s" % str(err)) + children.append(cdev) if as_primary or disk.AssembleOnSecondary(): r_dev = bdev.AttachOrAssemble(disk.dev_type, disk.physical_id, children) diff --git a/lib/bdev.py b/lib/bdev.py index 8a80a4c1c..abedc90c2 100644 --- a/lib/bdev.py +++ b/lib/bdev.py @@ -1566,6 +1566,8 @@ class DRBD8(BaseDRBD): _PARSE_SHOW = None def __init__(self, unique_id, children): + if children and children.count(None) > 0: + children = [] super(DRBD8, self).__init__(unique_id, children) self.major = self._DRBD_MAJOR [kmaj, kmin, kfix, api, proto] = self._GetVersion() @@ -2030,6 +2032,10 @@ class DRBD8(BaseDRBD): "C") if res_r and self._MatchesNet(self._GetDevInfo(minor)): break + # the weakest case: we find something that is only net attached + # even though we were passed some children at init time + if match_r and "local_dev" not in info: + break else: minor = None @@ -2066,7 +2072,7 @@ class DRBD8(BaseDRBD): minor = self._FindUnusedMinor() need_localdev_teardown = False - if self._children[0]: + if self._children and self._children[0] and self._children[1]: result = self._AssembleLocal(minor, self._children[0].dev_path, self._children[1].dev_path) if not result: diff --git a/lib/objects.py b/lib/objects.py index 9d199c577..507e43d55 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -338,6 +338,22 @@ class Disk(ConfigObject): return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1]) return None + def ChildrenNeeded(self): + """Compute the needed number of children for activation. + + This method will return either -1 (all children) or a positive + number denoting the minimum number of children needed for + activation (only mirrored devices will usually return >=0). + + Currently, only DRBD8 supports diskless activation (therefore we + return 0), for all other we keep the previous semantics and return + -1. + + """ + if self.dev_type == constants.LD_DRBD8: + return 0 + return -1 + def GetNodes(self, node): """This function returns the nodes this device lives on. -- GitLab