Fix LVM resizing for expanded partition-backed disks
Some checks failed
Tests / prove (push) Has been cancelled
Package and upload artifacts / build (push) Has been cancelled

ⓘ Grow eligible PV partitions into adjacent free space before retrying `pvresize`, and treat unchanged "use all free VG space" LV targets as no-ops.
This commit is contained in:
Ilia Ross
2026-07-17 20:34:36 +02:00
parent c1d526542f
commit f1841228ea
5 changed files with 62 additions and 3 deletions

View File

@@ -12,6 +12,7 @@
* Fix missing Maildir folders to be counted as empty in Mailboxes module
* Fix Postfix version comparisons to handle version strings safely
* Fix SELinux labeling for Webmin runtime data
* Fix LVM resizing to grow eligible partition-backed physical volumes into adjacent free disk space and handle unchanged logical volume sizes correctly
* Update the Authentic theme to the latest version with various improvements:
- Fix inconsistent gaps around rounded UI elements
- Fix CPU usage values exceeding 100% in the dashboard

View File

@@ -170,6 +170,7 @@ pv_resize=Resize To Match Device
pv_err=Failed to save physical volume
pv_err2=Failed to remove physical volume
pv_err3=Failed to resize physical volume
pv_enoresize=Physical volume $1 is already the size of its underlying device. If the device is a partition, expand the partition first and then resize the physical volume.
pv_delete=Remove Physical Volume
pv_rusure=Are you sure you want to remove physical volume device $1 from its volume group? This will result in any data being shifted to other physical volumes within the group.
pv_deleteok=Remove Volume

View File

@@ -151,9 +151,56 @@ return $? ? $out : undef;
# Set the size of a physical volume to match the underlying device
sub resize_physical_volume
{
local $cmd = "pvresize ".quotemeta($_[0]->{'device'});
local ($pv) = @_;
local $cmd = "pvresize ".quotemeta($pv->{'device'});
local $out = &backquote_logged("$cmd 2>&1");
return $? ? $out : undef;
return $out if ($?);
# If the PV did not change, its partition may have adjacent free space
return undef if (!defined($pv->{'pe_total'}));
local ($newpv) = grep { $_->{'device'} eq $pv->{'device'} }
&list_physical_volumes($pv->{'vg'});
return undef if (!$newpv || !defined($newpv->{'pe_total'}) ||
$newpv->{'pe_total'} != $pv->{'pe_total'});
local ($grew, $err) = &grow_physical_volume_partition($pv);
return $err if ($err);
if ($grew) {
$out = &backquote_logged("$cmd 2>&1");
return $out if ($?);
}
return undef;
}
# grow_physical_volume_partition(&pv)
# Grow a partition-backed PV into adjacent free disk space, if possible
sub grow_physical_volume_partition
{
local ($pv) = @_;
return (0, undef) if (!&has_command("growpart"));
local $pvdev = &simplify_path(&resolve_links($pv->{'device'}));
local ($disk, $part);
DISK: foreach $d (&fdisk::list_disks_partitions()) {
foreach $p (@{$d->{'parts'}}) {
local $pdev = &simplify_path(&resolve_links($p->{'device'}));
if ($pvdev eq $pdev &&
$p->{'number'} =~ /^\d+$/) {
$disk = $d;
$part = $p;
last DISK;
}
}
}
return (0, undef) if (!$disk);
# Only modify the partition when growpart confirms that it can be enlarged
local $cmd = "growpart -N ".quotemeta($disk->{'device'})." ".
quotemeta($part->{'number'});
&backquote_command("$cmd 2>&1");
return (0, undef) if ($?);
$cmd = "growpart ".quotemeta($disk->{'device'})." ".
quotemeta($part->{'number'});
local $out = &backquote_logged("$cmd 2>&1");
return $? ? (0, $out) : (1, undef);
}
# list_volume_groups()

View File

@@ -180,7 +180,10 @@ else {
$realsize = ($vg->{'pe_total'}*$vg->{'pe_size'})-($vg->{'pe_alloc'}*$vg->{'pe_size'})+$lv->{'size'};
}
if ($in{'sizeconfirm'}) {
if ($realsize == $lv->{'size'}) {
# No resize is needed
}
elsif ($in{'sizeconfirm'}) {
# Just resize the logical volume
$err = &resize_logical_volume($lv, $realsize);
&error("<pre>$err</pre>") if ($err);

View File

@@ -39,6 +39,13 @@ elsif ($in{'resize'}) {
&error_setup($text{'pv_err3'});
$err = &resize_physical_volume($pv);
&error("<pre>$err</pre>") if ($err);
($newpv) = grep { $_->{'device'} eq $pv->{'device'} }
&list_physical_volumes($in{'vg'});
if ($newpv && defined($pv->{'pe_total'}) &&
defined($newpv->{'pe_total'}) &&
$newpv->{'pe_total'} == $pv->{'pe_total'}) {
&error(&text('pv_enoresize', "<tt>$pv->{'device'}</tt>"));
}
&webmin_log("resize", "pv", $in{'pv'}, $pv);
&redirect("index.cgi?mode=pvs");
}