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
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);
});
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 ($path, $owner, $vtype) = PVE::Storage::path($storecfg, $volid);
return if !$owner || ($owner != $vmid);
- return if $attr->{cdrom};
-
- die "unable to replicate volume '$volid', type '$vtype'\n" if $vtype ne 'images';
-
- 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;
my $snap = $conf->{snapshots}->{$snapname};
- 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 $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);
+ $snap->{runningmachine} = PVE::QemuServer::get_current_qemu_machine($vmid);
}
sub __snapshot_check_running {
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);
}
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) = @_;
}
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 {