From: copystring <copystring@gmail.com>
To: pve-devel@lists.proxmox.com
Cc: copystring <copystring@gmail.com>
Subject: SPAM: [RFC PATCH v2 1/4] lxc: create: add isolated OCI rootfs preparation
Date: Sat, 18 Jul 2026 18:05:59 +0200 [thread overview]
Message-ID: <8c46d715887f1e6913a678a38a4c3b45423a3320.1784389742.git.copystring@gmail.com> (raw)
In-Reply-To: <cover.1784389742.git.copystring@gmail.com>
Prepare a new rootfs volume from an OCI archive without mounting any existing mpX mount points. This keeps the active container config untouched until the API layer switches rootfs under config lock.
Keep the allocation and temporary mount/populate flow generic: create the new rootfs volume, mount only that volume in a private mount namespace, populate it through a callback, and free the newly allocated volume on prepare or cleanup failure.
Signed-off-by: copystring <copystring@gmail.com>
---
src/PVE/LXC/Create.pm | 115 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)
diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index 69065b9..9fc01a8 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -783,6 +783,121 @@ sub restore_oci_archive {
return $conf; # it's a reference anyway, so return mostly for convenience.
}
+my sub volume_size_to_gb {
+ my ($size) = @_;
+
+ my $size_mib = int(($size + 1024 * 1024 - 1) / (1024 * 1024));
+ my $size_gb = sprintf('%.6f', $size_mib / 1024);
+ $size_gb =~ s/0+$//;
+ $size_gb =~ s/\.$//;
+
+ return $size_gb;
+}
+
+my sub idmap_lxc_config {
+ my ($conf) = @_;
+
+ return [map { [@$_] } grep { $_->[0] eq 'lxc.idmap' } @{ $conf->{lxc} // [] }];
+}
+
+my sub create_rootfs_volume {
+ my ($storage_cfg, $vmid, $storage, $size, $conf, $rootdir_base, $rootdir_name, $populate) =
+ @_;
+
+ my $size_gb = volume_size_to_gb($size);
+ my $rootfs = PVE::LXC::Config->parse_volume('rootfs', $conf->{rootfs});
+ my $new_rootfs_config = {
+ %$rootfs,
+ volume => "$storage:$size_gb",
+ };
+ delete $new_rootfs_config->{type};
+ delete $new_rootfs_config->{size};
+
+ my $settings = {
+ rootfs => PVE::LXC::Config->print_ct_mountpoint($new_rootfs_config, 1),
+ };
+ my $new_conf = {
+ lxc => idmap_lxc_config($conf),
+ };
+ $new_conf->{unprivileged} = $conf->{unprivileged} if exists($conf->{unprivileged});
+
+ $rootdir_base //= "/var/lib/lxc/$vmid";
+ make_path($rootdir_base);
+ my $rootdir = "$rootdir_base/$rootdir_name";
+
+ my $vollist = PVE::LXC::create_disks($storage_cfg, $vmid, $settings, $new_conf);
+ my $new_rootfs = PVE::LXC::Config->parse_volume('rootfs', $new_conf->{rootfs});
+ my $new_volid = $new_rootfs->{volume};
+
+ eval {
+ my (undef, $root_uid, $root_gid) = PVE::LXC::parse_id_maps($conf);
+
+ $new_conf = PVE::LXC::run_unshared(sub {
+ die "temporary rootfs path '$rootdir' already exists\n" if -e $rootdir;
+
+ my @mounted;
+ eval {
+ mkdir $rootdir
+ or die "failed to create temporary rootfs path '$rootdir': $!\n";
+
+ my $mountpoint = { %$new_rootfs, mp => '/', ro => 0 };
+ PVE::LXC::mountpoint_mount(
+ $mountpoint, $rootdir, $storage_cfg, undef, $root_uid, $root_gid,
+ );
+ push @mounted, $rootdir;
+
+ $populate->($rootdir, $new_conf);
+ };
+ my $err = $@;
+ my $cleanup_err = '';
+
+ foreach my $mount (reverse @mounted) {
+ eval {
+ PVE::Tools::run_command(['/bin/umount', $mount], errfunc => sub { });
+ };
+ $cleanup_err .= "can't unmount temporary rootfs path '$mount': $@\n" if $@;
+ }
+
+ $cleanup_err .= "failed to remove temporary rootfs path '$rootdir': $!\n"
+ if -d $rootdir && !rmdir $rootdir;
+
+ die $err if $err;
+ die $cleanup_err if $cleanup_err;
+
+ return $new_conf;
+ });
+ };
+ if (my $err = $@) {
+ PVE::LXC::destroy_disks($storage_cfg, $vollist);
+ die $err;
+ }
+
+ return ($new_conf->{rootfs}, $new_volid, $new_conf);
+}
+
+sub create_oci_rootfs {
+ my ($storage_cfg, $vmid, $archive, $storage, $size, $conf, $rootdir_base) = @_;
+
+ die "archive '$archive' is not an OCI image archive\n"
+ if !archive_is_oci_format($storage_cfg, $archive);
+
+ return create_rootfs_volume(
+ $storage_cfg,
+ $vmid,
+ $storage,
+ $size,
+ $conf,
+ $rootdir_base,
+ '.oci-replace-rootfs',
+ sub {
+ my ($rootdir, $new_conf) = @_;
+
+ restore_oci_archive($storage_cfg, $archive, $rootdir, $new_conf);
+ PVE::LXC::Setup->new($new_conf, $rootdir); # detect OS and architecture
+ },
+ );
+}
+
sub resolve_oci_user {
my ($userstr, $rootdir) = @_;
--
2.55.0.windows.3
next prev parent reply other threads:[~2026-07-20 11:29 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 19:40 SPAM: [RFC PATCH 0/4] lxc: add safe OCI rootfs replacement copystring
2026-07-06 19:40 ` SPAM: [RFC PATCH 1/4] lxc: create: add isolated OCI rootfs preparation copystring
2026-07-15 12:02 ` Filip Schauer
2026-07-06 19:40 ` SPAM: [RFC PATCH 2/4] api: lxc: add OCI rootfs replacement endpoint copystring
2026-07-06 19:40 ` SPAM: [RFC PATCH 3/4] pct: add OCI rootfs replacement command copystring
2026-07-06 19:40 ` SPAM: [RFC PATCH 4/4] test: cover OCI rootfs replacement API transaction copystring
2026-07-06 19:40 ` SPAM: [RFC PATCH pve-manager] lxc: add OCI rootfs replacement window copystring
2026-07-06 19:40 ` SPAM: [RFC PATCH pve-docs] pct: document OCI rootfs replacement semantics copystring
2026-07-14 13:23 ` [RFC PATCH 0/4] lxc: add safe OCI rootfs replacement Filip Schauer
2026-07-18 16:05 ` SPAM: [RFC PATCH v2 " copystring
2026-07-18 16:05 ` copystring [this message]
2026-07-18 16:06 ` SPAM: [RFC PATCH v2 2/4] api: lxc: add OCI rootfs replacement endpoint copystring
2026-07-18 16:06 ` SPAM: [RFC PATCH v2 3/4] pct: add OCI rootfs replacement command copystring
2026-07-18 16:06 ` SPAM: [RFC PATCH v2 4/4] test: cover OCI rootfs replacement API transaction copystring
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=8c46d715887f1e6913a678a38a4c3b45423a3320.1784389742.git.copystring@gmail.com \
--to=copystring@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.