From 3ee2a9da6251179c47ff6c2dc5c969e79f31e9e0 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Tue, 4 Apr 2023 13:31:40 +0200 Subject: [PATCH] Add support for filesystem online resize --- blivet/devices/lvm.py | 10 ++++++---- blivet/devices/partition.py | 11 ++++++----- blivet/flags.py | 3 +++ blivet/formats/fs.py | 32 ++++++++++++++++++++++++++++---- blivet/formats/fslib.py | 7 +++++++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py index 434c359f..04e03e82 100644 --- a/blivet/devices/lvm.py +++ b/blivet/devices/lvm.py @@ -42,6 +42,7 @@ from .. import errors from .. import util from ..storage_log import log_method_call from .. import udev +from ..flags import flags from ..size import Size, KiB, MiB, ROUND_UP, ROUND_DOWN from ..static_data.lvm_info import lvs_info from ..tasks import availability @@ -2719,10 +2720,11 @@ class LVMLogicalVolumeDevice(LVMLogicalVolumeBase, LVMInternalLogicalVolumeMixin # Setup VG parents (in case they are dmraid partitions for example) self.vg.setup_parents(orig=True) - if self.original_format.exists: - self.original_format.teardown() - if self.format.exists: - self.format.teardown() + if not flags.allow_online_fs_resize: + if self.original_format.exists: + self.original_format.teardown() + if self.format.exists: + self.format.teardown() udev.settle() blockdev.lvm.lvresize(self.vg.name, self._name, self.size) diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py index e8bd2b7b..5bf3c713 100644 --- a/blivet/devices/partition.py +++ b/blivet/devices/partition.py @@ -794,11 +794,12 @@ class PartitionDevice(StorageDevice): if not self.exists: raise errors.DeviceError("device has not been created") - # don't teardown when resizing luks - if self.format.type == "luks" and self.children: - self.children[0].format.teardown() - else: - self.teardown() + if not flags.allow_online_fs_resize: + # don't teardown when resizing luks + if self.format.type == "luks" and self.children: + self.children[0].format.teardown() + else: + self.teardown() if not self.sysfs_path: return diff --git a/blivet/flags.py b/blivet/flags.py index f0034070..716f0df4 100644 --- a/blivet/flags.py +++ b/blivet/flags.py @@ -95,6 +95,9 @@ class Flags(object): # https://uapi-group.org/specifications/specs/discoverable_partitions_specification/ self.gpt_discoverable_partitions = False + # Allow online filesystem resizes + self.allow_online_fs_resize = False + def get_boot_cmdline(self): with open("/proc/cmdline") as f: buf = f.read().strip() diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py index 8df881b8..acc1f9cb 100644 --- a/blivet/formats/fs.py +++ b/blivet/formats/fs.py @@ -56,7 +56,7 @@ from ..i18n import N_ from .. import udev from ..mounts import mounts_cache -from .fslib import kernel_filesystems +from .fslib import kernel_filesystems, FSResize import logging log = logging.getLogger("blivet") @@ -88,6 +88,9 @@ class FS(DeviceFormat): # value is already unpredictable and can change in the future... _metadata_size_factor = 1.0 + # support for resize: grow/shrink, online/offline + _resize_support = 0 + config_actions_map = {"label": "write_label"} def __init__(self, **kwargs): @@ -436,12 +439,27 @@ class FS(DeviceFormat): self.write_uuid() def _pre_resize(self): - # file systems need a check before being resized - self.do_check() + if self.status: + if flags.allow_online_fs_resize: + if self.target_size > self.size and not self._resize_support & FSResize.ONLINE_GROW: + raise FSError("This filesystem doesn't support online growing") + if self.target_size < self.size and not self._resize_support & FSResize.ONLINE_SHRINK: + raise FSError("This filesystem doesn't support online shrinking") + else: + raise FSError("Resizing of mounted filesystems is disabled") + + if self.status: + # fsck tools in general don't allow checks on mounted filesystems + log.debug("Filesystem on %s is mounted, not checking", self.device) + else: + # file systems need a check before being resized + self.do_check() + super(FS, self)._pre_resize() def _post_resize(self): - self.do_check() + if not self.status: + self.do_check() super(FS, self)._post_resize() def do_check(self): @@ -838,6 +856,7 @@ class Ext2FS(FS): _formattable = True _supported = True _resizable = True + _resize_support = FSResize.ONLINE_GROW | FSResize.OFFLINE_GROW | FSResize.OFFLINE_SHRINK _linux_native = True _max_size = Size("8 TiB") _dump = True @@ -1097,6 +1116,7 @@ class XFS(FS): _linux_native = True _supported = True _resizable = True + _resize_support = FSResize.ONLINE_GROW | FSResize.OFFLINE_GROW _packages = ["xfsprogs"] _fsck_class = fsck.XFSCK _info_class = fsinfo.XFSInfo @@ -1247,6 +1267,7 @@ class NTFS(FS): _labelfs = fslabeling.NTFSLabeling() _uuidfs = fsuuid.NTFSUUID() _resizable = True + _resize_support = FSResize.OFFLINE_GROW | FSResize.OFFLINE_SHRINK _formattable = True _supported = True _min_size = Size("1 MiB") @@ -1502,6 +1523,9 @@ class TmpFS(NoDevFS): # same, nothing actually needs to be set pass + def _pre_resize(self): + self.do_check() + def do_resize(self): # Override superclass method to record whether mount options # should include an explicit size specification. diff --git a/blivet/formats/fslib.py b/blivet/formats/fslib.py index ea93b1fd..8722e942 100644 --- a/blivet/formats/fslib.py +++ b/blivet/formats/fslib.py @@ -36,3 +36,10 @@ def update_kernel_filesystems(): update_kernel_filesystems() + + +class FSResize(): + OFFLINE_SHRINK = 1 << 1 + OFFLINE_GROW = 1 << 2 + ONLINE_SHRINK = 1 << 3 + ONLINE_GROW = 1 << 4 -- 2.40.1