public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH atomic snapshot 1/4] ui: snapshot: add atomic option
       [not found] <20250609073214.7880-1-denis.kanchev@storpool.com>
@ 2025-06-09  7:32 ` Demayl via pve-devel
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic_snapshot 2/4] snapshot api: add type option when making snapshots Demayl via pve-devel
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 4+ messages in thread
From: Demayl via pve-devel @ 2025-06-09  7:32 UTC (permalink / raw)
  To: pve-devel; +Cc: Demayl

[-- Attachment #1: Type: message/rfc822, Size: 7734 bytes --]

From: Demayl <denis.kanchev@storpool.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH atomic snapshot 1/4] ui: snapshot: add atomic option
Date: Mon,  9 Jun 2025 10:32:09 +0300
Message-ID: <20250609073214.7880-2-denis.kanchev@storpool.com>

Signed-off-by: Demayl <denis.kanchev@storpool.com>
---
 www/manager6/window/Snapshot.js | 43 +++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/www/manager6/window/Snapshot.js b/www/manager6/window/Snapshot.js
index 93ab61ec..902258b2 100644
--- a/www/manager6/window/Snapshot.js
+++ b/www/manager6/window/Snapshot.js
@@ -7,10 +7,14 @@ Ext.define('PVE.window.Snapshot', {
 	    isCreate: undefined,
 	    running: false,
 	    guestAgentEnabled: false,
+	    atomicPossible: false,
+	    atomicPreferred: false,
 	},
 	formulas: {
 	    runningWithoutGuestAgent: (get) => get('type') === 'qemu' && get('running') && !get('guestAgentEnabled'),
 	    shouldWarnAboutFS: (get) => get('isCreate') && get('runningWithoutGuestAgent') && get('!vmstate.checked'),
+	    atomicDisabled: (get) => !get('atomicPossible'),
+	    typeCheck: (get) => get('atomicPreferred') && get('atomicPossible') ? 'atomic' : 'sequential' ,
 	},
     },
 
@@ -55,6 +59,15 @@ Ext.define('PVE.window.Snapshot', {
 		    vm.set('guestAgentEnabled', !!PVE.Parser.parseBoolean(enabled.enabled));
 		},
 	    });
+	    Proxmox.Utils.API2Request({
+		url: `/nodes/${me.nodename}/${me.type}/${me.vmid}/status/current`,
+		method: 'GET',
+		success: function(response, options) {
+		    let snap = response.result.data.snapshots;
+		    vm.set('atomicPossible', !!PVE.Parser.parseBoolean(snap.atomic_possible.toString()));
+		    vm.set('atomicPreferred', !!PVE.Parser.parseBoolean(snap.atomic_preferred.toString()));
+		},
+	    });
 	}
 
 	me.items = [
@@ -85,6 +98,36 @@ Ext.define('PVE.window.Snapshot', {
 		checked: 1,
 		fieldLabel: gettext('Include RAM'),
 	    },
+	    {
+		xtype: 'radiogroup',
+		fieldLabel: gettext('Type'),
+		vertical: true,
+		hidden: !me.isCreate,
+		columns: 1,
+		reference: 'atomic',
+		items: [
+		    {
+			xtype: 'radiofield',
+			boxLabel: gettext('Sequential'),
+			name: 'type',
+			flex: 1,
+			inputValue: 'sequential',
+			bind: { value: '{typeCheck}' }
+		    },
+		    {
+			xtype: 'radiofield',
+			boxLabel: gettext('Atomic'),
+			name: 'type',
+			flex: 1,
+			inputValue: 'atomic',
+			disabled: true,
+			bind: {
+			    value: '{typeCheck}',
+			    disabled: '{atomicDisabled}',
+			}
+		    }
+		]
+	    },
 	    {
 		xtype: 'textareafield',
 		grow: true,
-- 
2.43.0



[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pve-devel] [PATCH atomic_snapshot 2/4] snapshot api: add type option when making snapshots
       [not found] <20250609073214.7880-1-denis.kanchev@storpool.com>
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 1/4] ui: snapshot: add atomic option Demayl via pve-devel
@ 2025-06-09  7:32 ` Demayl via pve-devel
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 3/4] storage snapshot: add optional atomic snapshot creation in snapshot_create Demayl via pve-devel
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 4/4] plugin: add optional atomic snapshot creation Demayl via pve-devel
  3 siblings, 0 replies; 4+ messages in thread
From: Demayl via pve-devel @ 2025-06-09  7:32 UTC (permalink / raw)
  To: pve-devel; +Cc: Demayl

[-- Attachment #1: Type: message/rfc822, Size: 7798 bytes --]

From: Demayl <denis.kanchev@storpool.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH atomic_snapshot 2/4] snapshot api: add type option when making snapshots
Date: Mon,  9 Jun 2025 10:32:10 +0300
Message-ID: <20250609073214.7880-3-denis.kanchev@storpool.com>

Allows picking between atomic and sequential snapshots

Default sequential

Signed-off-by: Demayl <denis.kanchev@storpool.com>
---
 PVE/API2/Qemu.pm  |  7 ++++++-
 PVE/QemuConfig.pm | 13 +++++++++++++
 PVE/QemuServer.pm | 10 ++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 626cce45..27d86438 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -5488,6 +5488,11 @@ __PACKAGE__->register_method({
 		type => 'string',
 		description => "A textual description or comment.",
 	    },
+	    type => {
+		optional => 1,
+		type => 'string',
+		description => "Sequential or atomic snapshot of VM volumes (if supported by storage)",
+	    },
 	},
     },
     returns => {
@@ -5519,7 +5524,7 @@ __PACKAGE__->register_method({
 	my $realcmd = sub {
 	    PVE::Cluster::log_msg('info', $authuser, "snapshot VM $vmid: $snapname");
 	    PVE::QemuConfig->snapshot_create($vmid, $snapname, $param->{vmstate},
-					     $param->{description});
+					     $param->{description}, $param->{type});
 	};
 
 	return $rpcenv->fork_worker('qmsnapshot', $vmid, $authuser, $realcmd);
diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
index 2609542c..7f6399c7 100644
--- a/PVE/QemuConfig.pm
+++ b/PVE/QemuConfig.pm
@@ -367,6 +367,19 @@ sub __snapshot_create_vol_snapshots_hook {
     }
 }
 
+sub get_atomic_snapshot_volumes {
+    my ($class, $conf) = @_;
+
+    my $volumes = $class->SUPER::get_atomic_snapshot_volumes($conf);
+    my $filtered = {};
+    for my $vol_name (keys %{$volumes}) {
+	if (! PVE::QemuServer::drive_is_cdrom($volumes->{$vol_name})) {
+		$filtered->{$vol_name} = $volumes->{$vol_name};
+	}
+    }
+    return $filtered;
+}
+
 sub __snapshot_create_vol_snapshot {
     my ($class, $vmid, $ds, $drive, $snapname) = @_;
 
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 577959a4..5c14ce49 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -2809,6 +2809,10 @@ our $vmstatus_return_properties = {
 	type => 'boolean',
 	optional => 1,
     },
+    snapshots => {
+	description => "Snapshot info.",
+	type => 'object',
+    },
 };
 
 my $last_proc_pid_stat;
@@ -2881,6 +2885,12 @@ sub vmstatus {
 	$d->{tags} = $conf->{tags} if defined($conf->{tags});
 
 	$res->{$vmid} = $d;
+
+	my ($can_atomic, $pref_atomic, undef) = PVE::QemuConfig->check_atomic_snapshots($conf);
+	$res->{$vmid}->{snapshots} = {
+	    atomic_possible => $can_atomic,
+	    atomic_preferred => $pref_atomic,
+	};
     }
 
     my $netdev = PVE::ProcFSTools::read_proc_net_dev();
-- 
2.43.0



[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pve-devel] [PATCH atomic snapshot 3/4] storage snapshot: add optional atomic snapshot creation in snapshot_create
       [not found] <20250609073214.7880-1-denis.kanchev@storpool.com>
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 1/4] ui: snapshot: add atomic option Demayl via pve-devel
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic_snapshot 2/4] snapshot api: add type option when making snapshots Demayl via pve-devel
@ 2025-06-09  7:32 ` Demayl via pve-devel
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 4/4] plugin: add optional atomic snapshot creation Demayl via pve-devel
  3 siblings, 0 replies; 4+ messages in thread
From: Demayl via pve-devel @ 2025-06-09  7:32 UTC (permalink / raw)
  To: pve-devel; +Cc: Demayl

[-- Attachment #1: Type: message/rfc822, Size: 8524 bytes --]

From: Demayl <denis.kanchev@storpool.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH atomic snapshot 3/4] storage snapshot: add optional atomic snapshot creation in snapshot_create
Date: Mon,  9 Jun 2025 10:32:11 +0300
Message-ID: <20250609073214.7880-4-denis.kanchev@storpool.com>

Signed-off-by: Demayl <denis.kanchev@storpool.com>
---
 src/PVE/AbstractConfig.pm | 60 +++++++++++++++++++++++++++++++++------
 1 file changed, 51 insertions(+), 9 deletions(-)

diff --git a/src/PVE/AbstractConfig.pm b/src/PVE/AbstractConfig.pm
index 3d4fcbb..8bb271d 100644
--- a/src/PVE/AbstractConfig.pm
+++ b/src/PVE/AbstractConfig.pm
@@ -811,10 +811,39 @@ sub __snapshot_activate_storages {
     return;
 }
 
+sub get_atomic_snapshot_volumes {
+    my ($class, $conf) = @_;
+    my $volumes = {};
+    $class->foreach_volume(
+        $conf,
+        sub {
+            my ($key, $volume_string) = @_;
+            $volumes->{$key} = $volume_string;
+        }
+    );
+    return $volumes;
+}
+sub check_atomic_snapshots {
+    my ($class, $conf) = @_;
+    return PVE::Storage::volumes_atomic_snapshot_possible(
+        PVE::Storage::config(),
+        $class->get_atomic_snapshot_volumes($conf),
+    );
+}
+
+sub __snapshot_volumes_atomically {
+    my ($class, $voldata, $snapname) = @_;
+    PVE::Storage::volumes_atomic_snapshot($voldata, $snapname);
+    return { map { $_ => 1 } keys %{$voldata} };
+}
+
+
 # Creates a snapshot for the VM/CT.
+# Type can be either atomic or sequential
 sub snapshot_create {
-    my ($class, $vmid, $snapname, $save_vmstate, $comment) = @_;
+    my ($class, $vmid, $snapname, $save_vmstate, $comment, $type) = @_;
 
+    my $atomic = $type && $type eq 'atomic';
     my $snap = $class->__snapshot_prepare($vmid, $snapname, $save_vmstate, $comment);
 
     $save_vmstate = 0 if !$snap->{vmstate};
@@ -823,32 +852,45 @@ sub snapshot_create {
 
     my ($running, $freezefs) = $class->__snapshot_check_freeze_needed($vmid, $conf, $snap->{vmstate});
 
+    my ($can_atomic, undef, $vol_cfg) = $class->check_atomic_snapshots($snap);
+    if ($atomic && !$can_atomic) {
+	warn "snapshot create failed: starting cleanup\n";
+	eval { $class->snapshot_delete($vmid, $snapname, 1, {}); };
+	warn "$@" if $@;
+	die "atomic snapshot impossible for mixed storage\n";
+    }
+    my $is_atomic = $atomic && $can_atomic;
+
     my $drivehash = {};
 
     eval {
 	$class->__snapshot_activate_storages($conf, 0);
 
-	if ($freezefs) {
+	if ($freezefs && !$is_atomic) {
 	    $class->__snapshot_freeze($vmid, 0);
 	}
 
 	$class->__snapshot_create_vol_snapshots_hook($vmid, $snap, $running, "before");
 
-	$class->foreach_volume($snap, sub {
-	    my ($vs, $volume) = @_;
+	if ($is_atomic) {
+	    $drivehash = $class->__snapshot_volumes_atomically($vol_cfg, $snapname);
+	} else {
+	    $class->foreach_volume($snap, sub {
+		my ($vs, $volume) = @_;
 
-	    $class->__snapshot_create_vol_snapshot($vmid, $vs, $volume, $snapname);
-	    $drivehash->{$vs} = 1;
-	});
+		$class->__snapshot_create_vol_snapshot($vmid, $vs, $volume, $snapname);
+		$drivehash->{$vs} = 1;
+	    });
+	}
     };
     my $err = $@;
 
     if ($running) {
 	$class->__snapshot_create_vol_snapshots_hook($vmid, $snap, $running, "after");
-	if ($freezefs) {
+	if ($freezefs && !$is_atomic) {
 	    $class->__snapshot_freeze($vmid, 1);
+	    $class->__snapshot_create_vol_snapshots_hook($vmid, $snap, $running, "after-unfreeze");
 	}
-	$class->__snapshot_create_vol_snapshots_hook($vmid, $snap, $running, "after-unfreeze");
     }
 
     if ($err) {
-- 
2.43.0



[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pve-devel] [PATCH atomic snapshot 4/4] plugin: add optional atomic snapshot creation
       [not found] <20250609073214.7880-1-denis.kanchev@storpool.com>
                   ` (2 preceding siblings ...)
  2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 3/4] storage snapshot: add optional atomic snapshot creation in snapshot_create Demayl via pve-devel
@ 2025-06-09  7:32 ` Demayl via pve-devel
  3 siblings, 0 replies; 4+ messages in thread
From: Demayl via pve-devel @ 2025-06-09  7:32 UTC (permalink / raw)
  To: pve-devel; +Cc: Demayl

[-- Attachment #1: Type: message/rfc822, Size: 8471 bytes --]

From: Demayl <denis.kanchev@storpool.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH atomic snapshot 4/4] plugin: add optional atomic snapshot creation
Date: Mon,  9 Jun 2025 10:32:12 +0300
Message-ID: <20250609073214.7880-5-denis.kanchev@storpool.com>

This will allow creating atomic snapshots from the custom plugins when they support it

Signed-off-by: Demayl <denis.kanchev@storpool.com>
---
 src/PVE/Storage.pm        | 52 +++++++++++++++++++++++++++++++++++++--
 src/PVE/Storage/Plugin.pm | 16 ++++++++++++
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index d0a696a..9b044cc 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -42,11 +42,11 @@ use PVE::Storage::BTRFSPlugin;
 use PVE::Storage::ESXiPlugin;
 
 # Storage API version. Increment it on changes in storage API interface.
-use constant APIVER => 11;
+use constant APIVER => 12;
 # Age is the number of versions we're backward compatible with.
 # This is like having 'current=APIVER' and age='APIAGE' in libtool,
 # see https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
-use constant APIAGE => 2;
+use constant APIAGE => 3;
 
 our $KNOWN_EXPORT_FORMATS = ['raw+size', 'tar+size', 'qcow2+size', 'vmdk+size', 'zfs', 'btrfs'];
 
@@ -347,6 +347,54 @@ sub volume_rollback_is_possible {
     }
 }
 
+
+sub get_volumes_storecfg {
+    my ($cfg, $volume_data) = @_;
+    my $vol_cfg = {};
+    for my $volid (keys %{$volume_data}) {
+	my ($storeid, $volname) = parse_volume_id($volume_data->{$volid}->{file}, 1);
+	if ($storeid) {
+	    $vol_cfg->{$volname} = {
+		storeid => $storeid,
+		scfg => storage_config($cfg, $storeid),
+	    };
+	}
+	elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+	    die "snapshot file/device '$volid' is not possible\n";
+	} else {
+	    die "unable to parse volume ID '$volid'\n";
+	}
+    }
+    return $vol_cfg;
+}
+
+sub volumes_atomic_snapshot_possible {
+    my ($cfg, $disk_data) = @_;
+    my $last_type;
+    my $voldata = get_volumes_storecfg($cfg, $disk_data);
+    for my $key (keys %$voldata) {
+	my $type = $voldata->{ $key }->{scfg}->{type};
+	if (defined($last_type) && $last_type ne $type) {
+	    return (0, 0, $voldata);
+	}
+	$last_type = $type;
+    }
+    my $plugin = PVE::Storage::Plugin->lookup($last_type);
+    return (
+	$plugin->volumes_atomic_snapshot_possible($voldata),
+	$plugin->atomic_snapshot_preferred($voldata),
+	$voldata,
+    )
+}
+
+sub volumes_atomic_snapshot {
+    my ($voldata, $snapname) = @_;
+    my $type   = $voldata->{(keys %{$voldata})[0]}->{scfg}->{type};
+    my $plugin = PVE::Storage::Plugin->lookup($type);
+
+    $plugin->volumes_atomic_snapshot($voldata, $snapname);
+}
+
 sub volume_snapshot {
     my ($cfg, $volid, $snap) = @_;
 
diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
index 4e16420..391dd0b 100644
--- a/src/PVE/Storage/Plugin.pm
+++ b/src/PVE/Storage/Plugin.pm
@@ -1904,4 +1904,20 @@ sub config_aware_base_mkdir {
     }
 }
 
+sub volumes_atomic_snapshot_possible {
+    my ($class, $voldata) = @_;
+    return 0;
+}
+
+sub atomic_snapshot_preferred {
+    my ($class, $volata) = @_;
+    return 0;
+}
+
+# Performs an atomic (crash-consistent) snapshot of all volumes at once.
+sub volumes_atomic_snapshot {
+    my ($class, $voldata, $snap) = @_;
+    die "volumes_atomic_snapshot is not implemented for $class";
+}
+
 1;
-- 
2.43.0



[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-06-09  7:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20250609073214.7880-1-denis.kanchev@storpool.com>
2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 1/4] ui: snapshot: add atomic option Demayl via pve-devel
2025-06-09  7:32 ` [pve-devel] [PATCH atomic_snapshot 2/4] snapshot api: add type option when making snapshots Demayl via pve-devel
2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 3/4] storage snapshot: add optional atomic snapshot creation in snapshot_create Demayl via pve-devel
2025-06-09  7:32 ` [pve-devel] [PATCH atomic snapshot 4/4] plugin: add optional atomic snapshot creation Demayl via pve-devel

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