Skip to content

Commit

Permalink
Use libblockdev to get filesystem min size
Browse files Browse the repository at this point in the history
Latest libblockdev added support for getting filesystem min size
so we can use it now.
  • Loading branch information
vojtechtrefny committed Nov 6, 2023
1 parent dbc3be9 commit 3f2ce4e
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 114 deletions.
9 changes: 5 additions & 4 deletions blivet/tasks/availability.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def availability_errors(self, resource):
return ["libblockdev fs plugin not loaded"]
else:
try:
if self.operation in (FSOperation.UUID, FSOperation.LABEL, FSOperation.INFO):
if self.operation in (FSOperation.UUID, FSOperation.LABEL, FSOperation.INFO, FSOperation.MIN_SIZE):
avail, utility = self.check_fn(self.fstype)
elif self.operation == FSOperation.RESIZE:
avail, _mode, utility = self.check_fn(self.fstype)
Expand Down Expand Up @@ -530,6 +530,7 @@ class FSOperation():
RESIZE = 2
INFO = 3
MKFS = 4
MIN_SIZE = 5


BLOCKDEV_EXT_UUID = blockdev_fs_plugin_operation(BlockDevFSMethod(FSOperation.UUID, blockdev.fs.can_set_uuid, "ext2"))
Expand Down Expand Up @@ -557,6 +558,9 @@ class FSOperation():
BLOCKDEV_VFAT_MKFS = blockdev_fs_plugin_operation(BlockDevFSMethod(FSOperation.MKFS, blockdev.fs.can_mkfs, "vfat"))
BLOCKDEV_F2FS_MKFS = blockdev_fs_plugin_operation(BlockDevFSMethod(FSOperation.MKFS, blockdev.fs.can_mkfs, "f2fs"))

BLOCKDEV_EXT_MIN_SIZE = blockdev_fs_plugin_operation(BlockDevFSMethod(FSOperation.MIN_SIZE, blockdev.fs.can_get_min_size, "ext2"))
BLOCKDEV_NTFS_MIN_SIZE = blockdev_fs_plugin_operation(BlockDevFSMethod(FSOperation.MIN_SIZE, blockdev.fs.can_get_min_size, "ntfs"))

# libblockdev plugins
# we can't just check if the plugin is loaded, we also need to make sure
# that all technologies required by us our supported (some may be missing
Expand All @@ -582,10 +586,7 @@ class FSOperation():
FSCK_HFSPLUS_APP = application("fsck.hfsplus")
XFSREPAIR_APP = application("xfs_repair")
FSCK_F2FS_APP = application("fsck.f2fs")

# resize (for min size)
NTFSRESIZE_APP = application("ntfsresize")
RESIZE2FS_APP = application("resize2fs")

# mkfs
MKFS_GFS2_APP = application("mkfs.gfs2")
Expand Down
134 changes: 24 additions & 110 deletions blivet/tasks/fsminsize.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@

from six import add_metaclass

import gi
gi.require_version("BlockDev", "3.0")
from gi.repository import BlockDev

from ..errors import FSError
from .. import util
from ..size import Size
from ..size import Size, MiB, ROUND_UP

from . import availability
from . import fstask
Expand All @@ -39,132 +42,43 @@ class FSMinSize(task.BasicApplication, fstask.FSTask):

description = "minimum filesystem size"

options = abc.abstractproperty(doc="Options for use with app.")

def _resize_command(self):
return [str(self.ext)] + self.options + [self.fs.device]

def _get_resize_info(self):
""" Get info from fsresize program.
:rtype: str
:returns: output returned by fsresize program
"""
error_msg = None
try:
(rc, out) = util.run_program_and_capture_output(self._resize_command())
if rc:
error_msg = "failed to gather info from resize program: %d" % rc
except OSError as e:
error_msg = "failed to gather info from resize program: %s" % e

if error_msg:
raise FSError(error_msg)
return out

@abc.abstractmethod
def _get_size(self):
raise NotImplementedError

def do_task(self): # pylint: disable=arguments-differ
""" Returns the minimum size for this filesystem object.
:rtype: :class:`~.size.Size`
:returns: the minimum size
:raises FSError: if filesystem can not be obtained
"""
raise NotImplementedError()


class Ext2FSMinSize(FSMinSize):

ext = availability.RESIZE2FS_APP
options = ["-P"]

@property
def depends_on(self):
return [self.fs._info]

def _extract_block_size(self):
""" Extract block size from filesystem info.
:returns: block size of fileystem or None
:rtype: :class:`~.size.Size` or NoneType
"""
if self.fs._current_info is None:
return None

return Size(self.fs._current_info.block_size)

def _extract_num_blocks(self, info):
""" Extract the number of blocks from the resizefs info.
:returns: the number of blocks or None
:rtype: int or NoneType
"""
num_blocks = None
for line in info.splitlines():
(text, _sep, value) = line.partition(":")
if "minimum size of the filesystem" not in text:
continue

try:
num_blocks = int(value.strip())
break
except ValueError:
break

return num_blocks

def do_task(self): # pylint: disable=arguments-differ
error_msgs = self.availability_errors
if error_msgs:
raise FSError("\n".join(error_msgs))

block_size = self._extract_block_size()
if block_size is None:
raise FSError("failed to get block size for %s filesystem on %s" % (self.fs.mount_type, self.fs.device))

resize_info = self._get_resize_info()
num_blocks = self._extract_num_blocks(resize_info)
if num_blocks is None:
raise FSError("failed to get minimum block number for %s filesystem on %s" % (self.fs.mount_type, self.fs.device))

return block_size * num_blocks


class NTFSMinSize(FSMinSize):

ext = availability.NTFSRESIZE_APP
options = ["-m"]
try:
return self._get_size()
except BlockDev.FSError as e:
raise FSError(str(e))

def _extract_min_size(self, info):
""" Extract the minimum size from the resizefs info.

:param str info: info obtained from resizefs prog
:rtype: :class:`~.size.Size` or NoneType
:returns: the minimum size, or None
"""
min_size = None
for line in info.splitlines():
(text, _sep, value) = line.partition(":")
if "Minsize" not in text:
continue
class Ext2FSMinSize(FSMinSize):
ext = availability.BLOCKDEV_EXT_MIN_SIZE

try:
min_size = Size("%d MB" % int(value.strip()))
except ValueError:
break
def _get_size(self):
bd_size = BlockDev.fs.ext2_get_min_size(self.fs.device)
return Size(bd_size)

return min_size

def do_task(self): # pylint: disable=arguments-differ
error_msgs = self.availability_errors
if error_msgs:
raise FSError("\n".join(error_msgs))
class NTFSMinSize(FSMinSize):
ext = availability.BLOCKDEV_NTFS_MIN_SIZE

resize_info = self._get_resize_info()
min_size = self._extract_min_size(resize_info)
if min_size is None:
raise FSError("Unable to discover minimum size of filesystem on %s" % self.fs.device)
return min_size
def _get_size(self):
bd_size = BlockDev.fs.ntfs_get_min_size(self.fs.device)
# originally this used ntfsresize -m to print the information in MiB
# so lets just round it here up to get the same result
return Size(bd_size).round_to_nearest(MiB, ROUND_UP)


class UnimplementedFSMinSize(fstask.UnimplementedFSTask):
Expand Down

0 comments on commit 3f2ce4e

Please sign in to comment.