Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master format free space #217

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion blivet/blivet.py
Expand Up @@ -1352,7 +1352,7 @@ def fileSystemFreeSpace(self):
if device.format.exists:
free += device.format.free
else:
free += device.size
free += device.format.freeSpaceEstimate(device.size)

return free

Expand Down
26 changes: 25 additions & 1 deletion blivet/formats/fs.py
Expand Up @@ -72,6 +72,11 @@ class FS(DeviceFormat):
_sizeinfoClass = fssize.UnimplementedFSSize
_syncClass = fssync.UnimplementedFSSync
_writelabelClass = fswritelabel.UnimplementedFSWriteLabel
# This constant is aquired by testing some filesystems
# and it's giving us percentage of space left after the format.
# This number is more guess then precise number because this
# value is already unpredictable and can change in the future...
_MetadataSizeFactor = 1.0

def __init__(self, **kwargs):
"""
Expand Down Expand Up @@ -168,6 +173,18 @@ def dict(self):
"mountable": self.mountable})
return d

@classmethod
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a class method? I'd just make it a @Property and use self.size instead of passing it in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna reply to this since it was my idea to make it a class method. The reason is that in many cases we want to know how much space a file system would provide even if it doesn't exist (as an object). Think about things like a list of file systems shown to user together with estimations of how much space they would get. And also in anaconda, we need this estimations early e.g. in disk selection where there are no devices and no file systems, but just a number giving the disk free space size.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense.

def freeSpaceEstimate(cls, device_size):
""" Get estimated free space when format will be done on device
with size ``device_size``.
This is more guess then precise number.

:param device_size: original device size
:type device_size: ``Size`` object
:return: estimated free size after format
"""
return device_size * cls._MetadataSizeFactor

def labeling(self):
"""Returns True if this filesystem uses labels, otherwise False.

Expand Down Expand Up @@ -337,7 +354,6 @@ def free(self):
"""
return max(Size(0), self.currentSize - self.minSize)


def _preCreate(self, **kwargs):
super(FS, self)._preCreate(**kwargs)
if not self._mkfs.available:
Expand Down Expand Up @@ -807,6 +823,7 @@ class Ext2FS(FS):
_sizeinfoClass = fssize.Ext2FSSize
_writelabelClass = fswritelabel.Ext2FSWriteLabel
partedSystem = fileSystemType["ext2"]
_MetadataSizeFactor = 0.93 # ext2 metadata may take 7% of space

register_device_format(Ext2FS)

Expand All @@ -823,6 +840,7 @@ class Ext3FS(Ext2FS):
# with regard to this maximum filesystem size, but if they're doing such
# things they should know the implications of their chosen block size.
_maxSize = Size("16 TiB")
_MetadataSizeFactor = 0.90 # ext3 metadata may take 10% of space

register_device_format(Ext3FS)

Expand All @@ -834,6 +852,7 @@ class Ext4FS(Ext3FS):
_mkfsClass = fsmkfs.Ext4FSMkfs
partedSystem = fileSystemType["ext4"]
_maxSize = Size("1 EiB")
_MetadataSizeFactor = 0.85 # ext4 metadata may take 15% of space

register_device_format(Ext4FS)

Expand All @@ -852,6 +871,7 @@ class FATFS(FS):
_mountClass = fsmount.FATFSMount
_readlabelClass = fsreadlabel.DosFSReadLabel
_writelabelClass = fswritelabel.DosFSWriteLabel
_MetadataSizeFactor = 0.99 # fat metadata may take 1% of space
# FIXME this should be fat32 in some cases
partedSystem = fileSystemType["fat16"]

Expand Down Expand Up @@ -883,6 +903,7 @@ class BTRFS(FS):
_minSize = Size("256 MiB")
_maxSize = Size("16 EiB")
_mkfsClass = fsmkfs.BTRFSMkfs
_MetadataSizeFactor = 0.80 # btrf metadata may take 20% of space
# FIXME parted needs to be taught about btrfs so that we can set the
# partition table type correctly for btrfs partitions
# partedSystem = fileSystemType["btrfs"]
Expand Down Expand Up @@ -946,6 +967,7 @@ class JFS(FS):
_mkfsClass = fsmkfs.JFSMkfs
_sizeinfoClass = fssize.JFSSize
_writelabelClass = fswritelabel.JFSWriteLabel
_MetadataSizeFactor = 0.99 # jfs metadata may take 1% of space
partedSystem = fileSystemType["jfs"]

@property
Expand All @@ -971,6 +993,7 @@ class ReiserFS(FS):
_mkfsClass = fsmkfs.ReiserFSMkfs
_sizeinfoClass = fssize.ReiserFSSize
_writelabelClass = fswritelabel.ReiserFSWriteLabel
_MetadataSizeFactor = 0.98 # reiserfs metadata may take 2% of space
partedSystem = fileSystemType["reiserfs"]

@property
Expand All @@ -997,6 +1020,7 @@ class XFS(FS):
_sizeinfoClass = fssize.XFSSize
_syncClass = fssync.XFSSync
_writelabelClass = fswritelabel.XFSWriteLabel
_MetadataSizeFactor = 0.97 # xfs metadata may take 3% of space
partedSystem = fileSystemType["xfs"]


Expand Down
9 changes: 9 additions & 0 deletions blivet/size.py
Expand Up @@ -303,16 +303,25 @@ def __reduce__(self):
return (self.__class__, (self.convertTo(),))

def __add__(self, other, context=None):
# because float is not automatically converted to Decimal type
if isinstance(other, float):
other = Decimal(other)
return Size(Decimal.__add__(self, other))

# needed to make sum() work with Size arguments
def __radd__(self, other, context=None):
if isinstance(other, float):
other = Decimal(other)
return Size(Decimal.__radd__(self, other))

def __sub__(self, other, context=None):
if isinstance(other, float):
other = Decimal(other)
return Size(Decimal.__sub__(self, other))

def __mul__(self, other, context=None):
if isinstance(other, float):
other = Decimal(other)
return Size(Decimal.__mul__(self, other))
__rmul__ = __mul__

Expand Down