From 1a4fb0b89bd90de200233fd40db00451cd55cc53 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Mon, 27 Jun 2022 14:33:37 +1200 Subject: [PATCH] Do dmsetup remove device in rollback Without this change, the final unmount will timeout after the rollbacks are called when the partitioning fails due to a user error. dmsetup remove is called both for partition and LVM volume devices. Change-Id: I99679ea00338d4018a95d4da9b21685161cd5049 --- diskimage_builder/block_device/level1/lvm.py | 5 ++++- .../block_device/level1/partitioning.py | 14 +++++++++----- diskimage_builder/block_device/utils.py | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/diskimage_builder/block_device/level1/lvm.py b/diskimage_builder/block_device/level1/lvm.py index f86f09e3a..84fcef016 100644 --- a/diskimage_builder/block_device/level1/lvm.py +++ b/diskimage_builder/block_device/level1/lvm.py @@ -20,6 +20,7 @@ from diskimage_builder.block_device.plugin import NodeBase from diskimage_builder.block_device.plugin import PluginBase from diskimage_builder.block_device.utils import exec_sudo from diskimage_builder.block_device.utils import parse_abs_size_spec +from diskimage_builder.block_device.utils import remove_device PHYSICAL_EXTENT_BYTES = parse_abs_size_spec('4MiB') @@ -211,13 +212,15 @@ class LvsNode(NodeBase): exec_sudo(cmd) # save state + device_name = '%s-%s' % (self.base, self.name) self.state['blockdev'][self.name] = { 'vgs': self.base, 'size': self.size, 'extents': self.extents, 'opts': self.options, - 'device': '/dev/mapper/%s-%s' % (self.base, self.name) + 'device': '/dev/mapper/%s' % device_name } + self.add_rollback(remove_device, device_name) def _umount(self): exec_sudo(['lvchange', '-an', diff --git a/diskimage_builder/block_device/level1/partitioning.py b/diskimage_builder/block_device/level1/partitioning.py index 078fd6a70..31ef8e54c 100644 --- a/diskimage_builder/block_device/level1/partitioning.py +++ b/diskimage_builder/block_device/level1/partitioning.py @@ -23,6 +23,7 @@ from diskimage_builder.block_device.plugin import PluginBase from diskimage_builder.block_device.utils import exec_sudo from diskimage_builder.block_device.utils import parse_abs_size_spec from diskimage_builder.block_device.utils import parse_rel_size_spec +from diskimage_builder.block_device.utils import remove_device logger = logging.getLogger(__name__) @@ -117,10 +118,11 @@ class Partitioning(PluginBase): # below once we're done. So the device this partition # will be seen at becomes "/dev/mapper/loop0pX" assert self.device_path[:5] == "/dev/" - partition_device_name = "/dev/mapper/%sp%d" % \ - (self.device_path[5:], part_no) + device_name = "%sp%d" % (self.device_path[5:], part_no) + device_path = "/dev/mapper/%s" % device_name self.state['blockdev'][part_name] \ - = {'device': partition_device_name} + = {'device': device_path} + part_cfg.add_rollback(remove_device, device_name) def _create_gpt(self): """Create partitions with GPT""" @@ -158,14 +160,16 @@ class Partitioning(PluginBase): # below once we're done. So the device this partition # will be seen at becomes "/dev/mapper/loop0pX" assert self.device_path[:5] == "/dev/" - device_name = "/dev/mapper/%sp%d" % (self.device_path[5:], pnum) + device_name = "%sp%d" % (self.device_path[5:], pnum) + device_path = "/dev/mapper/%s" % device_name self.state['blockdev'][p.get_name()] \ - = {'device': device_name} + = {'device': device_path} disk_free = disk_free - size pnum = pnum + 1 logger.debug("Partition %s added, %s remaining in disk", pnum, disk_free) + p.add_rollback(remove_device, device_name) logger.debug("cmd: %s", ' '.join(cmd)) exec_sudo(cmd) diff --git a/diskimage_builder/block_device/utils.py b/diskimage_builder/block_device/utils.py index ad4ab95c5..e0ea05e7b 100644 --- a/diskimage_builder/block_device/utils.py +++ b/diskimage_builder/block_device/utils.py @@ -143,3 +143,20 @@ def exec_sudo(cmd): raise e return out + + +def remove_device(device_name): + """Attempt to remove a device-mapper device + + Convenience rollback function to attempt to delete a device, + logging a warning if the delete fails. + + :param device_name: Name of device to run dmsetup remove on + """ + logger.debug('Removing device %s', device_name) + try: + exec_sudo(["dmsetup", "remove", device_name]) + except BlockDeviceSetupException as e: + # Do not raise an error - maybe other cleanup methods + # can at least do some more work. + logger.warning("Removing device failed (%s)", e.returncode)