[pve-devel] [PATCH qemu-server 3/5] implement suspend to disk for running vms
Thomas Lamprecht
t.lamprecht at proxmox.com
Mon Mar 11 16:23:55 CET 2019
On 3/11/19 3:45 PM, Dominik Csapak wrote:
> the idea is to have the same logic as with snapshots, but without
> the snapshotting of the disks, and after saving the vm state (incl memory),
> we hard shut off the guest.
>
> this way the disks will not be touched anymore by the guest
>
> to prevent any alteration of the vm (incl migration, hw changes, etc) we
> add a config lock 'suspend'
>
> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> ---
> PVE/QemuServer.pm | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 61 insertions(+), 8 deletions(-)
>
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 02bb798..46620de 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -300,7 +300,7 @@ my $confdesc = {
> optional => 1,
> type => 'string',
> description => "Lock/unlock the VM.",
> - enum => [qw(backup clone create migrate rollback snapshot snapshot-delete)],
> + enum => [qw(backup clone create migrate rollback snapshot snapshot-delete suspend)],
> },
> cpulimit => {
> optional => 1,
> @@ -5658,7 +5658,7 @@ sub vm_stop {
> }
>
> sub vm_suspend {
> - my ($vmid, $skiplock) = @_;
> + my ($vmid, $skiplock, $includestate) = @_;
>
> PVE::QemuConfig->lock_config($vmid, sub {
>
> @@ -5668,6 +5668,49 @@ sub vm_suspend {
> if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
>
> vm_mon_cmd($vmid, "stop");
> +
> + if ($includestate) {
> + $conf->{lock} = 'suspend';
> + PVE::QemuConfig->write_config($vmid, $conf);
> +
> + # save vm state
> + my $storecfg = PVE::Storage::config();
> + my $vmstate = prepare_save_vmstate($vmid, $conf, undef, $storecfg);
> + my $path = PVE::Storage::path($storecfg, $vmstate);
> + PVE::Storage::activate_volumes($storecfg, [$vmstate]);
> +
> + eval {
> + PVE::QemuServer::vm_mon_cmd($vmid, "savevm-start", statefile => $path);
> + for(;;) {
> + my $stat = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "query-savevm");
s/stat/state/ ?
> + if (!$stat->{status}) {
> + die "savevm not active\n";
> + } elsif ($stat->{status} eq 'active') {
> + sleep(1);
> + next;
> + } elsif ($stat->{status} eq 'completed') {
> + last;
> + } else {
> + die "query-savevm returned status '$stat->{status}'\n";
> + }
> + }
> + };
> + if (my $err = $@) {
> + # cleanup
> + warn $err;
> + eval {
> + vm_mon_cmd($vmid, "savevm-end");
> + PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
> + PVE::Storage::vdisk_free($storecfg, $vmstate);
keeping the lock though?
> + };
> + warn $@ if $@;
> + return;
> + }
> +
> + # save changes and write config
> + PVE::QemuConfig->write_config($vmid, $conf);
> + vm_qmp_command($vmid, { execute => "quit" });
> + }
> });
> }
>
> @@ -7103,8 +7146,6 @@ sub nbd_stop {
> sub prepare_save_vmstate {
> my ($vmid, $conf, $snapname, $storecfg) = @_;
>
> - my $snap = $conf->{snapshots}->{$snapname};
> -
> # first, use explicitly configured storage
> my $target = $conf->{vmstatestorage};
>
> @@ -7125,12 +7166,24 @@ sub prepare_save_vmstate {
>
> my $driver_state_size = 500; # assume 500MB is enough to safe all driver state;
> my $size = $conf->{memory}*2 + $driver_state_size;
> -
> - my $name = "vm-$vmid-state-$snapname";
> my $scfg = PVE::Storage::storage_config($storecfg, $target);
> +
> + my $name = "vm-$vmid-state-" . ($snapname // 'suspend');
'suspend' is a valid snapshot name, shouldn't this be a little more robust?
> $name .= ".raw" if $scfg->{path}; # add filename extension for file base storage
> - $snap->{vmstate} = PVE::Storage::vdisk_alloc($storecfg, $target, $vmid, 'raw', $name, $size*1024);
> - $snap->{runningmachine} = PVE::QemuServer::get_current_qemu_machine($vmid);
> +
> + my $statefile = PVE::Storage::vdisk_alloc($storecfg, $target, $vmid, 'raw', $name, $size*1024);
> + my $runningmachine = PVE::QemuServer::get_current_qemu_machine($vmid);
> +
> + if (defined($snapname)) {
I do not really like this implicit behaviour decided through the defindness of $snapname.
A more direct, easer to read out could be nicer. E.g., an additional function parameter.
$snapname could be always passed, either the real $snapname or some unique "$suspend-$datetime"
name?
> + my $snap = $conf->{snapshots}->{$snapname};
> + $snap->{vmstate} = $statefile;
> + $snap->{runningmachine} = $runningmachine;
> + } else {
> + $conf->{vmstate} = $statefile;
> + $conf->{runningmachine} = $runningmachine;
> + }
> +
> + return $statefile;
> }
>
> # bash completion helper
>
More information about the pve-devel
mailing list