Opteron_G3 => 'AuthenticAMD',
Opteron_G4 => 'AuthenticAMD',
Opteron_G5 => 'AuthenticAMD',
+ EPYC => 'AuthenticAMD',
+ 'EPYC-IBPB' => 'AuthenticAMD',
# generic types, use vendor from host node
host => 'default',
maxLength => 20*3, # *3 since it's %xx url enoded
description => "The drive's reported serial number, url-encoded, up to 20 bytes long.",
optional => 1,
+ },
+ shared => {
+ type => 'boolean',
+ description => 'Mark this locally-managed volume as available on all nodes',
+ verbose_description => "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
+ optional => 1,
+ default => 0,
}
);
my $volhash = {};
my $test_volid = sub {
- my ($volid, $is_cdrom, $replicate, $snapname) = @_;
+ my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
return if !$volid;
$volhash->{$volid}->{replicate} //= 0;
$volhash->{$volid}->{replicate} = 1 if $replicate;
+ $volhash->{$volid}->{shared} //= 0;
+ $volhash->{$volid}->{shared} = 1 if $shared;
+
$volhash->{$volid}->{referenced_in_config} //= 0;
$volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
foreach_drive($conf, sub {
my ($ds, $drive) = @_;
- $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, undef);
+ $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, undef);
});
foreach my $snapname (keys %{$conf->{snapshots}}) {
$test_volid->($snap->{vmstate}, 0, 1, $snapname);
foreach_drive($snap, sub {
my ($ds, $drive) = @_;
- $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $snapname);
+ $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, $snapname);
});
}
} elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
- #qemu 2.3 segfault on drive_del with virtioscsi + iothread
- my $device = parse_drive($deviceid, $conf->{$deviceid});
- die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread};
-
qemu_devicedel($vmid, $deviceid);
qemu_drivedel($vmid, $deviceid);
qemu_deletescsihw($conf, $vmid, $deviceid);
my $format;
$jobs->{"drive-$drive"} = {};
- if ($dst_volid =~ /^nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+):exportname=(\S+)/) {
- my $server = $1;
- my $port = $2;
- my $exportname = $3;
-
+ if ($dst_volid =~ /^nbd:/) {
+ $qemu_target = $dst_volid;
$format = "nbd";
- my $unixsocket = "/run/qemu-server/$vmid.mirror-drive-$drive";
- $qemu_target = "nbd+unix:///$exportname?socket=$unixsocket";
- my $cmd = ['socat', '-T30', "UNIX-LISTEN:$unixsocket,fork", "TCP:$server:$2,connect-timeout=5"];
-
- my $pid = fork();
- if (!defined($pid)) {
- die "forking socat tunnel failed\n";
- } elsif ($pid == 0) {
- exec(@$cmd);
- warn "exec failed: $!\n";
- POSIX::_exit(-1);
- }
- $jobs->{"drive-$drive"}->{pid} = $pid;
-
- my $timeout = 0;
- while (!-S $unixsocket) {
- die "nbd connection helper timed out\n"
- if $timeout++ > 5;
- sleep 1;
- }
} else {
my $storecfg = PVE::Storage::config();
my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
}else {
print "$job: Completed successfully.\n";
$jobs->{$job}->{complete} = 1;
- eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
}
}
}
if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
print "$job: Done.\n";
- eval { qemu_blockjobs_finish_tunnel($vmid, $job, $jobs->{$job}->{pid}) } ;
delete $jobs->{$job};
}
}
}
}
-sub qemu_blockjobs_finish_tunnel {
- my ($vmid, $job, $cpid) = @_;
-
- return if !$cpid;
-
- for (my $i = 1; $i < 20; $i++) {
- my $waitpid = waitpid($cpid, WNOHANG);
- last if (defined($waitpid) && ($waitpid == $cpid));
-
- if ($i == 10) {
- kill(15, $cpid);
- } elsif ($i >= 15) {
- kill(9, $cpid);
- }
- sleep (1);
- }
- unlink "/run/qemu-server/$vmid.mirror-$job";
-}
-
sub clone_disk {
my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
$newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;