aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm')
-rw-r--r--lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm311
1 files changed, 85 insertions, 226 deletions
diff --git a/lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm b/lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm
index fa14d995..a7acdd6d 100644
--- a/lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm
+++ b/lib/ManaTools/Shared/disk_backend/Plugin/Btrfs.pm
@@ -82,48 +82,71 @@ has 'filesystems' => (
default => sub { return {};}
);
-sub get_fsdev {
+sub create_subvolume {
my $self = shift;
- my $io = shift;
- my $rio = ref($io);
-
- # if it's a reference, it'll be an object, so return the mm property
- return $io->prop('mm') if defined($rio) && $rio;
-
- my @stat = stat($io);
- # if it's not a block device, it's no use
- return undef if (($stat[2] >> 12) != 6);
-
- # find the device
- my $dev = $stat[6];
- my $minor = $dev % 256;
- my $major = int (($dev - $minor) / 256);
- return $major .':'. $minor;
-}
-
-sub get_subvolumes {
- my $self = shift;
- my $io = shift;
- my $path = shift;
+ my $part = shift;
+ my $partstate = shift;
+ my $fields = shift;
+ my $quotas = shift;
+ my $subvolumes = shift;
+
+ # look or create part for btrfsvol
+ my $p = $part->trychild($partstate, sub {
+ my $self = shift;
+ my $parameters = shift;
+ return ($self->uuid() eq $parameters->{uuid});
+ }, 'BtrfsVol', {plugin => $self, fs => $part, mountsourcepath => $fields->{path} =~ s'<FS_TREE>''r, uuid => $fields->{uuid}, loaded => undef, saved => undef});
+
+ # set properties
+ $p->prop('label', $fields->{path} =~ s'<FS_TREE>/?''r);
+ $p->prop('uuid', $fields->{uuid});
+ $p->prop('parent_uuid', $fields->{parent_uuid});
+ $p->prop('subvolid', $fields->{ID});
+ $p->prop('gen', $fields->{gen});
+ $p->prop('cgen', $fields->{cgen});
+ $p->prop('parent', $fields->{parent});
+ $p->prop('top_level', $fields->{top_level});
+
+ # set quota information
+ if (defined($quotas->{'0/'. $fields->{ID}})) {
+ my $item = $quotas->{'0/'. $fields->{ID}};
+ $p->prop('referred', $item->{rfer});
+ $p->prop('exclusive', $item->{excl});
+ $p->prop('quota_referred', $item->{max_rfer});
+ $p->prop('quota_exclusive', $item->{max_excl});
+ }
- # get the dev numbering
- my $mm = $self->get_fsdev($io);
+ # trace parenting and fill in subvolumes in all the BtrfsVol Parts
+ # create missing parents too!
- # no device, get out now
- return undef if !defined($mm);
+ $self->D("$self: trigger changepart for BTRFS Volume $p: ". $p->mountsourcepath());
+ $p->changedpart($partstate);
- my $fs = $self->filesystems();
- # no filesystem, get out now
- return undef if !defined($fs->{$mm});
+ # if it has a mount point, get readonly state
+ # find Mount child (for subvolumes, might need to check the parent and base the path from there)
+ my $path = $p->find_path($partstate);
+ if (defined($path)) {
+ # if it's mounted, we can get readonly status with properties
+ my %fields = $self->tool_fields('btrfs', '=', 'property', 'get', "'$path'");
+ $p->prop('readonly', $fields{ro} eq 'true');
+ }
- # this is the filesystem part
- my $btrfs = $fs->{$mm};
+ # set up children subvolumes
+ for my $id (keys %{$fields->{subvolumes}}) {
+ if (defined($subvolumes->{$id})) {
+ # TODO: add childvol tag for this one
+ $p->add_taglink($subvolumes->{$id}, 'childsubvol');
+ }
+ }
- my $vols = $btrfs->subvolumes();
+ if (defined($subvolumes->{$p->prop('parent')})) {
+ # add a parent link
+ $p->add_taglink($subvolumes->{$p->prop('parent')}, 'parentsubvol');
+ }
- $vols = $btrfs->refresh($path) if scalar(@{$vols}) == 0;
+ $subvolumes->{$p->prop('subvolid')} = $p;
- return $vols;
+ return $p;
}
#=============================================================
@@ -153,23 +176,6 @@ override ('probe', sub {
$part->prop_from_file('used', "$fs/allocation/data/disk_used");
$part->prop_from_file('total', "$fs/allocation/data/disk_total");
$part->prop_from_file('flags', "$fs/allocation/data/flags");
- # create an io for out
- my $io = $self->parent->mkio('Btrfs', {id => $fs =~ s'^.+/''r});
- $io->prop('uuid', $fs =~ s'^.+/''r);
- $part->out_add($io);
-
- # TODO: find the in devices (create if needed?)
- for my $df (glob("$fs/devices/*")) {
- open F, '<'. $df .'/dev';
- my $value = <F>;
- close F;
- chomp($value);
- my @ios = $self->parent->findioprop('dev', $value);
- if (scalar(@ios) > 0) {
- $part->in_add($ios[0]);
- $fss->{$ios[0]->prop('dev')} = $part;
- }
- }
# TODO: find base mount point in order to find volumes
# TODO: quotas ...? pathbased?
@@ -179,64 +185,6 @@ override ('probe', sub {
#=============================================================
-=head2 fsprobe
-
-=head3 INPUT
-
- $io: ManaTools::Shared::disk_backend::IO | Str
- $mount: ManaTools::Shared::disk_backend::Part::Mount
-
-=head3 OUTPUT
-
- ManaTools::Shared::disk_backend::IO or undef
-
-=head3 DESCRIPTION
-
- this method probes the IO to see if it fits for this
- filesystem, if it does, create a new Part with this IO as in.
- also create an IO (linked as the out) and return that one.
- The resulting one can then be used as an in to eg: a Mount Part.
-
-=cut
-
-#=============================================================
-sub fsprobe {
- my $self = shift;
- my $io = shift;
- my $mount = shift;
- my $vols = $self->get_subvolumes($io, $mount->path());
- # return undef if there are not subvolumes
- return undef if !defined($vols);
-
- for my $vol (@{$vols}) {
- # return when we find the one with the correct srcpath
- return $vol if ($vol->prop('srcpath') eq $mount->prop('srcdevpath'));
- }
- return undef;
-}
-
-package ManaTools::Shared::disk_backend::IO::Btrfs;
-
-use Moose;
-
-extends 'ManaTools::Shared::disk_backend::IO';
-
-has '+type' => (
- default => 'Btrfs'
-);
-
-package ManaTools::Shared::disk_backend::IO::BtrfsVol;
-
-use Moose;
-
-extends 'ManaTools::Shared::disk_backend::IO';
-
-with 'ManaTools::Shared::disk_backend::IOFS';
-
-has '+type' => (
- default => 'BtrfsVol'
-);
-
package ManaTools::Shared::disk_backend::Part::Btrfs;
@@ -268,93 +216,6 @@ has 'subvolumes' => (
default => sub { return [];},
);
-class_has '+in_restriction' => (
- default => sub {
- return sub {
- my $self = shift;
- my $io = shift;
- my $del = shift;
- if (defined $del && !$del) {
- return ($self->in_length() > 0);
- }
- # multiple device allowed
- return $io->does('ManaTools::Shared::disk_backend::BlockDevice');
- };
- }
-);
-
-class_has '+out_restriction' => (
- default => sub {
- return sub {
- my $self = shift;
- my $io = shift;
- my $del = shift;
- if (!defined $del) {
- $del = 0;
- }
- if ($del != 0) {
- return ($self->in_length() > 0);
- }
- return ($self->in_length() == 0 && ref($io) eq 'ManaTools::Shared::disk_backend::IO::Btrfs');
- };
- }
-);
-
-sub refresh {
- my $self = shift;
- my $path = shift;
- my $subvols = $self->subvolumes();
-
- # first, clean up all Volume stuff
- my @parts = $self->db->findpart('BtrfsVol');
- for my $part (@parts) {
- $part->unhook();
- }
- # loop all BtrfsVol IO and remove safely
- for my $vol (@{$subvols}) {
- # this should also unhook from any Part
- $vol->unhook();
- }
- # clear subvols from list
- @{$subvols} = ();
-
- # find the IO::Btrfs
- my @outs = $self->get_outs();
- if (scalar(@outs) == 0) {
- # make an IO::Btrfs for this one
- @outs = ($self->db->mkio('Btrfs', {id => $self->uuid()}));
- }
-
- return $subvols if !defined($path) || !$path;
-
- # btrfs subvolume list / -agcpuq
- # ID 264 gen 1090157 cgen 255 parent 5 top level 5 parent_uuid - uuid ab6d48f8-6d65-6b43-b792-dd31d93018be path <FS_TREE>/backup-@
- my @lines = $self->tool_lines('btrfs', 'subvolume', 'list', "'$path'", '-agcpuq');
- for my $line (@lines) {
- # top level is 2 strings, so combine them, so that the fields can be nicely splitted
- my %fields = split(/[ \t\r\n]+/, $line =~ s'top level'top_level'r);
- # create the volume part
- my $part = $self->db->mkpart('BtrfsVol', {fs => $self, uuid => $fields{uuid}, plugin => $self->plugin()});
- # add the IO::Btrfs filesystem
- $part->in_add($outs[0]);
- # create a IO::BtrfsVol
- my $vol = $self->db->mkio('BtrfsVol', {id => $fields{ID}});
- # TODO: trace parenting and fill in subvolumes in all the BtrfsVol Parts
- # set properties
- $vol->prop('srcpath', $fields{path} =~ s'<FS_TREE>''r);
- $vol->prop('uuid', $fields{uuid});
- $vol->prop('parent_uuid', $fields{parent_uuid});
- $vol->prop('gen', $fields{gen});
- $vol->prop('cgen', $fields{cgen});
- $vol->prop('parent', $fields{parent});
- $vol->prop('top_level', $fields{top_level});
- $part->out_add($vol);
- push @{$subvols}, $vol;
- }
- return $subvols;
-}
-
-
package ManaTools::Shared::disk_backend::Part::BtrfsVol;
use Moose;
@@ -391,39 +252,37 @@ has 'subvolumes' => (
default => sub { return [];},
);
-class_has '+in_restriction' => (
+class_has '+restrictions' => (
default => sub {
- return sub {
- my $self = shift;
- my $io = shift;
- my $del = shift;
- if (!defined $del) {
- $del = 0;
- }
- if ($del != 0) {
- return ($self->in_length() > 0);
- }
- return ($self->in_length() == 0 && ref($io) eq 'ManaTools::Shared::disk_backend::IO::Btrfs');
- };
+ return {
+ sibling => sub {
+ my $self = shift;
+ my $part = shift;
+ return $part->isa('ManaTools::Shared::disk_backend::Part::BtrfsVol');;
+ },
+ parentsubvol => sub {
+ my $self = shift;
+ my $part = shift;
+ return $part->isa('ManaTools::Shared::disk_backend::Part::BtrfsVol');
+ },
+ childsubvol => sub {
+ my $self = shift;
+ my $part = shift;
+ return $part->isa('ManaTools::Shared::disk_backend::Part::BtrfsVol');
+ },
+ parent => sub {
+ my $self = shift;
+ my $part = shift;
+ return $part->isa('ManaTools::Shared::disk_backend::Part::Btrfs');
+ },
+ child => sub {
+ my $self = shift;
+ my $part = shift;
+ return $part->isa('ManaTools::Shared::disk_backend::Part::Mount');
+ },
+ }
}
);
-class_has '+out_restriction' => (
- default => sub {
- return sub {
- my $self = shift;
- my $io = shift;
- my $del = shift;
- if (!defined $del) {
- $del = 0;
- }
- if ($del != 0) {
- return ($self->in_length() > 0);
- }
- # multiple device allowed
- return (ref($io) eq 'ManaTools::Shared::disk_backend::IO::BtrfsVol');
- };
- }
-);
1;