diff --git a/0015-Add-support-for-filesystem-online-resize.patch b/0015-Add-support-for-filesystem-online-resize.patch new file mode 100644 index 0000000..39f30e8 --- /dev/null +++ b/0015-Add-support-for-filesystem-online-resize.patch @@ -0,0 +1,265 @@ +From eb16230427fc1081f8515e6ad69ccf99ca521e5d Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Tue, 4 Apr 2023 13:31:40 +0200 +Subject: [PATCH 1/2] Add support for filesystem online resize + +Resolves: rhbz#2168680 +--- + blivet/devices/lvm.py | 13 ++++++++----- + blivet/devices/partition.py | 11 ++++++----- + blivet/flags.py | 3 +++ + blivet/formats/fs.py | 32 ++++++++++++++++++++++++++++---- + blivet/formats/fslib.py | 7 +++++++ + 5 files changed, 52 insertions(+), 14 deletions(-) + +diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py +index c3132457..ca45c4b5 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 +@@ -2729,12 +2730,14 @@ 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() + +- udev.settle() + blockdev.lvm.lvresize(self.vg.name, self._name, self.size) + + @type_specific +diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py +index 0e9250ce..6ae4b8d3 100644 +--- a/blivet/devices/partition.py ++++ b/blivet/devices/partition.py +@@ -745,11 +745,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 6364164d..ecfa7ad7 100644 +--- a/blivet/flags.py ++++ b/blivet/flags.py +@@ -91,6 +91,9 @@ class Flags(object): + + self.debug_threads = 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 33922f3a..3f553eb0 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") +@@ -1490,6 +1511,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 + + +From 3fce5d0bfd7b09a976ff49feed15077477c6a425 Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Thu, 6 Apr 2023 14:02:11 +0200 +Subject: [PATCH 2/2] Add a test case for filesystem online resize + +Related: rhbz#2168680 +--- + tests/storage_tests/formats_test/fs_test.py | 43 ++++++++++++++++++++- + 1 file changed, 42 insertions(+), 1 deletion(-) + +diff --git a/tests/storage_tests/formats_test/fs_test.py b/tests/storage_tests/formats_test/fs_test.py +index 97f4cbbe..1d42dc21 100644 +--- a/tests/storage_tests/formats_test/fs_test.py ++++ b/tests/storage_tests/formats_test/fs_test.py +@@ -6,9 +6,10 @@ import parted + + import blivet.formats.fs as fs + from blivet.size import Size, ROUND_DOWN +-from blivet.errors import DeviceFormatError ++from blivet.errors import DeviceFormatError, FSError + from blivet.formats import get_format + from blivet.devices import PartitionDevice, DiskDevice ++from blivet.flags import flags + + from .loopbackedtestcase import LoopBackedTestCase + +@@ -26,6 +27,46 @@ class Ext3FSTestCase(Ext2FSTestCase): + class Ext4FSTestCase(Ext3FSTestCase): + _fs_class = fs.Ext4FS + ++ def test_online_resize(self): ++ an_fs = self._fs_class() ++ if not an_fs.formattable: ++ self.skipTest("can not create filesystem %s" % an_fs.name) ++ an_fs.device = self.loop_devices[0] ++ self.assertIsNone(an_fs.create()) ++ an_fs.update_size_info() ++ ++ if not self.can_resize(an_fs): ++ self.skipTest("filesystem is not resizable") ++ ++ # shrink offline first (ext doesn't support online shrinking) ++ TARGET_SIZE = Size("64 MiB") ++ an_fs.target_size = TARGET_SIZE ++ self.assertEqual(an_fs.target_size, TARGET_SIZE) ++ self.assertNotEqual(an_fs._size, TARGET_SIZE) ++ self.assertIsNone(an_fs.do_resize()) ++ ++ with tempfile.TemporaryDirectory() as mountpoint: ++ an_fs.mount(mountpoint=mountpoint) ++ ++ # grow back when mounted ++ TARGET_SIZE = Size("100 MiB") ++ an_fs.target_size = TARGET_SIZE ++ self.assertEqual(an_fs.target_size, TARGET_SIZE) ++ self.assertNotEqual(an_fs._size, TARGET_SIZE) ++ ++ # should fail, online resize disabled by default ++ with self.assertRaisesRegex(FSError, "Resizing of mounted filesystems is disabled"): ++ an_fs.do_resize() ++ ++ # enable online resize ++ flags.allow_online_fs_resize = True ++ an_fs.do_resize() ++ flags.allow_online_fs_resize = False ++ self._test_sizes(an_fs) ++ self.assertEqual(an_fs.system_mountpoint, mountpoint) ++ ++ an_fs.unmount() ++ + + class FATFSTestCase(fstesting.FSAsRoot): + _fs_class = fs.FATFS +-- +2.40.1 + diff --git a/python-blivet.spec b/python-blivet.spec index ae30496..a6acc65 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -23,7 +23,7 @@ Version: 3.6.0 #%%global prerelease .b2 # prerelease, if defined, should be something like .a1, .b1, .b2.dev1, or .c2 -Release: 7%{?prerelease}%{?dist} +Release: 8%{?prerelease}%{?dist} Epoch: 1 License: LGPLv2+ %global realname blivet @@ -44,6 +44,7 @@ Patch10: 0011-Default-to-encryption-sector-size-512-for-LUKS-devic.patch Patch11: 0012-Add-support-for-specifying-stripe-size-for-RAID-LVs.patch Patch12: 0013-Fix-setting-kickstart-data.patch Patch13: 0014-Do-not-set-memory-limit-for-LUKS2-when-running-in-FI.patch +Patch14: 0015-Add-support-for-filesystem-online-resize.patch # Versions of required components (done so we make sure the buildrequires # match the requires versions of things). @@ -207,6 +208,10 @@ configuration. %endif %changelog +* Wed May 24 2023 Vojtech Trefny - 3.6.0-8 +- Add support for filesystem online resize + Resolves: RHEL-326 + * Thu May 18 2023 Vojtech Trefny - 3.6.0-7 - Fix setting kickstart data Resolves: rhbz#2174296