Skip to content

Commit

Permalink
Initial wrapper for BtrfsQgroup and associated methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ancorgs committed Nov 12, 2020
1 parent 20fe54f commit e2be277
Show file tree
Hide file tree
Showing 9 changed files with 1,233 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/lib/y2storage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
require "y2storage/space_info"
require "y2storage/mount_point"
require "y2storage/btrfs_raid_level"
require "y2storage/btrfs_qgroup"
require "y2storage/btrfs_subvolume"
require "y2storage/storage_features_list"

require "y2storage/exceptions"
Expand Down
115 changes: 115 additions & 0 deletions src/lib/y2storage/btrfs_qgroup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright (c) [2020] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "y2storage/storage_class_wrapper"
require "y2storage/disk_size"

module Y2Storage
# A qgroup of a Btrfs filesystem
#
# This is a wrapper for Storage::BtrfsQgroup.
#
# In Btrfs, the qgroups hold the quota information for a given set of subvolumes.
# Although they can be organized in a tree hierarchy, we are only considering the
# first level (level 0, actually), so they are associated to a single subvolume.
#
# @see man btrfs-qgroup
class BtrfsQgroup < Device
wrap_class Storage::BtrfsQgroup

storage_forward :storage_id, to: :id
private :storage_id

# Id of the group including the level and the qgroup id
#
# For qgroups of level 0, the second term (the qgroup id) matches the id of
# the corresponding subvolume.
#
# @return [Array<Integer>] includes two terms, level and id
def id
[storage_id.first, storage_id.second]
end

# @!method referenced
# Size of the referenced space of the qgroup
#
# @return [DiskSize] zero if the size is not known (the qgroup was created after probing)
storage_forward :referenced, as: "DiskSize"

# @!method exclusive
# Size of the exclusive space of the qgroup
#
# @return [DiskSize] zero if the size is not known (the qgroup was created after probing)
storage_forward :exclusive, as: "DiskSize"

storage_forward :storage_referenced_limit, to: :referenced_limit, as: "DiskSize"
private :storage_referenced_limit

# Limit of the referenced space for the qgroup
#
# @return [DiskSize] unlimited if there is no quota
def referenced_limit
return DiskSize.unlimited unless to_storage_value.has_referenced_limit

storage_referenced_limit
end

# Setter for {#referenced_limit}
#
# @param limit [DiskSize] setting it to DiskSize.Unlimited removes the quota
def referenced_limit=(limit)
if limit.unlimited?
to_storage_value.clear_referenced_limit
else
to_storage_value.referenced_limit = limit.to_i
end
end

storage_forward :storage_exclusive_limit, to: :exclusive_limit, as: "DiskSize"
private :storage_exclusive_limit

# @!method exclusive_limit
# Limit of the exclusive space for the qgroup
#
# @return [DiskSize] unlimited if there is no quota
def exclusive_limit
return DiskSize.unlimited unless to_storage_value.has_exclusive_limit

storage_exclusive_limit
end

# Setter for {#exclusive_limit}
#
# @param limit [DiskSize] setting it to DiskSize.Unlimited removes the quota
def exclusive_limit=(limit)
if limit.unlimited?
to_storage_value.clear_exclusive_limit
else
to_storage_value.exclusive_limit = limit.to_i
end
end

protected

# @see Device#is?
def types_for_is
super << :btrfs_qgroup
end
end
end
90 changes: 90 additions & 0 deletions src/lib/y2storage/btrfs_subvolume.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# find current contact information at www.suse.com.

require "y2storage/storage_class_wrapper"
require "y2storage/btrfs_qgroup"
require "y2storage/mountable"

module Y2Storage
Expand Down Expand Up @@ -67,6 +68,22 @@ class BtrfsSubvolume < Mountable
# @return [BtrfsSubvolume]
storage_forward :create_btrfs_subvolume, as: "BtrfsSubvolume"

# @!method btrfs_qgroup
# Level 0 qgroup associated to this subvolume, if any
#
# @return [BtrfsQgroup, nil]
storage_forward :btrfs_qgroup, as: "BtrfsQgroup", check_with: :has_btrfs_qgroup

# @!method create_btrfs_qgroup
# Creates the corresponding level 0 qgroup for the subvolume
#
# Quota support must be enabled for the filesystem (see {Filesystems::Btrfs#quota?}).
# If that's the case, usually the qgroup already exists unless it was removed by
# the user.
#
# @raise [Storage::Exception] if quota support is not enabled
storage_forward :create_btrfs_qgroup, as: "BtrfsQgroup"

# Sets this subvolume as the default one
def set_default_btrfs_subvolume
# The original libstorage method is wrongly renamed to
Expand Down Expand Up @@ -109,6 +126,67 @@ def can_be_auto_deleted=(value)
save_userdata(:can_be_auto_deleted, value)
end

# Size of the referenced space of the subvolume, if known
#
# The information is obtained from the qgroup of level 0 associated to the subvolume,
# which implies it can only be known if quotas are enabled for the filesystem.
# If quota support is disabled, this method returns nil.
#
# If the filesystem already existed during probing but got no quota support enabled at
# that moment, this method returns zero if quota support was enabled after probing.
#
# @return [DiskSize, nil] nil if quota support is disabled, zero if it was enabled only
# after probing, the known size in any other case
def referenced
btrfs_qgroup&.referenced
end

# Size of the exclusive space of the subvolume, if known
#
# See {#referenced} for details about the possible returned values in several situations.
#
# @return [DiskSize, nil] nil if quota support is disabled, zero if it was enabled only
# after probing, the known size in any other case
def exclusive
btrfs_qgroup&.exclusive
end

# Limit of the referenced space for the subvolume
#
# @return [DiskSize] unlimited if there is no quota
def referenced_limit
btrfs_qgroup&.referenced_limit || DiskSize.unlimited
end

# Limit of the referenced space for the subvolume
#
# @return [DiskSize] unlimited if there is no quota
def exclusive_limit
btrfs_qgroup&.exclusive_limit || DiskSize.unlimited
end

# Setter for #{referenced_limit}
#
# Works only if quotas are enabled for the filesystem (see {Filesystems::Btrfs#quota?})
#
# @param limit [DiskSize] setting it to DiskSize.Unlimited removes the quota
def referenced_limit=(limit)
return unless create_missing_qgroup

btrfs_qgroup.referenced_limit = limit
end

# Setter for #{exclusive_limit}
#
# Works only if quotas are enabled for the filesystem (see {Filesystems::Btrfs#quota?})
#
# @param limit [DiskSize] setting it to DiskSize.Unlimited removes the quota
def exclusive_limit=(limit)
return unless create_missing_qgroup

btrfs_qgroup.exclusive_limit = limit
end

# Checks whether the subvolume is shadowed by any other mount point in the system
#
# @return [Boolean] true if the subvolume is shadowed
Expand Down Expand Up @@ -169,8 +247,20 @@ def self.shadowers(devicegraph, mount_path)

protected

# @see Device#is?
def types_for_is
super << :btrfs_subvolume
end

# Returns the associated level 0 qgroup, creating one if needed and possible
#
# @return [BtrfsQgroup, nil] nil if quotas are disabled for the filesystem, a valid
# qgroup (new or pre-existing) in any other case
def create_missing_qgroup
btrfs_qgroup || create_btrfs_qgroup
# libstorage-ng throws an exception for #create_btrfs_qgroup if quotas are disabled
rescue Storage::Exception
nil
end
end
end
2 changes: 1 addition & 1 deletion src/lib/y2storage/device.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Device

wrap_class Storage::Device,
downcast_to: ["BlkDevice", "BcacheCset", "Mountable", "MountPoint", "PartitionTables::Base",
"LvmPv", "LvmVg"]
"LvmPv", "LvmVg", "BtrfsQgroup"]

storage_forward :storage_eql, to: :==
protected :storage_eql
Expand Down
31 changes: 30 additions & 1 deletion src/lib/y2storage/filesystems/btrfs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class Btrfs < BlkFilesystem

# @!method btrfs_subvolumes
# Collection of Btrfs subvolumes of the filesystem
# @return [Array<BtrfsSubvolumes>]
# @return [Array<BtrfsSubvolume>]
storage_forward :btrfs_subvolumes, as: "BtrfsSubvolume"

# @!method find_btrfs_subvolume_by_path(path)
Expand Down Expand Up @@ -127,6 +127,35 @@ class Btrfs < BlkFilesystem
# @raise [Storage::Exception] if the device cannot be removed
storage_forward :remove_device

# @!method btrfs_qgroups
# Collection of Btrfs qgroups of the filesystem
# @return [Array<BtrfsQgroup>]
storage_forward :btrfs_qgroups, as: "BtrfsQgroup"

# @!method has_quota
# Whether quota support is enabled for this btrfs filesystem
#
# @return [Boolean]
storage_forward :has_quota
alias_method :quota?, :has_quota

# @!method quota=(value)
# Enable or disable quota for the btrfs
#
# When disabling quota, all qgroups and qgroup relations of the btrfs are removed.
#
# When enabling quota, qgroups and qgroup relations are created for the
# btrfs. This is done so that no qgroup related actions will be done during
# commit (unless further changes are done). If quota was disabled during probing,
# the qgroups are created like btrfs would do. If quota was enabled during
# probing, the qgroups from probing are restored.
#
# @raise [Storage::Exception] according to libstorage-ng documentation this method
# can raise an exception, although the circumstances are not clear.
#
# @param value [Boolean]
storage_forward :quota=

# Only Btrfs should support subvolumes
def supports_btrfs_subvolumes?
true
Expand Down

0 comments on commit e2be277

Please sign in to comment.