X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FQemuConfig.pm;h=6693585016fb7f53ce485d4aa8940aee6a85f581;hb=159719e55b0e84ec91c72b051adc44a7cb52662c;hp=1ea975d157dc6155d17af1233efe746ebe968bca;hpb=f949eb77608c4e0bb88c517d792a170efa25409d;p=qemu-server.git diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm index 1ea975d..6693585 100644 --- a/PVE/QemuConfig.pm +++ b/PVE/QemuConfig.pm @@ -20,7 +20,7 @@ mkdir $confdir; my $lock_dir = "/var/lock/qemu-server"; mkdir $lock_dir; -my $MAX_UNUSED_DISKS = 8; +my $MAX_UNUSED_DISKS = 256; # BEGIN implemented abstract methods from PVE::AbstractConfig @@ -55,7 +55,7 @@ sub has_feature { my ($ds, $drive) = @_; return if PVE::QemuServer::drive_is_cdrom($drive); - return if $backup_only && !$drive->{backup}; + return if $backup_only && defined($drive->{backup}) && !$drive->{backup}; my $volid = $drive->{file}; $err = 1 if !PVE::Storage::volume_has_feature($storecfg, $feature, $volid, $snapname, $running); }); @@ -71,15 +71,29 @@ sub get_replicatable_volumes { my $test_volid = sub { my ($volid, $attr) = @_; + return if $attr->{cdrom}; + + return if !$cleanup && !$attr->{replicate}; + + if ($volid =~ m|^/|) { + return if !$attr->{replicate}; + return if $cleanup || $noerr; + die "unable to replicate local file/device '$volid'\n"; + } + my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, $noerr); return if !$storeid; - my $scfg = storage_config($storecfg, $storeid); + my $scfg = PVE::Storage::storage_config($storecfg, $storeid); return if $scfg->{shared}; - return if $attr->{cdrom}; + my ($path, $owner, $vtype) = PVE::Storage::path($storecfg, $volid); + return if !$owner || ($owner != $vmid); - return if !$cleanup && !$attr->{replicate}; + if ($vtype ne 'images') { + return if $cleanup || $noerr; + die "unable to replicate volume '$volid', type '$vtype'\n"; + } if (!PVE::Storage::volume_has_feature($storecfg, 'replicate', $volid)) { return if $cleanup || $noerr; @@ -91,49 +105,57 @@ sub get_replicatable_volumes { PVE::QemuServer::foreach_volid($conf, $test_volid); + # add 'unusedX' volumes to volhash + foreach my $key (keys %$conf) { + if ($key =~ m/^unused/) { + $test_volid->($conf->{$key}, { replicate => 1 }); + } + } + return $volhash; } sub __snapshot_save_vmstate { - my ($class, $vmid, $conf, $snapname, $storecfg) = @_; - - my $snap = $conf->{snapshots}->{$snapname}; + my ($class, $vmid, $conf, $snapname, $storecfg, $suspend) = @_; - my $target; - - # search shared storage first - PVE::QemuServer::foreach_writable_storage($conf, sub { - my ($sid) = @_; - my $scfg = PVE::Storage::storage_config($storecfg, $sid); - return if !$scfg->{shared}; - - $target = $sid if !$target || $scfg->{path}; # prefer file based storage - }); + # first, use explicitly configured storage + my $target = $conf->{vmstatestorage}; if (!$target) { - # now search local storage - PVE::QemuServer::foreach_writable_storage($conf, sub { + my ($shared, $local); + PVE::QemuServer::foreach_storage_used_by_vm($conf, sub { my ($sid) = @_; my $scfg = PVE::Storage::storage_config($storecfg, $sid); - return if $scfg->{shared}; - - $target = $sid if !$target || $scfg->{path}; # prefer file based storage; + my $dst = $scfg->{shared} ? \$shared : \$local; + $$dst = $sid if !$$dst || $scfg->{path}; # prefer file based storage }); - } - $target = 'local' if !$target; + # second, use shared storage where VM has at least one disk + # third, use local storage where VM has at least one disk + # fall back to local storage + $target = $shared // $local // 'local'; + } - my $driver_state_size = 500; # assume 32MB is enough to safe all driver state; - # we abort live save after $conf->{memory}, so we need at max twice that space + my $driver_state_size = 500; # assume 500MB is enough to safe all driver state; my $size = $conf->{memory}*2 + $driver_state_size; + my $scfg = PVE::Storage::storage_config($storecfg, $target); my $name = "vm-$vmid-state-$snapname"; - my $scfg = PVE::Storage::storage_config($storecfg, $target); $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); - # always overwrite machine if we save vmstate. This makes sure we - # can restore it later using correct machine type - $snap->{machine} = 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 ($suspend) { + $conf->{vmstate} = $statefile; + $conf->{runningmachine} = $runningmachine; + } else { + my $snap = $conf->{snapshots}->{$snapname}; + $snap->{vmstate} = $statefile; + $snap->{runningmachine} = $runningmachine; + } + + return $statefile; } sub __snapshot_check_running { @@ -145,8 +167,8 @@ sub __snapshot_check_freeze_needed { my ($class, $vmid, $config, $save_vmstate) = @_; my $running = $class->__snapshot_check_running($vmid); - if ($save_vmstate) { - return ($running, $running && $config->{agent} && PVE::QemuServer::qga_check_running($vmid)); + if (!$save_vmstate) { + return ($running, $running && PVE::QemuServer::parse_guest_agent($config)->{enabled} && PVE::QemuServer::qga_check_running($vmid)); } else { return ($running, 0); } @@ -266,6 +288,39 @@ sub __snapshot_delete_vol_snapshot { push @$unused, $volid; } +sub __snapshot_rollback_hook { + my ($class, $vmid, $conf, $snap, $prepare, $data) = @_; + + if ($prepare) { + # we save the machine of the current config + $data->{oldmachine} = $conf->{machine}; + } else { + # if we have a 'runningmachine' entry in the snapshot we use that + # for the forcemachine parameter, else we use the old logic + if (defined($conf->{runningmachine})) { + $data->{forcemachine} = $conf->{runningmachine}; + delete $conf->{runningmachine}; + } else { + # Note: old code did not store 'machine', so we try to be smart + # and guess the snapshot was generated with kvm 1.4 (pc-i440fx-1.4). + $data->{forcemachine} = $conf->{machine} || 'pc-i440fx-1.4'; + + # we remove the 'machine' configuration if not explicitly specified + # in the original config. + delete $conf->{machine} if $snap->{vmstate} && !defined($data->{oldmachine}); + } + + if ($conf->{vmgenid}) { + # tell the VM that it's another generation, so it can react + # appropriately, e.g. dirty-mark copies of distributed databases or + # re-initializing its random number generator + $conf->{vmgenid} = PVE::QemuServer::generate_uuid(); + } + } + + return; +} + sub __snapshot_rollback_vol_possible { my ($class, $drive, $snapname) = @_; @@ -294,11 +349,11 @@ sub __snapshot_rollback_vm_stop { } sub __snapshot_rollback_vm_start { - my ($class, $vmid, $vmstate, $forcemachine) = @_; + my ($class, $vmid, $vmstate, $data) = @_; my $storecfg = PVE::Storage::config(); my $statefile = PVE::Storage::path($storecfg, $vmstate); - PVE::QemuServer::vm_start($storecfg, $vmid, $statefile, undef, undef, undef, $forcemachine); + PVE::QemuServer::vm_start($storecfg, $vmid, $statefile, undef, undef, undef, $data->{forcemachine}); } sub __snapshot_rollback_get_unused {