public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Fiona Ebner <f.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH container 2/2] api: resize: fork before locking
Date: Tue, 30 May 2023 15:52:07 +0200	[thread overview]
Message-ID: <20230530135207.87705-6-f.ebner@proxmox.com> (raw)
In-Reply-To: <20230530135207.87705-1-f.ebner@proxmox.com>

making sure the early checks are done once before the expensive
forking and locking and once after locking, because the state might
have changed.

The size calculation had to be adapted a bit, to ensure the original
size is not added twice when it's a request with a leading '+'.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---

Best viewed with -w.

 src/PVE/API2/LXC.pm | 124 +++++++++++++++++++++++---------------------
 1 file changed, 66 insertions(+), 58 deletions(-)

diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
index f69b44b..2d67997 100644
--- a/src/PVE/API2/LXC.pm
+++ b/src/PVE/API2/LXC.pm
@@ -1926,15 +1926,14 @@ __PACKAGE__->register_method({
 
 	my $sizestr = extract_param($param, 'size');
 	my $ext = ($sizestr =~ s/^\+//);
-	my $newsize = PVE::JSONSchema::parse_size($sizestr);
-	die "invalid size string" if !defined($newsize);
+	my $request_size = PVE::JSONSchema::parse_size($sizestr);
+	die "invalid size string" if !defined($request_size);
 
 	die "no options specified\n" if !scalar(keys %$param);
 
 	my $storage_cfg = cfs_read_file("storage.cfg");
 
-	my $code = sub {
-
+	my $load_and_check = sub {
 	    my $conf = PVE::LXC::Config->load_config($vmid);
 	    PVE::LXC::Config->check_lock($conf);
 
@@ -1942,8 +1941,6 @@ __PACKAGE__->register_method({
 
 	    PVE::Tools::assert_if_modified($digest, $conf->{digest});
 
-	    my $running = PVE::LXC::check_running($vmid);
-
 	    my $disk = $param->{disk};
 	    my $mp = PVE::LXC::Config->parse_volume($disk, $conf->{$disk});
 
@@ -1965,66 +1962,77 @@ __PACKAGE__->register_method({
 
 	    die "Could not determine current size of volume '$volid'\n" if !defined($size);
 
-	    $newsize += $size if $ext;
+	    my $newsize = $ext ? $size + $request_size : $request_size;
 	    $newsize = int($newsize);
 
 	    die "unable to shrink disk size\n" if $newsize < $size;
 
 	    die "disk is already at specified size\n" if $size == $newsize;
 
-	    PVE::Cluster::log_msg('info', $authuser, "update CT $vmid: resize --disk $disk --size $sizestr");
-	    my $realcmd = sub {
-		# Note: PVE::Storage::volume_resize doesn't do anything if $running=1, so
-		# we pass 0 here (parameter only makes sense for qemu)
-		PVE::Storage::volume_resize($storage_cfg, $volid, $newsize, 0);
-
-		$mp->{size} = $newsize;
-		$conf->{$disk} = PVE::LXC::Config->print_ct_mountpoint($mp, $disk eq 'rootfs');
-
-		PVE::LXC::Config->write_config($vmid, $conf);
-
-		if ($format eq 'raw') {
-		    # we need to ensure that the volume is mapped, if not needed this is a NOP
-		    my $path = PVE::Storage::map_volume($storage_cfg, $volid);
-		    $path = PVE::Storage::path($storage_cfg, $volid) if !defined($path);
-		    if ($running) {
-
-			$mp->{mp} = '/';
-			my $use_loopdev = (PVE::LXC::mountpoint_mount_path($mp, $storage_cfg))[1];
-			$path = PVE::LXC::query_loopdev($path) if $use_loopdev;
-			die "internal error: CT running but mount point not attached to a loop device"
-			    if !$path;
-			PVE::Tools::run_command(['losetup', '--set-capacity', $path]) if $use_loopdev;
-
-			# In order for resize2fs to know that we need online-resizing a mountpoint needs
-			# to be visible to it in its namespace.
-			# To not interfere with the rest of the system we unshare the current mount namespace,
-			# mount over /tmp and then run resize2fs.
-
-			# interestingly we don't need to e2fsck on mounted systems...
-			my $quoted = PVE::Tools::shellquote($path);
-			my $cmd = "mount --make-rprivate / && mount $quoted /tmp && resize2fs $quoted";
-			eval {
-			    PVE::Tools::run_command(['unshare', '-m', '--', 'sh', '-c', $cmd]);
-			};
-			warn "Failed to update the container's filesystem: $@\n" if $@;
-		    } else {
-			eval {
-			    PVE::Tools::run_command(['e2fsck', '-f', '-y', $path]);
-			    PVE::Tools::run_command(['resize2fs', $path]);
-			};
-			warn "Failed to update the container's filesystem: $@\n" if $@;
-
-			# always un-map if not running, this is a NOP if not needed
-			PVE::Storage::unmap_volume($storage_cfg, $volid);
-		    }
-		}
-	    };
-
-	    return $rpcenv->fork_worker('resize', $vmid, $authuser, $realcmd);
+	    return ($conf, $disk, $mp, $volid, $format, $newsize);
 	};
 
-	return PVE::LXC::Config->lock_config($vmid, $code);;
+	my $code = sub {
+	    my ($conf, $disk, $mp, $volid, $format, $newsize) = $load_and_check->();
+
+	    my $running = PVE::LXC::check_running($vmid);
+
+	    PVE::Cluster::log_msg('info', $authuser, "update CT $vmid: resize --disk $disk --size $sizestr");
+
+	    # Note: PVE::Storage::volume_resize doesn't do anything if $running=1, so
+	    # we pass 0 here (parameter only makes sense for qemu)
+	    PVE::Storage::volume_resize($storage_cfg, $volid, $newsize, 0);
+
+	    $mp->{size} = $newsize;
+	    $conf->{$disk} = PVE::LXC::Config->print_ct_mountpoint($mp, $disk eq 'rootfs');
+
+	    PVE::LXC::Config->write_config($vmid, $conf);
+
+	    if ($format eq 'raw') {
+		# we need to ensure that the volume is mapped, if not needed this is a NOP
+		my $path = PVE::Storage::map_volume($storage_cfg, $volid);
+		$path = PVE::Storage::path($storage_cfg, $volid) if !defined($path);
+		if ($running) {
+
+		    $mp->{mp} = '/';
+		    my $use_loopdev = (PVE::LXC::mountpoint_mount_path($mp, $storage_cfg))[1];
+		    $path = PVE::LXC::query_loopdev($path) if $use_loopdev;
+		    die "internal error: CT running but mount point not attached to a loop device"
+			if !$path;
+		    PVE::Tools::run_command(['losetup', '--set-capacity', $path]) if $use_loopdev;
+
+		    # In order for resize2fs to know that we need online-resizing a mountpoint needs
+		    # to be visible to it in its namespace.
+		    # To not interfere with the rest of the system we unshare the current mount namespace,
+		    # mount over /tmp and then run resize2fs.
+
+		    # interestingly we don't need to e2fsck on mounted systems...
+		    my $quoted = PVE::Tools::shellquote($path);
+		    my $cmd = "mount --make-rprivate / && mount $quoted /tmp && resize2fs $quoted";
+		    eval {
+			PVE::Tools::run_command(['unshare', '-m', '--', 'sh', '-c', $cmd]);
+		    };
+		    warn "Failed to update the container's filesystem: $@\n" if $@;
+		} else {
+		    eval {
+			PVE::Tools::run_command(['e2fsck', '-f', '-y', $path]);
+			PVE::Tools::run_command(['resize2fs', $path]);
+		    };
+		    warn "Failed to update the container's filesystem: $@\n" if $@;
+
+		    # always un-map if not running, this is a NOP if not needed
+		    PVE::Storage::unmap_volume($storage_cfg, $volid);
+		}
+	    }
+	};
+
+	my $worker = sub {
+	    PVE::LXC::Config->lock_config($vmid, $code);;
+	};
+
+	$load_and_check->(); # early checks before forking+locking
+
+	return $rpcenv->fork_worker('resize', $vmid, $authuser, $worker);
     }});
 
 __PACKAGE__->register_method({
-- 
2.39.2





  parent reply	other threads:[~2023-05-30 13:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-30 13:52 [pve-devel] [PATCH-SERIES qemu-server/manager/container] resize endpoint improvements Fiona Ebner
2023-05-30 13:52 ` [pve-devel] [PATCH qemu-server 1/2] fix #517: api: allow resizing qcow2 disk with snapshots Fiona Ebner
2023-05-30 13:52 ` [pve-devel] [PATCH qemu-server 2/2] fix #2315: api: have resize endpoint spawn a worker task Fiona Ebner
2023-05-30 13:52 ` [pve-devel] [PATCH manager 1/1] ui: override description for resize task Fiona Ebner
2023-05-30 13:52 ` [pve-devel] [PATCH container 1/2] api: resize: drop error that can never apply Fiona Ebner
2023-05-30 13:52 ` Fiona Ebner [this message]
2023-06-07 17:29 ` [pve-devel] applied-series: [PATCH-SERIES qemu-server/manager/container] resize endpoint improvements Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230530135207.87705-6-f.ebner@proxmox.com \
    --to=f.ebner@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal