Signed-off-by: Wolfgang Bumiller <w.bumil...@proxmox.com>
---
Difference to the main btrfs series v2:
  * removed double-eval to catch errors when setting limits in
    alloc_image
  Note that the issue that subvols are created with size zero was an
  issue in pve-container.
  Volume resizing is fixed in patch 3

 PVE/Storage/BTRFSPlugin.pm | 93 +++++++++++++++++++++++---------------
 1 file changed, 57 insertions(+), 36 deletions(-)

diff --git a/PVE/Storage/BTRFSPlugin.pm b/PVE/Storage/BTRFSPlugin.pm
index 5360dca..179186b 100644
--- a/PVE/Storage/BTRFSPlugin.pm
+++ b/PVE/Storage/BTRFSPlugin.pm
@@ -57,6 +57,14 @@ sub properties {
            type => 'boolean',
            default => 0,
        },
+       quotas => {
+           description => "If enabled, containers will use subvolumes 
directly, using quotas"
+               . " for space accounting, instead of using ext4 formatted 
images files."
+               . " While this removes a file system layer for containers, 
there is a risk of"
+               . " performance degrading over time.",
+           type => 'boolean',
+           default => 0,
+       },
     };
 }
 
@@ -71,6 +79,7 @@ sub options {
        format => { optional => 1 },
        is_mountpoint => { optional => 1 },
        nocow => { optional => 1 },
+       quotas => { optional => 1 },
        # TODO: The new variant of mkdir with  `populate` vs `create`...
     };
 }
@@ -336,27 +345,20 @@ sub alloc_image {
        $path = "$subvol/disk.raw";
     }
 
-    if ($fmt eq 'subvol' && !!$size) {
+    if ($fmt eq 'subvol' && !!$size && !$scfg->{quotas}) {
        # NOTE: `btrfs send/recv` actually drops quota information so 
supporting subvolumes with
        # quotas doesn't play nice with send/recv.
-       die "btrfs quotas are currently not supported, use an unsized subvolume 
or a raw file\n";
+       die "btrfs quotas are currently disabled, use an unsized subvolume or a 
raw file\n";
     }
 
     $class->btrfs_cmd(['subvolume', 'create', '--', $subvol]);
 
     eval {
        if ($fmt eq 'subvol') {
-           # Nothing to do for now...
-
-           # This is how we *would* do it:
-           # # Use the subvol's default 0/$id qgroup
-           # eval {
-           #     # This call should happen at storage creation instead and 
therefore governed by a
-           #     # configuration option!
-           #     # $class->btrfs_cmd(['quota', 'enable', $subvol]);
-           #     my $id = $class->btrfs_get_subvol_id($subvol);
-           #     $class->btrfs_cmd(['qgroup', 'limit', "${size}k", "0/$id", 
$subvol]);
-           # };
+           if (!!$size) {
+               my $id = $class->btrfs_get_subvol_id($subvol);
+               $class->btrfs_cmd(['qgroup', 'limit', "${size}k", "0/$id", 
$subvol]);
+           }
        } elsif ($fmt eq 'raw') {
            sysopen my $fh, $path, O_WRONLY | O_CREAT | O_EXCL
                or die "failed to create raw file '$path' - $!\n";
@@ -434,27 +436,26 @@ sub free_image {
     return undef;
 }
 
-# Currently not used because quotas clash with send/recv.
-# my sub btrfs_subvol_quota {
-#     my ($class, $path) = @_;
-#     my $id = '0/' . $class->btrfs_get_subvol_id($path);
-#     my $search = qr/^\Q$id\E\s+(\d)+\s+\d+\s+(\d+)\s*$/;
-#     my ($used, $size);
-#     $class->btrfs_cmd(['qgroup', 'show', '--raw', '-rf', '--', $path], sub {
-#      return if defined($size);
-#      if ($_[0] =~ $search) {
-#          ($used, $size) = ($1, $2);
-#      }
-#     });
-#     if (!defined($size)) {
-#      # syslog should include more information:
-#      syslog('err', "failed to get subvolume size for: $path (id $id)");
-#      # UI should only see the last path component:
-#      $path =~ s|^.*/||;
-#      die "failed to get subvolume size for $path\n";
-#     }
-#     return wantarray ? ($used, $size) : $size;
-# }
+my sub btrfs_subvol_quota {
+    my ($class, $path) = @_;
+    my $id = '0/' . $class->btrfs_get_subvol_id($path);
+    my $search = qr/^\Q$id\E\s+(\d)+\s+\d+\s+(\d+)\s*$/;
+    my ($used, $size);
+    $class->btrfs_cmd(['qgroup', 'show', '--raw', '-rf', '--', $path], sub {
+       return if defined($size);
+       if ($_[0] =~ $search) {
+           ($used, $size) = ($1, $2);
+       }
+    });
+    if (!defined($size)) {
+       # syslog should include more information:
+       syslog('err', "failed to get subvolume size for: $path (id $id)");
+       # UI should only see the last path component:
+       $path =~ s|^.*/||;
+       die "failed to get subvolume size for $path\n";
+    }
+    return wantarray ? ($used, $size) : $size;
+}
 
 sub volume_size_info {
     my ($class, $scfg, $storeid, $volname, $timeout) = @_;
@@ -466,7 +467,9 @@ sub volume_size_info {
     if ($format eq 'subvol') {
        my $ctime = (stat($path))[10];
        my ($used, $size) = (0, 0);
-       #my ($used, $size) = btrfs_subvol_quota($class, $path); # uses wantarray
+       if ($scfg->{quotas}) {
+           ($used, $size) = btrfs_subvol_quota($class, $path);
+       }
        return wantarray ? ($size, 'subvol', $used, undef, $ctime) : 1;
     }
 
@@ -478,6 +481,9 @@ sub volume_resize {
 
     my $format = ($class->parse_volname($volname))[6];
     if ($format eq 'subvol') {
+       die "subvolumes can only be resized with quotas enabled\n"
+           if !$scfg->{quotas};
+
        my $path = $class->filesystem_path($scfg, $volname);
        my $id = '0/' . $class->btrfs_get_subvol_id($path);
        $class->btrfs_cmd(['qgroup', 'limit', '--', "${size}k", "0/$id", 
$path]);
@@ -638,7 +644,9 @@ sub list_images {
            ($size, $format, $used, $parent, $ctime) = 
PVE::Storage::Plugin::file_size_info("$fn/disk.raw");
        } elsif ($ext eq 'subvol') {
            ($used, $size) = (0, 0);
-           #($used, $size) = btrfs_subvol_quota($class, $fn);
+           if ($scfg->{quotas}) {
+               ($used, $size) = btrfs_subvol_quota($class, $fn);
+           }
            $format = 'subvol';
        } else {
            ($size, $format, $used, $parent, $ctime) = 
PVE::Storage::Plugin::file_size_info($fn);
@@ -680,6 +688,9 @@ sub volume_export_formats {
     my $format = ($class->parse_volname($volname))[6];
     return @result if $format ne 'raw' && $format ne 'subvol';
 
+    # Currently we don't allow using btrfs-send/recv with quotas on subvolumes.
+    return @result if $scfg->{quotas} && $format eq 'subvol';
+
     return ('btrfs', @result);
 }
 
@@ -726,6 +737,11 @@ sub volume_export {
     die "btrfs-sending volumes of type $volume_format ('$volname') is not 
supported\n"
        if $volume_format ne 'raw' && $volume_format ne 'subvol';
 
+    if ($scfg->{quotas} && $format eq 'subvol') {
+       die "btrfs-sending volumes of type $volume_format ('$volname') with 
quotas enabled is"
+           . " currently not supported\n";
+    }
+
     my $path = $class->path($scfg, $volname, $storeid);
 
     if ($volume_format eq 'raw') {
@@ -782,6 +798,11 @@ sub volume_import {
     die "btrfs-receiving volumes of type $volume_format ('$volname') is not 
supported\n"
        if $volume_format ne 'raw' && $volume_format ne 'subvol';
 
+    if ($scfg->{quotas} && $format eq 'subvol') {
+       die "btrfs-receiving volumes of type $volume_format ('$volname') with 
quotas enabled is"
+           . " currently not supported\n";
+    }
+
     if (defined($base_snapshot)) {
        my $path = $class->path($scfg, $volname, $storeid, $base_snapshot);
        die "base snapshot '$base_snapshot' not found - no such directory 
'$path'\n"
-- 
2.30.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to