Fix to clarify Btrfs qgroup limit retry behavior

https://github.com/webmin/webmin/pull/2807#discussion_r3708456970
This commit is contained in:
Ilia Ross
2026-08-04 02:04:59 +02:00
parent 65e171a92f
commit b433cdd810
3 changed files with 13 additions and 12 deletions

View File

@@ -1482,9 +1482,9 @@ return defined($_[0]) && $_[0] =~ /^\d+\/\d+$/ ? 1 : 0;
Sets the referenced or exclusive byte limit for a Btrfs qgroup. If qgroup is
undef, path must be a subvolume and its level-0 qgroup is changed. If bytes
is undef, the limit is removed. If an exceeded limit blocks the update, quota
enforcement is temporarily overridden for one retry. Returns undef on success
or an error message on failure.
is undef, the limit is removed. If quota enforcement on path or one of its
parent qgroups blocks the transaction, it is temporarily overridden for one
retry. Returns undef on success or an error message on failure.
=cut
sub set_btrfs_qgroup_limit
@@ -1502,9 +1502,10 @@ push(@args, $qgroup) if (defined($qgroup));
push(@args, $path);
my ($out, $err) = &run_btrfs_command(1, @args);
# An exceeded qgroup can block the metadata write needed to raise or remove its
# own limit. Retry once with the kernel's administrative override, preserving
# the previous state and restoring enforcement immediately after the command.
# A limit on the command path or one of its parent qgroups can block the
# transaction needed to update any qgroup limit. Retry once with the kernel's
# administrative override, preserving the previous state and restoring
# enforcement immediately after the command.
if ($err && $err =~ /disk quota exceeded/i) {
my $uuid = &btrfs_filesystem_uuid($path);
my $sysfs = $btrfs_sysfs_root || "/sys/fs/btrfs";

View File

@@ -68,8 +68,8 @@ $same_referenced = &same_limit(
$same_exclusive = &same_limit(
$max_exclusive, $qgroup->{'max_exclusive'});
# Apply only changed limits, keeping an unrelated existing over-limit setting
# from causing Btrfs to reject an otherwise valid update.
# Apply only changed limits so each independent setting is left untouched when
# the submitted value already matches it.
if (!$same_referenced) {
$err = &set_btrfs_qgroup_limit(
$dir, $in{'qgroup'}, $max_referenced, 0);

View File

@@ -287,8 +287,8 @@ is(main::set_btrfs_qgroup_limit("/srv/btrfs", "1/100", "1M"),
is(main::assign_btrfs_qgroup("/srv/btrfs", "bad", "1/100"),
"Invalid child Btrfs qgroup ID", "invalid child assignment is rejected");
# An existing over-limit qgroup must not prevent an administrator from raising
# or removing its limit. The kernel override is restored after the retry.
# A qgroup-limit transaction rejected by quota enforcement is retried once,
# and the kernel override is restored immediately afterward.
my $override_root = tempdir(CLEANUP => 1);
my $override_uuid = "abcdef01-2345-6789-abcd-ef0123456789";
make_path("$override_root/$override_uuid");
@@ -305,12 +305,12 @@ local $main::btrfs_sysfs_root = $override_root;
{ 'out' => "", 'status' => 0 },
);
is(main::set_btrfs_qgroup_limit("/srv/btrfs", "1/100", 2097152),
undef, "over-limit qgroup updates retry with the administrative override");
undef, "an EDQUOT limit update retries with the administrative override");
open($override_fh, '<', "$override_root/$override_uuid/quota_override")
or die $!;
is(<$override_fh>, "0\n", "quota enforcement is restored after the retry");
close($override_fh);
is(scalar(@commands), 3, "one status lookup and one limit retry are run");
is(scalar(@commands), 3, "one UUID lookup and one limit retry are run");
@responses = ({ 'out' => "ERROR: qgroup exists\n", 'status' => 1 });
is(main::create_btrfs_qgroup("/srv/btrfs", "1/100"),