]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
pci: to not capture first group in PCIRE
[qemu-server.git] / PVE / QemuServer.pm
CommitLineData
1e3baf05
DM
1package PVE::QemuServer;
2
3use strict;
990fc5e2 4use warnings;
3ff84d6f 5
5da072fb
TL
6use Cwd 'abs_path';
7use Digest::SHA;
8use Fcntl ':flock';
9use Fcntl;
1e3baf05 10use File::Basename;
5da072fb 11use File::Copy qw(copy);
1e3baf05
DM
12use File::Path;
13use File::stat;
14use Getopt::Long;
5da072fb
TL
15use IO::Dir;
16use IO::File;
17use IO::Handle;
18use IO::Select;
19use IO::Socket::UNIX;
1e3baf05 20use IPC::Open3;
c971c4f2 21use JSON;
1f30ac3a 22use MIME::Base64;
5da072fb
TL
23use POSIX;
24use Storable qw(dclone);
25use Time::HiRes qw(gettimeofday);
26use URI::Escape;
425441e6 27use UUID;
5da072fb 28
82841214 29use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file);
5b65b00d 30use PVE::CGroup;
48cf040f 31use PVE::DataCenterConfig;
5da072fb 32use PVE::Exception qw(raise raise_param_exc);
3b56383b 33use PVE::Format qw(render_duration render_bytes);
81d6e4e1 34use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
1e3baf05 35use PVE::INotify;
4df98f2f 36use PVE::JSONSchema qw(get_standard_option parse_property_string);
1e3baf05 37use PVE::ProcFSTools;
fbec3f89 38use PVE::PBSClient;
91bd6c90 39use PVE::RPCEnvironment;
5da072fb 40use PVE::Storage;
b71351a7 41use PVE::SysFSTools;
d04d6af1 42use PVE::Systemd;
82841214 43use PVE::Tools qw(run_command file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
5da072fb
TL
44
45use PVE::QMPClient;
46use PVE::QemuConfig;
2f18c84d 47use PVE::QemuServer::Helpers qw(min_version config_aware_timeout);
5da072fb 48use PVE::QemuServer::Cloudinit;
5b65b00d 49use PVE::QemuServer::CGroup;
d786a274 50use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
75748d44 51use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom drive_is_read_only parse_drive print_drive);
2ea5fb7e 52use PVE::QemuServer::Machine;
5da072fb 53use PVE::QemuServer::Memory;
0a13e08e 54use PVE::QemuServer::Monitor qw(mon_cmd);
74c17b7a 55use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
5da072fb 56use PVE::QemuServer::USB qw(parse_usb_device);
1e3baf05 57
28e129cc
AD
58my $have_sdn;
59eval {
60 require PVE::Network::SDN::Zones;
61 $have_sdn = 1;
62};
63
102cf9d8 64my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
96ed3574
WB
65my $OVMF = {
66 x86_64 => [
67 "$EDK2_FW_BASE/OVMF_CODE.fd",
68 "$EDK2_FW_BASE/OVMF_VARS.fd"
69 ],
70 aarch64 => [
71 "$EDK2_FW_BASE/AAVMF_CODE.fd",
72 "$EDK2_FW_BASE/AAVMF_VARS.fd"
73 ],
74};
2ddc0a5c 75
7f0b5beb 76my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
1e3baf05 77
19672434 78# Note about locking: we use flock on the config file protect
1e3baf05
DM
79# against concurent actions.
80# Aditionaly, we have a 'lock' setting in the config file. This
22c377f0 81# can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
1e3baf05
DM
82# allowed when such lock is set. But you can ignore this kind of
83# lock with the --skiplock flag.
84
97d62eb7 85cfs_register_file('/qemu-server/',
1858638f
DM
86 \&parse_vm_config,
87 \&write_vm_config);
1e3baf05 88
3ea94c60
DM
89PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
90 description => "Some command save/restore state from this location.",
91 type => 'string',
92 maxLength => 128,
93 optional => 1,
94});
95
c6737ef1
DC
96PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
97 description => "Specifies the Qemu machine type.",
98 type => 'string',
9471e48b 99 pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
c6737ef1
DC
100 maxLength => 40,
101 optional => 1,
102});
103
bf8fc5a3
FG
104
105sub map_storage {
106 my ($map, $source) = @_;
107
108 return $source if !defined($map);
109
110 return $map->{entries}->{$source}
b6d9b54b 111 if $map->{entries} && defined($map->{entries}->{$source});
bf8fc5a3
FG
112
113 return $map->{default} if $map->{default};
114
115 # identity (fallback)
116 return $source;
117}
118
119PVE::JSONSchema::register_standard_option('pve-targetstorage', {
120 description => "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
121 type => 'string',
122 format => 'storagepair-list',
123 optional => 1,
124});
125
1e3baf05
DM
126#no warnings 'redefine';
127
38277afc
TL
128my $nodename_cache;
129sub nodename {
130 $nodename_cache //= PVE::INotify::nodename();
131 return $nodename_cache;
132}
1e3baf05 133
ec3582b5
WB
134my $watchdog_fmt = {
135 model => {
136 default_key => 1,
137 type => 'string',
138 enum => [qw(i6300esb ib700)],
139 description => "Watchdog type to emulate.",
140 default => 'i6300esb',
141 optional => 1,
142 },
143 action => {
144 type => 'string',
145 enum => [qw(reset shutdown poweroff pause debug none)],
146 description => "The action to perform if after activation the guest fails to poll the watchdog in time.",
147 optional => 1,
148 },
149};
150PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
151
9d66b397
SI
152my $agent_fmt = {
153 enabled => {
154 description => "Enable/disable Qemu GuestAgent.",
155 type => 'boolean',
156 default => 0,
157 default_key => 1,
158 },
159 fstrim_cloned_disks => {
0a4aff09 160 description => "Run fstrim after moving a disk or migrating the VM.",
9d66b397
SI
161 type => 'boolean',
162 optional => 1,
163 default => 0
164 },
48657158
MD
165 type => {
166 description => "Select the agent type",
167 type => 'string',
168 default => 'virtio',
169 optional => 1,
170 enum => [qw(virtio isa)],
171 },
9d66b397
SI
172};
173
55655ebc
DC
174my $vga_fmt = {
175 type => {
176 description => "Select the VGA type.",
177 type => 'string',
178 default => 'std',
179 optional => 1,
180 default_key => 1,
7c954c42 181 enum => [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
55655ebc
DC
182 },
183 memory => {
184 description => "Sets the VGA memory (in MiB). Has no effect with serial display.",
185 type => 'integer',
186 optional => 1,
187 minimum => 4,
188 maximum => 512,
189 },
190};
191
6dbcb073
DC
192my $ivshmem_fmt = {
193 size => {
194 type => 'integer',
195 minimum => 1,
196 description => "The size of the file in MB.",
197 },
198 name => {
199 type => 'string',
200 pattern => '[a-zA-Z0-9\-]+',
201 optional => 1,
202 format_description => 'string',
203 description => "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
204 },
205};
206
1448547f
AL
207my $audio_fmt = {
208 device => {
209 type => 'string',
210 enum => [qw(ich9-intel-hda intel-hda AC97)],
211 description => "Configure an audio device."
212 },
213 driver => {
214 type => 'string',
211785ee 215 enum => ['spice', 'none'],
1448547f
AL
216 default => 'spice',
217 optional => 1,
218 description => "Driver backend for the audio device."
219 },
220};
221
c4df18db
AL
222my $spice_enhancements_fmt = {
223 foldersharing => {
224 type => 'boolean',
225 optional => 1,
d282a24d 226 default => '0',
c4df18db
AL
227 description => "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
228 },
229 videostreaming => {
230 type => 'string',
231 enum => ['off', 'all', 'filter'],
d282a24d 232 default => 'off',
c4df18db
AL
233 optional => 1,
234 description => "Enable video streaming. Uses compression for detected video streams."
235 },
236};
237
2cf61f33
SR
238my $rng_fmt = {
239 source => {
240 type => 'string',
241 enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
242 default_key => 1,
243 description => "The file on the host to gather entropy from. In most"
244 . " cases /dev/urandom should be preferred over /dev/random"
245 . " to avoid entropy-starvation issues on the host. Using"
246 . " urandom does *not* decrease security in any meaningful"
247 . " way, as it's still seeded from real entropy, and the"
248 . " bytes provided will most likely be mixed with real"
249 . " entropy on the guest as well. /dev/hwrng can be used"
250 . " to pass through a hardware RNG from the host.",
251 },
252 max_bytes => {
253 type => 'integer',
254 description => "Maximum bytes of entropy injected into the guest every"
255 . " 'period' milliseconds. Prefer a lower value when using"
256 . " /dev/random as source. Use 0 to disable limiting"
257 . " (potentially dangerous!).",
258 optional => 1,
259
260 # default is 1 KiB/s, provides enough entropy to the guest to avoid
261 # boot-starvation issues (e.g. systemd etc...) while allowing no chance
262 # of overwhelming the host, provided we're reading from /dev/urandom
263 default => 1024,
264 },
265 period => {
266 type => 'integer',
267 description => "Every 'period' milliseconds the entropy-injection quota"
268 . " is reset, allowing the guest to retrieve another"
269 . " 'max_bytes' of entropy.",
270 optional => 1,
271 default => 1000,
272 },
273};
274
1e3baf05
DM
275my $confdesc = {
276 onboot => {
277 optional => 1,
278 type => 'boolean',
279 description => "Specifies whether a VM will be started during system bootup.",
280 default => 0,
281 },
282 autostart => {
283 optional => 1,
284 type => 'boolean',
285 description => "Automatic restart after crash (currently ignored).",
286 default => 0,
287 },
2ff09f52
DA
288 hotplug => {
289 optional => 1,
b3c2bdd1
DM
290 type => 'string', format => 'pve-hotplug-features',
291 description => "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
292 default => 'network,disk,usb',
2ff09f52 293 },
1e3baf05
DM
294 reboot => {
295 optional => 1,
296 type => 'boolean',
297 description => "Allow reboot. If set to '0' the VM exit on reboot.",
298 default => 1,
299 },
300 lock => {
301 optional => 1,
302 type => 'string',
303 description => "Lock/unlock the VM.",
159719e5 304 enum => [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
1e3baf05
DM
305 },
306 cpulimit => {
307 optional => 1,
c6f773b8 308 type => 'number',
52261945
DM
309 description => "Limit of CPU usage.",
310 verbose_description => "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
1e3baf05 311 minimum => 0,
c6f773b8 312 maximum => 128,
52261945 313 default => 0,
1e3baf05
DM
314 },
315 cpuunits => {
316 optional => 1,
317 type => 'integer',
67498860
TL
318 description => "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
319 verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler."
320 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
321 ." weights of all the other running VMs.",
237239bf
PA
322 minimum => 2,
323 maximum => 262144,
67498860 324 default => 'cgroup v1: 1024, cgroup v2: 100',
1e3baf05
DM
325 },
326 memory => {
327 optional => 1,
328 type => 'integer',
7878afeb 329 description => "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
1e3baf05
DM
330 minimum => 16,
331 default => 512,
332 },
13a48620
DA
333 balloon => {
334 optional => 1,
335 type => 'integer',
8b1accf7
DM
336 description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
337 minimum => 0,
338 },
339 shares => {
340 optional => 1,
341 type => 'integer',
82329cd5 342 description => "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
8b1accf7
DM
343 minimum => 0,
344 maximum => 50000,
345 default => 1000,
13a48620 346 },
1e3baf05
DM
347 keyboard => {
348 optional => 1,
349 type => 'string',
f889aa0f 350 description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
aea47dd6 351 "It should not be necessary to set it.",
e95fe75f 352 enum => PVE::Tools::kvmkeymaplist(),
aea47dd6 353 default => undef,
1e3baf05
DM
354 },
355 name => {
356 optional => 1,
7fabe17d 357 type => 'string', format => 'dns-name',
1e3baf05
DM
358 description => "Set a name for the VM. Only used on the configuration web interface.",
359 },
cdd20088
AD
360 scsihw => {
361 optional => 1,
362 type => 'string',
52261945 363 description => "SCSI controller model",
6731a4cf 364 enum => [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
cdd20088
AD
365 default => 'lsi',
366 },
1e3baf05
DM
367 description => {
368 optional => 1,
369 type => 'string',
a200af10
TL
370 description => "Description for the VM. Shown in the web-interface VM's summary."
371 ." This is saved as comment inside the configuration file.",
372 maxLength => 1024 * 8,
1e3baf05
DM
373 },
374 ostype => {
375 optional => 1,
376 type => 'string',
0cb9971e 377 enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
52261945
DM
378 description => "Specify guest operating system.",
379 verbose_description => <<EODESC,
380Specify guest operating system. This is used to enable special
381optimization/features for specific operating systems:
382
383[horizontal]
384other;; unspecified OS
385wxp;; Microsoft Windows XP
386w2k;; Microsoft Windows 2000
387w2k3;; Microsoft Windows 2003
388w2k8;; Microsoft Windows 2008
389wvista;; Microsoft Windows Vista
390win7;; Microsoft Windows 7
44c2a647 391win8;; Microsoft Windows 8/2012/2012r2
1f5828f2 392win10;; Microsoft Windows 10/2016/2019
52261945 393l24;; Linux 2.4 Kernel
a5269260 394l26;; Linux 2.6 - 5.X Kernel
52261945 395solaris;; Solaris/OpenSolaris/OpenIndiania kernel
1e3baf05
DM
396EODESC
397 },
398 boot => {
399 optional => 1,
2141a802
SR
400 type => 'string', format => 'pve-qm-boot',
401 description => "Specify guest boot order. Use with 'order=', usage with"
402 . " no key or 'legacy=' is deprecated.",
1e3baf05
DM
403 },
404 bootdisk => {
405 optional => 1,
406 type => 'string', format => 'pve-qm-bootdisk',
2141a802 407 description => "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
03e480fc 408 pattern => '(ide|sata|scsi|virtio)\d+',
1e3baf05
DM
409 },
410 smp => {
411 optional => 1,
412 type => 'integer',
413 description => "The number of CPUs. Please use option -sockets instead.",
414 minimum => 1,
415 default => 1,
416 },
417 sockets => {
418 optional => 1,
419 type => 'integer',
420 description => "The number of CPU sockets.",
421 minimum => 1,
422 default => 1,
423 },
424 cores => {
425 optional => 1,
426 type => 'integer',
427 description => "The number of cores per socket.",
428 minimum => 1,
429 default => 1,
430 },
8a010eae
AD
431 numa => {
432 optional => 1,
433 type => 'boolean',
1917695c 434 description => "Enable/disable NUMA.",
8a010eae
AD
435 default => 0,
436 },
7023f3ea
AD
437 hugepages => {
438 optional => 1,
439 type => 'string',
440 description => "Enable/disable hugepages memory.",
441 enum => [qw(any 2 1024)],
442 },
f36e9894
SR
443 keephugepages => {
444 optional => 1,
445 type => 'boolean',
446 default => 0,
4df98f2f
TL
447 description => "Use together with hugepages. If enabled, hugepages will not not be deleted"
448 ." after VM shutdown and can be used for subsequent starts.",
f36e9894 449 },
de9d1e55 450 vcpus => {
3bd18e48
AD
451 optional => 1,
452 type => 'integer',
de9d1e55 453 description => "Number of hotplugged vcpus.",
3bd18e48 454 minimum => 1,
de9d1e55 455 default => 0,
3bd18e48 456 },
1e3baf05
DM
457 acpi => {
458 optional => 1,
459 type => 'boolean',
460 description => "Enable/disable ACPI.",
461 default => 1,
462 },
bc84dcca 463 agent => {
ab6a046f 464 optional => 1,
9d66b397
SI
465 description => "Enable/disable Qemu GuestAgent and its properties.",
466 type => 'string',
467 format => $agent_fmt,
ab6a046f 468 },
1e3baf05
DM
469 kvm => {
470 optional => 1,
471 type => 'boolean',
472 description => "Enable/disable KVM hardware virtualization.",
473 default => 1,
474 },
475 tdf => {
476 optional => 1,
477 type => 'boolean',
8c559505
DM
478 description => "Enable/disable time drift fix.",
479 default => 0,
1e3baf05 480 },
19672434 481 localtime => {
1e3baf05
DM
482 optional => 1,
483 type => 'boolean',
4df98f2f
TL
484 description => "Set the real time clock to local time. This is enabled by default if ostype"
485 ." indicates a Microsoft OS.",
1e3baf05
DM
486 },
487 freeze => {
488 optional => 1,
489 type => 'boolean',
490 description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
491 },
492 vga => {
493 optional => 1,
55655ebc
DC
494 type => 'string', format => $vga_fmt,
495 description => "Configure the VGA hardware.",
4df98f2f
TL
496 verbose_description => "Configure the VGA Hardware. If you want to use high resolution"
497 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
498 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
499 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
500 ." display server. For win* OS you can select how many independent displays you want,"
501 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
502 ." using a serial device as terminal.",
1e3baf05 503 },
0ea9541d
DM
504 watchdog => {
505 optional => 1,
506 type => 'string', format => 'pve-qm-watchdog',
52261945 507 description => "Create a virtual hardware watchdog device.",
4df98f2f
TL
508 verbose_description => "Create a virtual hardware watchdog device. Once enabled (by a guest"
509 ." action), the watchdog must be periodically polled by an agent inside the guest or"
510 ." else the watchdog will reset the guest (or execute the respective action specified)",
0ea9541d 511 },
1e3baf05
DM
512 startdate => {
513 optional => 1,
19672434 514 type => 'string',
1e3baf05 515 typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
4df98f2f
TL
516 description => "Set the initial date of the real time clock. Valid format for date are:"
517 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
1e3baf05
DM
518 pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
519 default => 'now',
520 },
43574f73 521 startup => get_standard_option('pve-startup-order'),
68eda3ab
AD
522 template => {
523 optional => 1,
524 type => 'boolean',
525 description => "Enable/disable Template.",
526 default => 0,
527 },
1e3baf05
DM
528 args => {
529 optional => 1,
530 type => 'string',
52261945
DM
531 description => "Arbitrary arguments passed to kvm.",
532 verbose_description => <<EODESCR,
c7a8aad6 533Arbitrary arguments passed to kvm, for example:
1e3baf05
DM
534
535args: -no-reboot -no-hpet
c7a8aad6
FG
536
537NOTE: this option is for experts only.
1e3baf05
DM
538EODESCR
539 },
540 tablet => {
541 optional => 1,
542 type => 'boolean',
543 default => 1,
52261945 544 description => "Enable/disable the USB tablet device.",
4df98f2f
TL
545 verbose_description => "Enable/disable the USB tablet device. This device is usually needed"
546 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
547 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
548 ." may consider disabling this to save some context switches. This is turned off by"
549 ." default if you use spice (`qm set <vmid> --vga qxl`).",
1e3baf05
DM
550 },
551 migrate_speed => {
552 optional => 1,
553 type => 'integer',
554 description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
555 minimum => 0,
556 default => 0,
557 },
558 migrate_downtime => {
559 optional => 1,
04432191 560 type => 'number',
1e3baf05
DM
561 description => "Set maximum tolerated downtime (in seconds) for migrations.",
562 minimum => 0,
04432191 563 default => 0.1,
1e3baf05
DM
564 },
565 cdrom => {
566 optional => 1,
b799312f 567 type => 'string', format => 'pve-qm-ide',
8485b9ba 568 typetext => '<volume>',
1e3baf05
DM
569 description => "This is an alias for option -ide2",
570 },
571 cpu => {
572 optional => 1,
573 description => "Emulated CPU type.",
574 type => 'string',
5d008ad3 575 format => 'pve-vm-cpu-conf',
1e3baf05 576 },
b7ba6b79
DM
577 parent => get_standard_option('pve-snapshot-name', {
578 optional => 1,
579 description => "Parent snapshot name. This is used internally, and should not be modified.",
580 }),
982c7f12
DM
581 snaptime => {
582 optional => 1,
583 description => "Timestamp for snapshots.",
584 type => 'integer',
585 minimum => 0,
586 },
18bfb361
DM
587 vmstate => {
588 optional => 1,
589 type => 'string', format => 'pve-volume-id',
4df98f2f
TL
590 description => "Reference to a volume which stores the VM state. This is used internally"
591 ." for snapshots.",
18bfb361 592 },
253624c7
FG
593 vmstatestorage => get_standard_option('pve-storage-id', {
594 description => "Default storage for VM state volumes/files.",
595 optional => 1,
596 }),
c6737ef1 597 runningmachine => get_standard_option('pve-qemu-machine', {
4df98f2f
TL
598 description => "Specifies the QEMU machine type of the running vm. This is used internally"
599 ." for snapshots.",
c6737ef1 600 }),
ea1c2110 601 runningcpu => {
4df98f2f
TL
602 description => "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
603 ." internally for snapshots.",
ea1c2110
SR
604 optional => 1,
605 type => 'string',
606 pattern => $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re,
607 format_description => 'QEMU -cpu parameter'
608 },
c6737ef1 609 machine => get_standard_option('pve-qemu-machine'),
d731ecbe
WB
610 arch => {
611 description => "Virtual processor architecture. Defaults to the host.",
612 optional => 1,
613 type => 'string',
614 enum => [qw(x86_64 aarch64)],
615 },
2796e7d5
DM
616 smbios1 => {
617 description => "Specify SMBIOS type 1 fields.",
618 type => 'string', format => 'pve-qm-smbios1',
5d004b00 619 maxLength => 512,
2796e7d5
DM
620 optional => 1,
621 },
cb0e4540
AG
622 protection => {
623 optional => 1,
624 type => 'boolean',
4df98f2f
TL
625 description => "Sets the protection flag of the VM. This will disable the remove VM and"
626 ." remove disk operations.",
cb0e4540
AG
627 default => 0,
628 },
3edb45e7 629 bios => {
a783c78e 630 optional => 1,
3edb45e7
DM
631 type => 'string',
632 enum => [ qw(seabios ovmf) ],
633 description => "Select BIOS implementation.",
634 default => 'seabios',
a783c78e 635 },
6ee499ff
DC
636 vmgenid => {
637 type => 'string',
638 pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
639 format_description => 'UUID',
4df98f2f
TL
640 description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
641 ." to disable explicitly.",
642 verbose_description => "The VM generation ID (vmgenid) device exposes a 128-bit integer"
643 ." value identifier to the guest OS. This allows to notify the guest operating system"
644 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
645 ." execution or creation from a template). The guest operating system notices the"
646 ." change, and is then able to react as appropriate by marking its copies of"
647 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
648 ."Note that auto-creation only works when done through API/CLI create or update methods"
649 .", but not when manually editing the config file.",
f7ed64e7 650 default => "1 (autogenerated)",
6ee499ff
DC
651 optional => 1,
652 },
9e784b11
DC
653 hookscript => {
654 type => 'string',
655 format => 'pve-volume-id',
656 optional => 1,
657 description => "Script that will be executed during various steps in the vms lifetime.",
658 },
6dbcb073
DC
659 ivshmem => {
660 type => 'string',
661 format => $ivshmem_fmt,
4df98f2f
TL
662 description => "Inter-VM shared memory. Useful for direct communication between VMs, or to"
663 ." the host.",
6dbcb073 664 optional => 1,
2e7b5925
AL
665 },
666 audio0 => {
667 type => 'string',
1448547f 668 format => $audio_fmt,
194b65f1 669 description => "Configure a audio device, useful in combination with QXL/Spice.",
2e7b5925
AL
670 optional => 1
671 },
c4df18db
AL
672 spice_enhancements => {
673 type => 'string',
674 format => $spice_enhancements_fmt,
675 description => "Configure additional enhancements for SPICE.",
676 optional => 1
677 },
b8e7068a
DC
678 tags => {
679 type => 'string', format => 'pve-tag-list',
680 description => 'Tags of the VM. This is only meta information.',
681 optional => 1,
682 },
2cf61f33
SR
683 rng0 => {
684 type => 'string',
685 format => $rng_fmt,
686 description => "Configure a VirtIO-based Random Number Generator.",
687 optional => 1,
688 },
9ed7a77c
WB
689};
690
cb702ebe
DL
691my $cicustom_fmt = {
692 meta => {
693 type => 'string',
694 optional => 1,
4df98f2f
TL
695 description => 'Specify a custom file containing all meta data passed to the VM via"
696 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
cb702ebe
DL
697 format => 'pve-volume-id',
698 format_description => 'volume',
699 },
700 network => {
701 type => 'string',
702 optional => 1,
4df98f2f
TL
703 description => 'Specify a custom file containing all network data passed to the VM via'
704 .' cloud-init.',
cb702ebe
DL
705 format => 'pve-volume-id',
706 format_description => 'volume',
707 },
708 user => {
709 type => 'string',
710 optional => 1,
4df98f2f
TL
711 description => 'Specify a custom file containing all user data passed to the VM via'
712 .' cloud-init.',
cb702ebe
DL
713 format => 'pve-volume-id',
714 format_description => 'volume',
715 },
716};
717PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
718
9ed7a77c 719my $confdesc_cloudinit = {
41cd94a0
WB
720 citype => {
721 optional => 1,
722 type => 'string',
4df98f2f
TL
723 description => 'Specifies the cloud-init configuration format. The default depends on the'
724 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
725 .' and `configdrive2` for windows.',
545eec65 726 enum => ['configdrive2', 'nocloud', 'opennebula'],
41cd94a0 727 },
7b42f951
WB
728 ciuser => {
729 optional => 1,
730 type => 'string',
4df98f2f
TL
731 description => "cloud-init: User name to change ssh keys and password for instead of the"
732 ." image's configured default user.",
7b42f951
WB
733 },
734 cipassword => {
735 optional => 1,
736 type => 'string',
4df98f2f
TL
737 description => 'cloud-init: Password to assign the user. Using this is generally not'
738 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
739 .' support hashed passwords.',
7b42f951 740 },
cb702ebe
DL
741 cicustom => {
742 optional => 1,
743 type => 'string',
4df98f2f
TL
744 description => 'cloud-init: Specify custom files to replace the automatically generated'
745 .' ones at start.',
cb702ebe
DL
746 format => 'pve-qm-cicustom',
747 },
0c9a7596
AD
748 searchdomain => {
749 optional => 1,
750 type => 'string',
4df98f2f
TL
751 description => "cloud-init: Sets DNS search domains for a container. Create will'
752 .' automatically use the setting from the host if neither searchdomain nor nameserver'
753 .' are set.",
0c9a7596
AD
754 },
755 nameserver => {
756 optional => 1,
757 type => 'string', format => 'address-list',
4df98f2f
TL
758 description => "cloud-init: Sets DNS server IP address for a container. Create will'
759 .' automatically use the setting from the host if neither searchdomain nor nameserver'
760 .' are set.",
0c9a7596
AD
761 },
762 sshkeys => {
763 optional => 1,
764 type => 'string',
765 format => 'urlencoded',
1d1c4e1c 766 description => "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
0c9a7596 767 },
1e3baf05
DM
768};
769
770# what about other qemu settings ?
771#cpu => 'string',
772#machine => 'string',
773#fda => 'file',
774#fdb => 'file',
775#mtdblock => 'file',
776#sd => 'file',
777#pflash => 'file',
778#snapshot => 'bool',
779#bootp => 'file',
780##tftp => 'dir',
781##smb => 'dir',
782#kernel => 'file',
783#append => 'string',
784#initrd => 'file',
785##soundhw => 'string',
786
787while (my ($k, $v) = each %$confdesc) {
788 PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
789}
790
1e3baf05 791my $MAX_USB_DEVICES = 5;
5bdcf937 792my $MAX_NETS = 32;
bae179aa 793my $MAX_SERIAL_PORTS = 4;
1989a89c 794my $MAX_PARALLEL_PORTS = 3;
2ed5d572
AD
795my $MAX_NUMA = 8;
796
ffc0d8c7
WB
797my $numa_fmt = {
798 cpus => {
799 type => "string",
800 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 801 description => "CPUs accessing this NUMA node.",
ffc0d8c7
WB
802 format_description => "id[-id];...",
803 },
804 memory => {
805 type => "number",
52261945 806 description => "Amount of memory this NUMA node provides.",
ffc0d8c7
WB
807 optional => 1,
808 },
809 hostnodes => {
810 type => "string",
811 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 812 description => "Host NUMA nodes to use.",
ffc0d8c7
WB
813 format_description => "id[-id];...",
814 optional => 1,
815 },
816 policy => {
817 type => 'string',
818 enum => [qw(preferred bind interleave)],
52261945 819 description => "NUMA allocation policy.",
ffc0d8c7
WB
820 optional => 1,
821 },
822};
823PVE::JSONSchema::register_format('pve-qm-numanode', $numa_fmt);
2ed5d572
AD
824my $numadesc = {
825 optional => 1,
ffc0d8c7 826 type => 'string', format => $numa_fmt,
52261945 827 description => "NUMA topology.",
2ed5d572
AD
828};
829PVE::JSONSchema::register_standard_option("pve-qm-numanode", $numadesc);
830
831for (my $i = 0; $i < $MAX_NUMA; $i++) {
832 $confdesc->{"numa$i"} = $numadesc;
833}
1e3baf05 834
f7bc17ca
TL
835my $nic_model_list = [
836 'e1000',
837 'e1000-82540em',
838 'e1000-82544gc',
839 'e1000-82545em',
e83dd50a 840 'e1000e',
f7bc17ca
TL
841 'i82551',
842 'i82557b',
843 'i82559er',
844 'ne2k_isa',
845 'ne2k_pci',
846 'pcnet',
847 'rtl8139',
848 'virtio',
849 'vmxnet3',
850];
6b64503e 851my $nic_model_list_txt = join(' ', sort @$nic_model_list);
1e3baf05 852
52261945
DM
853my $net_fmt_bridge_descr = <<__EOD__;
854Bridge to attach the network device to. The Proxmox VE standard bridge
855is called 'vmbr0'.
856
857If you do not specify a bridge, we create a kvm user (NATed) network
858device, which provides DHCP and DNS services. The following addresses
859are used:
860
861 10.0.2.2 Gateway
862 10.0.2.3 DNS Server
863 10.0.2.4 SMB Server
864
865The DHCP server assign addresses to the guest starting from 10.0.2.15.
866__EOD__
867
cd9c34d1 868my $net_fmt = {
399d96db 869 macaddr => get_standard_option('mac-addr', {
4df98f2f
TL
870 description => "MAC address. That address must be unique withing your network. This is"
871 ." automatically generated if not specified.",
399d96db 872 }),
7f694a71
DM
873 model => {
874 type => 'string',
4df98f2f
TL
875 description => "Network Card Model. The 'virtio' model provides the best performance with"
876 ." very low CPU overhead. If your guest does not support this driver, it is usually"
877 ." best to use 'e1000'.",
7f694a71
DM
878 enum => $nic_model_list,
879 default_key => 1,
880 },
881 (map { $_ => { keyAlias => 'model', alias => 'macaddr' }} @$nic_model_list),
cd9c34d1
WB
882 bridge => {
883 type => 'string',
52261945 884 description => $net_fmt_bridge_descr,
cd9c34d1 885 format_description => 'bridge',
e1cfa02e 886 pattern => '[-_.\w\d]+',
cd9c34d1
WB
887 optional => 1,
888 },
889 queues => {
890 type => 'integer',
891 minimum => 0, maximum => 16,
892 description => 'Number of packet queues to be used on the device.',
cd9c34d1
WB
893 optional => 1,
894 },
895 rate => {
896 type => 'number',
897 minimum => 0,
52261945 898 description => "Rate limit in mbps (megabytes per second) as floating point number.",
cd9c34d1
WB
899 optional => 1,
900 },
901 tag => {
902 type => 'integer',
9f41a659 903 minimum => 1, maximum => 4094,
cd9c34d1 904 description => 'VLAN tag to apply to packets on this interface.',
cd9c34d1
WB
905 optional => 1,
906 },
907 trunks => {
908 type => 'string',
909 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
910 description => 'VLAN trunks to pass through this interface.',
7f694a71 911 format_description => 'vlanid[;vlanid...]',
cd9c34d1
WB
912 optional => 1,
913 },
914 firewall => {
915 type => 'boolean',
916 description => 'Whether this interface should be protected by the firewall.',
cd9c34d1
WB
917 optional => 1,
918 },
919 link_down => {
920 type => 'boolean',
52261945 921 description => 'Whether this interface should be disconnected (like pulling the plug).',
cd9c34d1
WB
922 optional => 1,
923 },
61a14cde
AD
924 mtu => {
925 type => 'integer',
926 minimum => 1, maximum => 65520,
0530177b 927 description => "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
61a14cde
AD
928 optional => 1,
929 },
cd9c34d1 930};
52261945 931
1e3baf05
DM
932my $netdesc = {
933 optional => 1,
7f694a71 934 type => 'string', format => $net_fmt,
52261945 935 description => "Specify network devices.",
1e3baf05 936};
52261945 937
1e3baf05
DM
938PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
939
0c9a7596
AD
940my $ipconfig_fmt = {
941 ip => {
942 type => 'string',
943 format => 'pve-ipv4-config',
944 format_description => 'IPv4Format/CIDR',
945 description => 'IPv4 address in CIDR format.',
946 optional => 1,
947 default => 'dhcp',
948 },
949 gw => {
950 type => 'string',
951 format => 'ipv4',
952 format_description => 'GatewayIPv4',
953 description => 'Default gateway for IPv4 traffic.',
954 optional => 1,
955 requires => 'ip',
956 },
957 ip6 => {
958 type => 'string',
959 format => 'pve-ipv6-config',
960 format_description => 'IPv6Format/CIDR',
961 description => 'IPv6 address in CIDR format.',
962 optional => 1,
963 default => 'dhcp',
964 },
965 gw6 => {
966 type => 'string',
967 format => 'ipv6',
968 format_description => 'GatewayIPv6',
969 description => 'Default gateway for IPv6 traffic.',
970 optional => 1,
971 requires => 'ip6',
972 },
973};
974PVE::JSONSchema::register_format('pve-qm-ipconfig', $ipconfig_fmt);
975my $ipconfigdesc = {
976 optional => 1,
977 type => 'string', format => 'pve-qm-ipconfig',
978 description => <<'EODESCR',
979cloud-init: Specify IP addresses and gateways for the corresponding interface.
980
981IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
982
4df98f2f
TL
983The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
984gateway should be provided.
988be8d0
ML
985For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
986cloud-init 19.4 or newer.
0c9a7596 987
4df98f2f
TL
988If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
989dhcp on IPv4.
0c9a7596
AD
990EODESCR
991};
992PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
993
1e3baf05
DM
994for (my $i = 0; $i < $MAX_NETS; $i++) {
995 $confdesc->{"net$i"} = $netdesc;
9ed7a77c
WB
996 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
997}
998
999foreach my $key (keys %$confdesc_cloudinit) {
1000 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1e3baf05
DM
1001}
1002
ffa42b86
DC
1003PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
1004sub verify_volume_id_or_qm_path {
822c8a07
WB
1005 my ($volid, $noerr) = @_;
1006
ffa42b86
DC
1007 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m|^/|) {
1008 return $volid;
1009 }
1010
1011 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
822c8a07
WB
1012 $volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
1013 if ($@) {
d1c1af4b 1014 return if $noerr;
822c8a07
WB
1015 die $@;
1016 }
1017 return $volid;
1018}
1019
ff6ffe20 1020my $usb_fmt = {
a6b9aee4
DC
1021 host => {
1022 default_key => 1,
1023 type => 'string', format => 'pve-qm-usb-device',
1024 format_description => 'HOSTUSBDEVICE|spice',
52261945
DM
1025 description => <<EODESCR,
1026The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1027
1028 'bus-port(.port)*' (decimal numbers) or
1029 'vendor_id:product_id' (hexadeciaml numbers) or
1030 'spice'
1031
1032You can use the 'lsusb -t' command to list existing usb devices.
1033
4df98f2f
TL
1034NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1035machines - use with special care.
52261945
DM
1036
1037The value 'spice' can be used to add a usb redirection devices for spice.
1038EODESCR
a6b9aee4
DC
1039 },
1040 usb3 => {
1041 optional => 1,
1042 type => 'boolean',
97ef5356 1043 description => "Specifies whether if given host option is a USB3 device or port.",
52261945 1044 default => 0,
a6b9aee4
DC
1045 },
1046};
1047
1e3baf05
DM
1048my $usbdesc = {
1049 optional => 1,
ff6ffe20 1050 type => 'string', format => $usb_fmt,
52261945 1051 description => "Configure an USB device (n is 0 to 4).",
1e3baf05
DM
1052};
1053PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
1054
bae179aa
DA
1055my $serialdesc = {
1056 optional => 1,
ca0cef26 1057 type => 'string',
1b0b51ed 1058 pattern => '(/dev/.+|socket)',
52261945
DM
1059 description => "Create a serial device inside the VM (n is 0 to 3)",
1060 verbose_description => <<EODESCR,
52261945
DM
1061Create a serial device inside the VM (n is 0 to 3), and pass through a
1062host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1063host side (use 'qm terminal' to open a terminal connection).
bae179aa 1064
4df98f2f
TL
1065NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1066use with special care.
bae179aa 1067
52261945 1068CAUTION: Experimental! User reported problems with this option.
bae179aa
DA
1069EODESCR
1070};
bae179aa 1071
1989a89c
DA
1072my $paralleldesc= {
1073 optional => 1,
ca0cef26 1074 type => 'string',
9ecc8431 1075 pattern => '/dev/parport\d+|/dev/usb/lp\d+',
52261945
DM
1076 description => "Map host parallel devices (n is 0 to 2).",
1077 verbose_description => <<EODESCR,
19672434 1078Map host parallel devices (n is 0 to 2).
1989a89c 1079
4df98f2f
TL
1080NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1081machines - use with special care.
1989a89c 1082
52261945 1083CAUTION: Experimental! User reported problems with this option.
1989a89c
DA
1084EODESCR
1085};
1989a89c
DA
1086
1087for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1088 $confdesc->{"parallel$i"} = $paralleldesc;
1089}
1090
bae179aa
DA
1091for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1092 $confdesc->{"serial$i"} = $serialdesc;
1093}
1094
74c17b7a
SR
1095for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
1096 $confdesc->{"hostpci$i"} = $PVE::QemuServer::PCI::hostpcidesc;
040b06b7 1097}
1e3baf05 1098
e0fd2b2f
FE
1099for my $key (keys %{$PVE::QemuServer::Drive::drivedesc_hash}) {
1100 $confdesc->{$key} = $PVE::QemuServer::Drive::drivedesc_hash->{$key};
cdb0931f
DA
1101}
1102
1e3baf05
DM
1103for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1104 $confdesc->{"usb$i"} = $usbdesc;
1105}
1106
5cfa9f5f
SR
1107my $boot_fmt = {
1108 legacy => {
1109 optional => 1,
1110 default_key => 1,
1111 type => 'string',
1112 description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1113 . " Deprecated, use 'order=' instead.",
1114 pattern => '[acdn]{1,4}',
1115 format_description => "[acdn]{1,4}",
1116
1117 # note: this is also the fallback if boot: is not given at all
1118 default => 'cdn',
1119 },
1120 order => {
1121 optional => 1,
1122 type => 'string',
1123 format => 'pve-qm-bootdev-list',
1124 format_description => "device[;device...]",
1125 description => <<EODESC,
1126The guest will attempt to boot from devices in the order they appear here.
1127
1128Disks, optical drives and passed-through storage USB devices will be directly
1129booted from, NICs will load PXE, and PCIe devices will either behave like disks
1130(e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1131
1132Note that only devices in this list will be marked as bootable and thus loaded
1133by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1134(e.g. software-raid), you need to specify all of them here.
1135
1136Overrides the deprecated 'legacy=[acdn]*' value when given.
1137EODESC
1138 },
1139};
1140PVE::JSONSchema::register_format('pve-qm-boot', $boot_fmt);
1141
1142PVE::JSONSchema::register_format('pve-qm-bootdev', \&verify_bootdev);
1143sub verify_bootdev {
1144 my ($dev, $noerr) = @_;
1145
f9dde219
SR
1146 my $special = $dev =~ m/^efidisk/ || $dev =~ m/^tpmstate/;
1147 return $dev if PVE::QemuServer::Drive::is_valid_drivename($dev) && !$special;
5cfa9f5f
SR
1148
1149 my $check = sub {
1150 my ($base) = @_;
1151 return 0 if $dev !~ m/^$base\d+$/;
1152 return 0 if !$confdesc->{$dev};
1153 return 1;
1154 };
1155
1156 return $dev if $check->("net");
1157 return $dev if $check->("usb");
1158 return $dev if $check->("hostpci");
1159
d1c1af4b 1160 return if $noerr;
5cfa9f5f
SR
1161 die "invalid boot device '$dev'\n";
1162}
1163
1164sub print_bootorder {
1165 my ($devs) = @_;
4c27b18c 1166 return "" if !@$devs;
5cfa9f5f
SR
1167 my $data = { order => join(';', @$devs) };
1168 return PVE::JSONSchema::print_property_string($data, $boot_fmt);
1169}
1170
1e3baf05
DM
1171my $kvm_api_version = 0;
1172
1173sub kvm_version {
1e3baf05
DM
1174 return $kvm_api_version if $kvm_api_version;
1175
808a65b5 1176 open my $fh, '<', '/dev/kvm' or return;
1e3baf05 1177
646f2df4
WB
1178 # 0xae00 => KVM_GET_API_VERSION
1179 $kvm_api_version = ioctl($fh, 0xae00, 0);
808a65b5 1180 close($fh);
1e3baf05 1181
646f2df4 1182 return $kvm_api_version;
1e3baf05
DM
1183}
1184
1476b99f
DC
1185my $kvm_user_version = {};
1186my $kvm_mtime = {};
1e3baf05
DM
1187
1188sub kvm_user_version {
1476b99f 1189 my ($binary) = @_;
1e3baf05 1190
1476b99f
DC
1191 $binary //= get_command_for_arch(get_host_arch()); # get the native arch by default
1192 my $st = stat($binary);
1e3baf05 1193
1476b99f
DC
1194 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1195 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1196 $cachedmtime == $st->mtime;
1197
1198 $kvm_user_version->{$binary} = 'unknown';
1199 $kvm_mtime->{$binary} = $st->mtime;
1e3baf05 1200
09b11429
TL
1201 my $code = sub {
1202 my $line = shift;
1203 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1476b99f 1204 $kvm_user_version->{$binary} = $2;
09b11429
TL
1205 }
1206 };
19672434 1207
1476b99f 1208 eval { run_command([$binary, '--version'], outfunc => $code); };
09b11429 1209 warn $@ if $@;
1e3baf05 1210
1476b99f 1211 return $kvm_user_version->{$binary};
1e3baf05
DM
1212
1213}
4df98f2f
TL
1214my sub extract_version {
1215 my ($machine_type, $version) = @_;
1216 $version = kvm_user_version() if !defined($version);
1217 PVE::QemuServer::Machine::extract_version($machine_type, $version)
1218}
1e3baf05 1219
db70021b
TL
1220sub kernel_has_vhost_net {
1221 return -c '/dev/vhost-net';
1222}
1e3baf05 1223
1e3baf05
DM
1224sub option_exists {
1225 my $key = shift;
1226 return defined($confdesc->{$key});
19672434 1227}
1e3baf05 1228
1e3baf05 1229my $cdrom_path;
1e3baf05
DM
1230sub get_cdrom_path {
1231
1232 return $cdrom_path if $cdrom_path;
1233
1234 return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
1235 return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
1236 return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
1237}
1238
1239sub get_iso_path {
1240 my ($storecfg, $vmid, $cdrom) = @_;
1241
1242 if ($cdrom eq 'cdrom') {
1243 return get_cdrom_path();
1244 } elsif ($cdrom eq 'none') {
1245 return '';
1246 } elsif ($cdrom =~ m|^/|) {
1247 return $cdrom;
1248 } else {
6b64503e 1249 return PVE::Storage::path($storecfg, $cdrom);
1e3baf05
DM
1250 }
1251}
1252
1253# try to convert old style file names to volume IDs
1254sub filename_to_volume_id {
1255 my ($vmid, $file, $media) = @_;
1256
0c9a7596 1257 if (!($file eq 'none' || $file eq 'cdrom' ||
1e3baf05 1258 $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
19672434 1259
d1c1af4b 1260 return if $file =~ m|/|;
19672434 1261
1e3baf05
DM
1262 if ($media && $media eq 'cdrom') {
1263 $file = "local:iso/$file";
1264 } else {
1265 $file = "local:$vmid/$file";
1266 }
1267 }
1268
1269 return $file;
1270}
1271
1272sub verify_media_type {
1273 my ($opt, $vtype, $media) = @_;
1274
1275 return if !$media;
1276
1277 my $etype;
1278 if ($media eq 'disk') {
a125592c 1279 $etype = 'images';
1e3baf05
DM
1280 } elsif ($media eq 'cdrom') {
1281 $etype = 'iso';
1282 } else {
1283 die "internal error";
1284 }
1285
1286 return if ($vtype eq $etype);
19672434 1287
1e3baf05
DM
1288 raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
1289}
1290
1291sub cleanup_drive_path {
1292 my ($opt, $storecfg, $drive) = @_;
1293
1294 # try to convert filesystem paths to volume IDs
1295
1296 if (($drive->{file} !~ m/^(cdrom|none)$/) &&
1297 ($drive->{file} !~ m|^/dev/.+|) &&
1298 ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
19672434 1299 ($drive->{file} !~ m/^\d+$/)) {
1e3baf05 1300 my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
4df98f2f
TL
1301 raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1302 if !$vtype;
1e3baf05
DM
1303 $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
1304 verify_media_type($opt, $vtype, $drive->{media});
1305 $drive->{file} = $volid;
1306 }
1307
1308 $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
1309}
1310
b3c2bdd1
DM
1311sub parse_hotplug_features {
1312 my ($data) = @_;
1313
1314 my $res = {};
1315
1316 return $res if $data eq '0';
a1b7d579 1317
b3c2bdd1
DM
1318 $data = $confdesc->{hotplug}->{default} if $data eq '1';
1319
45827685 1320 foreach my $feature (PVE::Tools::split_list($data)) {
b3c2bdd1
DM
1321 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1322 $res->{$1} = 1;
1323 } else {
596a0a20 1324 die "invalid hotplug feature '$feature'\n";
b3c2bdd1
DM
1325 }
1326 }
1327 return $res;
1328}
1329
1330PVE::JSONSchema::register_format('pve-hotplug-features', \&pve_verify_hotplug_features);
1331sub pve_verify_hotplug_features {
1332 my ($value, $noerr) = @_;
1333
1334 return $value if parse_hotplug_features($value);
1335
d1c1af4b 1336 return if $noerr;
b3c2bdd1
DM
1337
1338 die "unable to parse hotplug option\n";
1339}
1340
28ef82d3
DM
1341sub scsi_inquiry {
1342 my($fh, $noerr) = @_;
1343
1344 my $SG_IO = 0x2285;
1345 my $SG_GET_VERSION_NUM = 0x2282;
1346
1347 my $versionbuf = "\x00" x 8;
1348 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1349 if (!$ret) {
1350 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
d1c1af4b 1351 return;
28ef82d3 1352 }
97d62eb7 1353 my $version = unpack("I", $versionbuf);
28ef82d3
DM
1354 if ($version < 30000) {
1355 die "scsi generic interface too old\n" if !$noerr;
d1c1af4b 1356 return;
28ef82d3 1357 }
97d62eb7 1358
28ef82d3
DM
1359 my $buf = "\x00" x 36;
1360 my $sensebuf = "\x00" x 8;
f334aa3e 1361 my $cmd = pack("C x3 C x1", 0x12, 36);
97d62eb7 1362
28ef82d3
DM
1363 # see /usr/include/scsi/sg.h
1364 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1365
97d62eb7
DM
1366 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1367 length($sensebuf), 0, length($buf), $buf,
28ef82d3
DM
1368 $cmd, $sensebuf, 6000);
1369
1370 $ret = ioctl($fh, $SG_IO, $packet);
1371 if (!$ret) {
1372 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
d1c1af4b 1373 return;
28ef82d3 1374 }
97d62eb7 1375
28ef82d3
DM
1376 my @res = unpack($sg_io_hdr_t, $packet);
1377 if ($res[17] || $res[18]) {
1378 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
d1c1af4b 1379 return;
28ef82d3
DM
1380 }
1381
1382 my $res = {};
09984754 1383 (my $byte0, my $byte1, $res->{vendor},
28ef82d3
DM
1384 $res->{product}, $res->{revision}) = unpack("C C x6 A8 A16 A4", $buf);
1385
09984754
DM
1386 $res->{removable} = $byte1 & 128 ? 1 : 0;
1387 $res->{type} = $byte0 & 31;
1388
28ef82d3
DM
1389 return $res;
1390}
1391
1392sub path_is_scsi {
1393 my ($path) = @_;
1394
d1c1af4b 1395 my $fh = IO::File->new("+<$path") || return;
28ef82d3
DM
1396 my $res = scsi_inquiry($fh, 1);
1397 close($fh);
1398
1399 return $res;
1400}
1401
db656e5f 1402sub print_tabletdevice_full {
d559309f 1403 my ($conf, $arch) = @_;
b467f79a 1404
3392d6ca 1405 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f
DM
1406
1407 # we use uhci for old VMs because tablet driver was buggy in older qemu
d559309f 1408 my $usbbus;
3392d6ca 1409 if (PVE::QemuServer::Machine::machine_type_is_q35($conf) || $arch eq 'aarch64') {
d559309f
WB
1410 $usbbus = 'ehci';
1411 } else {
1412 $usbbus = 'uhci';
1413 }
b467f79a 1414
db656e5f
DM
1415 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1416}
1417
d559309f
WB
1418sub print_keyboarddevice_full {
1419 my ($conf, $arch, $machine) = @_;
1420
d1c1af4b 1421 return if $arch ne 'aarch64';
d559309f
WB
1422
1423 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1424}
1425
a183df68
TL
1426my sub get_drive_id {
1427 my ($drive) = @_;
1428 return "$drive->{interface}$drive->{index}";
1429}
1430
ca916ecc 1431sub print_drivedevice_full {
d559309f 1432 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
ca916ecc
DA
1433
1434 my $device = '';
1435 my $maxdev = 0;
19672434 1436
a183df68 1437 my $drive_id = get_drive_id($drive);
ca916ecc 1438 if ($drive->{interface} eq 'virtio') {
4df98f2f
TL
1439 my $pciaddr = print_pci_addr("$drive_id", $bridges, $arch, $machine_type);
1440 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1441 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread};
2ed36a41 1442 } elsif ($drive->{interface} eq 'scsi') {
6731a4cf 1443
ee034f5c 1444 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
2ed36a41
DM
1445 my $unit = $drive->{index} % $maxdev;
1446 my $devicetype = 'hd';
69bcf246
WB
1447 my $path = '';
1448 if (drive_is_cdrom($drive)) {
1449 $devicetype = 'cd';
29b19529 1450 } else {
69bcf246
WB
1451 if ($drive->{file} =~ m|^/|) {
1452 $path = $drive->{file};
1453 if (my $info = path_is_scsi($path)) {
8e3c33ab 1454 if ($info->{type} == 0 && $drive->{scsiblock}) {
69bcf246
WB
1455 $devicetype = 'block';
1456 } elsif ($info->{type} == 1) { # tape
1457 $devicetype = 'generic';
1458 }
1459 }
1460 } else {
1461 $path = PVE::Storage::path($storecfg, $drive->{file});
1462 }
1463
a034e3d6 1464 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
4df98f2f 1465 my $version = extract_version($machine_type, kvm_user_version());
a034e3d6 1466 if ($path =~ m/^iscsi\:\/\// &&
2ea5fb7e 1467 !min_version($version, 4, 1)) {
69bcf246
WB
1468 $devicetype = 'generic';
1469 }
1470 }
1471
ef88eaaa 1472 if (!$conf->{scsihw} || $conf->{scsihw} =~ m/^lsi/ || $conf->{scsihw} eq 'pvscsi') {
4df98f2f 1473 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
69bcf246 1474 } else {
4df98f2f
TL
1475 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1476 .",lun=$drive->{index}";
69bcf246 1477 }
4df98f2f 1478 $device .= ",drive=drive-$drive_id,id=$drive_id";
cdd20088 1479
6c875f9f
NC
1480 if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1481 $device .= ",rotation_rate=1";
1482 }
e741c516 1483 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
6c875f9f
NC
1484
1485 } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') {
e0fd2b2f 1486 my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2;
2ed36a41
DM
1487 my $controller = int($drive->{index} / $maxdev);
1488 my $unit = $drive->{index} % $maxdev;
1489 my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
1490
6c875f9f
NC
1491 $device = "ide-$devicetype";
1492 if ($drive->{interface} eq 'ide') {
1493 $device .= ",bus=ide.$controller,unit=$unit";
1494 } else {
1495 $device .= ",bus=ahci$controller.$unit";
1496 }
4df98f2f 1497 $device .= ",drive=drive-$drive_id,id=$drive_id";
6c875f9f
NC
1498
1499 if ($devicetype eq 'hd') {
1500 if (my $model = $drive->{model}) {
1501 $model = URI::Escape::uri_unescape($model);
1502 $device .= ",model=$model";
1503 }
1504 if ($drive->{ssd}) {
1505 $device .= ",rotation_rate=1";
1506 }
0f2812c2 1507 }
e741c516 1508 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
2ed36a41
DM
1509 } elsif ($drive->{interface} eq 'usb') {
1510 die "implement me";
1511 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1512 } else {
1513 die "unsupported interface type";
ca916ecc
DA
1514 }
1515
3b408e82
DM
1516 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
1517
a70e7e6c
TL
1518 if (my $serial = $drive->{serial}) {
1519 $serial = URI::Escape::uri_unescape($serial);
1520 $device .= ",serial=$serial";
1521 }
1522
1523
ca916ecc
DA
1524 return $device;
1525}
1526
15b21acc 1527sub get_initiator_name {
46f58b5f 1528 my $initiator;
15b21acc 1529
d1c1af4b 1530 my $fh = IO::File->new('/etc/iscsi/initiatorname.iscsi') || return;
46f58b5f
DM
1531 while (defined(my $line = <$fh>)) {
1532 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
15b21acc
MR
1533 $initiator = $1;
1534 last;
1535 }
46f58b5f
DM
1536 $fh->close();
1537
15b21acc
MR
1538 return $initiator;
1539}
1540
776c5f50 1541sub print_drive_commandline_full {
6d5673c3 1542 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1e3baf05 1543
d81f0f09
DM
1544 my $path;
1545 my $volid = $drive->{file};
5921764c 1546 my $format = $drive->{format};
a183df68 1547 my $drive_id = get_drive_id($drive);
370b05e7 1548
0fe779a6
WB
1549 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
1550 my $scfg = $storeid ? PVE::Storage::storage_config($storecfg, $storeid) : undef;
1551
d81f0f09
DM
1552 if (drive_is_cdrom($drive)) {
1553 $path = get_iso_path($storecfg, $vmid, $volid);
a183df68 1554 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
d81f0f09 1555 } else {
d81f0f09
DM
1556 if ($storeid) {
1557 $path = PVE::Storage::path($storecfg, $volid);
5921764c 1558 $format //= qemu_img_format($scfg, $volname);
d81f0f09
DM
1559 } else {
1560 $path = $volid;
5921764c 1561 $format //= "raw";
d81f0f09
DM
1562 }
1563 }
1564
5921764c
SR
1565 my $is_rbd = $path =~ m/^rbd:/;
1566
1e3baf05 1567 my $opts = '';
5921764c 1568 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1e3baf05 1569 foreach my $o (@qemu_drive_options) {
5fc74861 1570 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
19672434 1571 }
8a267708
DC
1572
1573 # snapshot only accepts on|off
1574 if (defined($drive->{snapshot})) {
1575 my $v = $drive->{snapshot} ? 'on' : 'off';
1576 $opts .= ",snapshot=$v";
1577 }
1578
fb8e95a2
WB
1579 foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
1580 my ($dir, $qmpname) = @$type;
1581 if (my $v = $drive->{"mbps$dir"}) {
1582 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1583 }
1584 if (my $v = $drive->{"mbps${dir}_max"}) {
1585 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1586 }
1587 if (my $v = $drive->{"bps${dir}_max_length"}) {
1588 $opts .= ",throttling.bps$qmpname-max-length=$v";
1589 }
1590 if (my $v = $drive->{"iops${dir}"}) {
1591 $opts .= ",throttling.iops$qmpname=$v";
1592 }
1593 if (my $v = $drive->{"iops${dir}_max"}) {
8aca1654 1594 $opts .= ",throttling.iops$qmpname-max=$v";
fb8e95a2
WB
1595 }
1596 if (my $v = $drive->{"iops${dir}_max_length"}) {
8aca1654 1597 $opts .= ",throttling.iops$qmpname-max-length=$v";
fb8e95a2
WB
1598 }
1599 }
1600
5921764c
SR
1601 if ($pbs_name) {
1602 $format = "rbd" if $is_rbd;
a183df68
TL
1603 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1604 if !$format;
5921764c
SR
1605 $opts .= ",format=alloc-track,file.driver=$format";
1606 } elsif ($format) {
1607 $opts .= ",format=$format";
1608 }
d81f0f09 1609
b2ee900e
WB
1610 my $cache_direct = 0;
1611
1612 if (my $cache = $drive->{cache}) {
1613 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
0fe779a6 1614 } elsif (!drive_is_cdrom($drive) && !($scfg && $scfg->{type} eq 'btrfs' && !$scfg->{nocow})) {
b2ee900e
WB
1615 $opts .= ",cache=none";
1616 $cache_direct = 1;
1617 }
1618
628937f5
SR
1619 # io_uring with cache mode writeback or writethrough on krbd will hang...
1620 my $rbd_no_io_uring = $scfg && $scfg->{type} eq 'rbd' && $scfg->{krbd} && !$cache_direct;
1621
78a3ada7
TL
1622 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1623 # sometimes, just plain disable...
1624 my $lvm_no_io_uring = $scfg && $scfg->{type} eq 'lvm';
ec5d198e 1625
b2ee900e 1626 if (!$drive->{aio}) {
ec5d198e 1627 if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring) {
6d5673c3
SR
1628 # io_uring supports all cache modes
1629 $opts .= ",aio=io_uring";
b2ee900e 1630 } else {
6d5673c3
SR
1631 # aio native works only with O_DIRECT
1632 if($cache_direct) {
1633 $opts .= ",aio=native";
1634 } else {
1635 $opts .= ",aio=threads";
1636 }
b2ee900e
WB
1637 }
1638 }
11490cf2 1639
6e47c3b4
WB
1640 if (!drive_is_cdrom($drive)) {
1641 my $detectzeroes;
7d4e30f3 1642 if (defined($drive->{detect_zeroes}) && !$drive->{detect_zeroes}) {
6e47c3b4
WB
1643 $detectzeroes = 'off';
1644 } elsif ($drive->{discard}) {
1645 $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
1646 } else {
1647 # This used to be our default with discard not being specified:
1648 $detectzeroes = 'on';
1649 }
5921764c
SR
1650
1651 # note: 'detect-zeroes' works per blockdev and we want it to persist
1652 # after the alloc-track is removed, so put it on 'file' directly
1653 my $dz_param = $pbs_name ? "file.detect-zeroes" : "detect-zeroes";
1654 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
6e47c3b4 1655 }
f1e05305 1656
5921764c
SR
1657 if ($pbs_name) {
1658 $opts .= ",backing=$pbs_name";
1659 $opts .= ",auto-remove=on";
1660 }
1661
1662 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1663 my $file_param = "file";
1664 if ($pbs_name) {
1665 # non-rbd drivers require the underlying file to be a seperate block
1666 # node, so add a second .file indirection
1667 $file_param .= ".file" if !$is_rbd;
1668 $file_param .= ".filename";
1669 }
1670 my $pathinfo = $path ? "$file_param=$path," : '';
1e3baf05 1671
3ebfcc86 1672 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
1673}
1674
5921764c
SR
1675sub print_pbs_blockdev {
1676 my ($pbs_conf, $pbs_name) = @_;
1677 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1678 $blockdev .= ",repository=$pbs_conf->{repository}";
1679 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1680 $blockdev .= ",archive=$pbs_conf->{archive}";
1681 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile};
1682 return $blockdev;
1683}
1684
cc4d6182 1685sub print_netdevice_full {
d559309f 1686 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
cc4d6182 1687
cc4d6182
DA
1688 my $device = $net->{model};
1689 if ($net->{model} eq 'virtio') {
1690 $device = 'virtio-net-pci';
1691 };
1692
d559309f 1693 my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
5e2068d2 1694 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
a9410357 1695 if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
4df98f2f
TL
1696 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1697 # and out of each queue plus one config interrupt and control vector queue
a9410357
AD
1698 my $vectors = $net->{queues} * 2 + 2;
1699 $tmpstr .= ",vectors=$vectors,mq=on";
1700 }
cc4d6182 1701 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
ba9e1000 1702
0530177b
TL
1703 if (my $mtu = $net->{mtu}) {
1704 if ($net->{model} eq 'virtio' && $net->{bridge}) {
1705 my $bridge_mtu = PVE::Network::read_bridge_mtu($net->{bridge});
1706 if ($mtu == 1) {
1707 $mtu = $bridge_mtu;
1708 } elsif ($mtu < 576) {
1709 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1710 } elsif ($mtu > $bridge_mtu) {
1711 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1712 }
1713 $tmpstr .= ",host_mtu=$mtu";
1714 } else {
1715 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
61a14cde 1716 }
61a14cde
AD
1717 }
1718
ba9e1000
DM
1719 if ($use_old_bios_files) {
1720 my $romfile;
1721 if ($device eq 'virtio-net-pci') {
1722 $romfile = 'pxe-virtio.rom';
1723 } elsif ($device eq 'e1000') {
1724 $romfile = 'pxe-e1000.rom';
e83dd50a
TL
1725 } elsif ($device eq 'e1000e') {
1726 $romfile = 'pxe-e1000e.rom';
ba9e1000
DM
1727 } elsif ($device eq 'ne2k') {
1728 $romfile = 'pxe-ne2k_pci.rom';
1729 } elsif ($device eq 'pcnet') {
1730 $romfile = 'pxe-pcnet.rom';
1731 } elsif ($device eq 'rtl8139') {
1732 $romfile = 'pxe-rtl8139.rom';
1733 }
1734 $tmpstr .= ",romfile=$romfile" if $romfile;
1735 }
1736
cc4d6182
DA
1737 return $tmpstr;
1738}
1739
1740sub print_netdev_full {
d559309f 1741 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
cc4d6182
DA
1742
1743 my $i = '';
1744 if ($netid =~ m/^net(\d+)$/) {
1745 $i = int($1);
1746 }
1747
1748 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
1749
1750 my $ifname = "tap${vmid}i$i";
1751
1752 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1753 die "interface name '$ifname' is too long (max 15 character)\n"
1754 if length($ifname) >= 16;
1755
1756 my $vhostparam = '';
6f0cb675 1757 if (is_native($arch)) {
db70021b 1758 $vhostparam = ',vhost=on' if kernel_has_vhost_net() && $net->{model} eq 'virtio';
6f0cb675 1759 }
cc4d6182
DA
1760
1761 my $vmname = $conf->{name} || "vm$vmid";
1762
a9410357 1763 my $netdev = "";
208ba94e 1764 my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
a9410357 1765
cc4d6182 1766 if ($net->{bridge}) {
4df98f2f
TL
1767 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1768 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
cc4d6182 1769 } else {
a9410357 1770 $netdev = "type=user,id=$netid,hostname=$vmname";
cc4d6182 1771 }
a9410357
AD
1772
1773 $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
1774
1775 return $netdev;
cc4d6182 1776}
1e3baf05 1777
55655ebc
DC
1778my $vga_map = {
1779 'cirrus' => 'cirrus-vga',
1780 'std' => 'VGA',
1781 'vmware' => 'vmware-svga',
1782 'virtio' => 'virtio-vga',
1783};
1784
1785sub print_vga_device {
2ea5fb7e 1786 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
55655ebc
DC
1787
1788 my $type = $vga_map->{$vga->{type}};
86c9fafe 1789 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
d559309f
WB
1790 $type = 'virtio-gpu';
1791 }
55655ebc 1792 my $vgamem_mb = $vga->{memory};
6021c7a5
AL
1793
1794 my $max_outputs = '';
55655ebc
DC
1795 if ($qxlnum) {
1796 $type = $id ? 'qxl' : 'qxl-vga';
6021c7a5 1797
c5a4c92c 1798 if (!$conf->{ostype} || $conf->{ostype} =~ m/^(?:l\d\d)|(?:other)$/) {
6021c7a5 1799 # set max outputs so linux can have up to 4 qxl displays with one device
2ea5fb7e 1800 if (min_version($machine_version, 4, 1)) {
9e8976ea
TL
1801 $max_outputs = ",max_outputs=4";
1802 }
6021c7a5 1803 }
55655ebc 1804 }
6021c7a5 1805
55655ebc
DC
1806 die "no devicetype for $vga->{type}\n" if !$type;
1807
1808 my $memory = "";
1809 if ($vgamem_mb) {
1810 if ($vga->{type} eq 'virtio') {
1811 my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
1812 $memory = ",max_hostmem=$bytes";
1813 } elsif ($qxlnum) {
1814 # from https://www.spice-space.org/multiple-monitors.html
1815 $memory = ",vgamem_mb=$vga->{memory}";
1816 my $ram = $vgamem_mb * 4;
1817 my $vram = $vgamem_mb * 2;
1818 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1819 } else {
1820 $memory = ",vgamem_mb=$vga->{memory}";
1821 }
1822 } elsif ($qxlnum && $id) {
1823 $memory = ",ram_size=67108864,vram_size=33554432";
1824 }
1825
789fe8e8
AL
1826 my $edidoff = "";
1827 if ($type eq 'VGA' && windows_version($conf->{ostype})) {
b5d32c6b 1828 $edidoff=",edid=off" if (!defined($conf->{bios}) || $conf->{bios} ne 'ovmf');
789fe8e8
AL
1829 }
1830
3392d6ca 1831 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
55655ebc
DC
1832 my $vgaid = "vga" . ($id // '');
1833 my $pciaddr;
daadd5a4 1834
55655ebc 1835 if ($q35 && $vgaid eq 'vga') {
daadd5a4 1836 # the first display uses pcie.0 bus on q35 machines
d559309f 1837 $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
55655ebc 1838 } else {
d559309f 1839 $pciaddr = print_pci_addr($vgaid, $bridges, $arch, $machine);
55655ebc
DC
1840 }
1841
789fe8e8 1842 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
55655ebc
DC
1843}
1844
ffc0d8c7
WB
1845sub parse_number_sets {
1846 my ($set) = @_;
1847 my $res = [];
1848 foreach my $part (split(/;/, $set)) {
1849 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1850 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1851 push @$res, [ $1, $2 ];
2ed5d572 1852 } else {
ffc0d8c7 1853 die "invalid range: $part\n";
2ed5d572
AD
1854 }
1855 }
ffc0d8c7
WB
1856 return $res;
1857}
2ed5d572 1858
ffc0d8c7
WB
1859sub parse_numa {
1860 my ($data) = @_;
1861
4df98f2f 1862 my $res = parse_property_string($numa_fmt, $data);
ffc0d8c7
WB
1863 $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
1864 $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2ed5d572
AD
1865 return $res;
1866}
1867
1e3baf05
DM
1868# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1869sub parse_net {
1870 my ($data) = @_;
1871
4df98f2f 1872 my $res = eval { parse_property_string($net_fmt, $data) };
cd9c34d1
WB
1873 if ($@) {
1874 warn $@;
d1c1af4b 1875 return;
1e3baf05 1876 }
b5b99790
WB
1877 if (!defined($res->{macaddr})) {
1878 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
1879 $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
1880 }
0c9a7596
AD
1881 return $res;
1882}
1883
1884# ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1885sub parse_ipconfig {
1886 my ($data) = @_;
1887
4df98f2f 1888 my $res = eval { parse_property_string($ipconfig_fmt, $data) };
0c9a7596
AD
1889 if ($@) {
1890 warn $@;
d1c1af4b 1891 return;
0c9a7596
AD
1892 }
1893
1894 if ($res->{gw} && !$res->{ip}) {
1895 warn 'gateway specified without specifying an IP address';
d1c1af4b 1896 return;
0c9a7596
AD
1897 }
1898 if ($res->{gw6} && !$res->{ip6}) {
1899 warn 'IPv6 gateway specified without specifying an IPv6 address';
d1c1af4b 1900 return;
0c9a7596
AD
1901 }
1902 if ($res->{gw} && $res->{ip} eq 'dhcp') {
1903 warn 'gateway specified together with DHCP';
d1c1af4b 1904 return;
0c9a7596
AD
1905 }
1906 if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
1907 # gw6 + auto/dhcp
1908 warn "IPv6 gateway specified together with $res->{ip6} address";
d1c1af4b 1909 return;
0c9a7596
AD
1910 }
1911
1912 if (!$res->{ip} && !$res->{ip6}) {
1913 return { ip => 'dhcp', ip6 => 'dhcp' };
1914 }
1915
1e3baf05
DM
1916 return $res;
1917}
1918
1919sub print_net {
1920 my $net = shift;
1921
cd9c34d1 1922 return PVE::JSONSchema::print_property_string($net, $net_fmt);
1e3baf05
DM
1923}
1924
1925sub add_random_macs {
1926 my ($settings) = @_;
1927
1928 foreach my $opt (keys %$settings) {
1929 next if $opt !~ m/^net(\d+)$/;
1930 my $net = parse_net($settings->{$opt});
1931 next if !$net;
1932 $settings->{$opt} = print_net($net);
1933 }
1934}
1935
055d554d
DM
1936sub vm_is_volid_owner {
1937 my ($storecfg, $vmid, $volid) = @_;
1938
1939 if ($volid !~ m|^/|) {
1940 my ($path, $owner);
1941 eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
1942 if ($owner && ($owner == $vmid)) {
1943 return 1;
1944 }
1945 }
1946
d1c1af4b 1947 return;
055d554d
DM
1948}
1949
055d554d
DM
1950sub vmconfig_register_unused_drive {
1951 my ($storecfg, $vmid, $conf, $drive) = @_;
1952
2d9ddec5
WB
1953 if (drive_is_cloudinit($drive)) {
1954 eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
1955 warn $@ if $@;
1956 } elsif (!drive_is_cdrom($drive)) {
055d554d
DM
1957 my $volid = $drive->{file};
1958 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
8793d495 1959 PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
055d554d
DM
1960 }
1961 }
1962}
1963
1f30ac3a 1964# smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
ff6ffe20 1965my $smbios1_fmt = {
bd27e851
WB
1966 uuid => {
1967 type => 'string',
1968 pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1969 format_description => 'UUID',
52261945 1970 description => "Set SMBIOS1 UUID.",
bd27e851
WB
1971 optional => 1,
1972 },
1973 version => {
1974 type => 'string',
1f30ac3a
CE
1975 pattern => '[A-Za-z0-9+\/]+={0,2}',
1976 format_description => 'Base64 encoded string',
52261945 1977 description => "Set SMBIOS1 version.",
bd27e851
WB
1978 optional => 1,
1979 },
1980 serial => {
1981 type => 'string',
1f30ac3a
CE
1982 pattern => '[A-Za-z0-9+\/]+={0,2}',
1983 format_description => 'Base64 encoded string',
52261945 1984 description => "Set SMBIOS1 serial number.",
bd27e851
WB
1985 optional => 1,
1986 },
1987 manufacturer => {
1988 type => 'string',
1f30ac3a
CE
1989 pattern => '[A-Za-z0-9+\/]+={0,2}',
1990 format_description => 'Base64 encoded string',
52261945 1991 description => "Set SMBIOS1 manufacturer.",
bd27e851
WB
1992 optional => 1,
1993 },
1994 product => {
1995 type => 'string',
1f30ac3a
CE
1996 pattern => '[A-Za-z0-9+\/]+={0,2}',
1997 format_description => 'Base64 encoded string',
52261945 1998 description => "Set SMBIOS1 product ID.",
bd27e851
WB
1999 optional => 1,
2000 },
2001 sku => {
2002 type => 'string',
1f30ac3a
CE
2003 pattern => '[A-Za-z0-9+\/]+={0,2}',
2004 format_description => 'Base64 encoded string',
52261945 2005 description => "Set SMBIOS1 SKU string.",
bd27e851
WB
2006 optional => 1,
2007 },
2008 family => {
2009 type => 'string',
1f30ac3a
CE
2010 pattern => '[A-Za-z0-9+\/]+={0,2}',
2011 format_description => 'Base64 encoded string',
52261945 2012 description => "Set SMBIOS1 family string.",
bd27e851
WB
2013 optional => 1,
2014 },
1f30ac3a
CE
2015 base64 => {
2016 type => 'boolean',
2017 description => 'Flag to indicate that the SMBIOS values are base64 encoded',
2018 optional => 1,
2019 },
2796e7d5
DM
2020};
2021
2796e7d5
DM
2022sub parse_smbios1 {
2023 my ($data) = @_;
2024
4df98f2f 2025 my $res = eval { parse_property_string($smbios1_fmt, $data) };
bd27e851 2026 warn $@ if $@;
2796e7d5
DM
2027 return $res;
2028}
2029
cd11416f
DM
2030sub print_smbios1 {
2031 my ($smbios1) = @_;
ff6ffe20 2032 return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
cd11416f
DM
2033}
2034
ff6ffe20 2035PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2796e7d5 2036
0ea9541d
DM
2037sub parse_watchdog {
2038 my ($value) = @_;
2039
d1c1af4b 2040 return if !$value;
0ea9541d 2041
4df98f2f 2042 my $res = eval { parse_property_string($watchdog_fmt, $value) };
ec3582b5 2043 warn $@ if $@;
0ea9541d
DM
2044 return $res;
2045}
2046
9d66b397 2047sub parse_guest_agent {
a2af1bbe 2048 my ($conf) = @_;
9d66b397 2049
a2af1bbe 2050 return {} if !defined($conf->{agent});
9d66b397 2051
a2af1bbe 2052 my $res = eval { parse_property_string($agent_fmt, $conf->{agent}) };
9d66b397
SI
2053 warn $@ if $@;
2054
2055 # if the agent is disabled ignore the other potentially set properties
2056 return {} if !$res->{enabled};
2057 return $res;
2058}
2059
a2af1bbe
TL
2060sub get_qga_key {
2061 my ($conf, $key) = @_;
2062 return undef if !defined($conf->{agent});
2063
2064 my $agent = parse_guest_agent($conf);
2065 return $agent->{$key};
2066}
2067
55655ebc
DC
2068sub parse_vga {
2069 my ($value) = @_;
2070
2071 return {} if !$value;
4df98f2f 2072 my $res = eval { parse_property_string($vga_fmt, $value) };
55655ebc
DC
2073 warn $@ if $@;
2074 return $res;
2075}
2076
2cf61f33
SR
2077sub parse_rng {
2078 my ($value) = @_;
2079
d1c1af4b 2080 return if !$value;
2cf61f33 2081
4df98f2f 2082 my $res = eval { parse_property_string($rng_fmt, $value) };
2cf61f33
SR
2083 warn $@ if $@;
2084 return $res;
2085}
2086
1e3baf05
DM
2087PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
2088sub verify_usb_device {
2089 my ($value, $noerr) = @_;
2090
2091 return $value if parse_usb_device($value);
2092
d1c1af4b 2093 return if $noerr;
19672434 2094
1e3baf05
DM
2095 die "unable to parse usb device\n";
2096}
2097
1e3baf05
DM
2098# add JSON properties for create and set function
2099sub json_config_properties {
2100 my $prop = shift;
2101
2102 foreach my $opt (keys %$confdesc) {
ea1c2110
SR
2103 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' ||
2104 $opt eq 'runningmachine' || $opt eq 'runningcpu';
1e3baf05
DM
2105 $prop->{$opt} = $confdesc->{$opt};
2106 }
2107
2108 return $prop;
2109}
2110
d41121fd
DM
2111# return copy of $confdesc_cloudinit to generate documentation
2112sub cloudinit_config_properties {
2113
2114 return dclone($confdesc_cloudinit);
2115}
2116
1e3baf05
DM
2117sub check_type {
2118 my ($key, $value) = @_;
2119
2120 die "unknown setting '$key'\n" if !$confdesc->{$key};
2121
2122 my $type = $confdesc->{$key}->{type};
2123
6b64503e 2124 if (!defined($value)) {
1e3baf05
DM
2125 die "got undefined value\n";
2126 }
2127
2128 if ($value =~ m/[\n\r]/) {
2129 die "property contains a line feed\n";
2130 }
2131
2132 if ($type eq 'boolean') {
19672434
DM
2133 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2134 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2135 die "type check ('boolean') failed - got '$value'\n";
1e3baf05
DM
2136 } elsif ($type eq 'integer') {
2137 return int($1) if $value =~ m/^(\d+)$/;
2138 die "type check ('integer') failed - got '$value'\n";
04432191
AD
2139 } elsif ($type eq 'number') {
2140 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2141 die "type check ('number') failed - got '$value'\n";
1e3baf05
DM
2142 } elsif ($type eq 'string') {
2143 if (my $fmt = $confdesc->{$key}->{format}) {
1e3baf05 2144 PVE::JSONSchema::check_format($fmt, $value);
19672434
DM
2145 return $value;
2146 }
1e3baf05 2147 $value =~ s/^\"(.*)\"$/$1/;
19672434 2148 return $value;
1e3baf05
DM
2149 } else {
2150 die "internal error"
2151 }
2152}
2153
1e3baf05 2154sub destroy_vm {
75854662 2155 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
1e3baf05 2156
ffda963f 2157 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2158
ffda963f 2159 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 2160
5e67a2d2
DC
2161 if ($conf->{template}) {
2162 # check if any base image is still used by a linked clone
3ab0f925 2163 PVE::QemuConfig->foreach_volume_full($conf, { include_unused => 1 }, sub {
5e67a2d2 2164 my ($ds, $drive) = @_;
5e67a2d2
DC
2165 return if drive_is_cdrom($drive);
2166
2167 my $volid = $drive->{file};
5e67a2d2
DC
2168 return if !$volid || $volid =~ m|^/|;
2169
2170 die "base volume '$volid' is still in use by linked cloned\n"
2171 if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2172
2173 });
2174 }
2175
3e07c6d5 2176 my $volids = {};
ba1a1984 2177 my $remove_owned_drive = sub {
1e3baf05 2178 my ($ds, $drive) = @_;
9c52f5ed 2179 return if drive_is_cdrom($drive, 1);
1e3baf05
DM
2180
2181 my $volid = $drive->{file};
ff1a2432 2182 return if !$volid || $volid =~ m|^/|;
3e07c6d5 2183 return if $volids->{$volid};
1e3baf05 2184
6b64503e 2185 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
ff1a2432 2186 return if !$path || !$owner || ($owner != $vmid);
1e3baf05 2187
3e07c6d5 2188 $volids->{$volid} = 1;
a2f50f01 2189 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
31b52247 2190 warn "Could not remove disk '$volid', check manually: $@" if $@;
ba1a1984
FE
2191 };
2192
2193 # only remove disks owned by this VM (referenced in the config)
2194 my $include_opts = {
2195 include_unused => 1,
2196 extra_keys => ['vmstate'],
2197 };
2198 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2199
2200 for my $snap (values %{$conf->{snapshots}}) {
2201 next if !defined($snap->{vmstate});
2202 my $drive = PVE::QemuConfig->parse_volume('vmstate', $snap->{vmstate}, 1);
2203 next if !defined($drive);
2204 $remove_owned_drive->('vmstate', $drive);
2205 }
19672434 2206
3e07c6d5
FG
2207 PVE::QemuConfig->foreach_volume_full($conf->{pending}, $include_opts, $remove_owned_drive);
2208
75854662 2209 if ($purge_unreferenced) { # also remove unreferenced disk
d0ff75d9 2210 my $vmdisks = PVE::Storage::vdisk_list($storecfg, undef, $vmid, undef, 'images');
75854662
TL
2211 PVE::Storage::foreach_volid($vmdisks, sub {
2212 my ($volid, $sid, $volname, $d) = @_;
2213 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
2214 warn $@ if $@;
2215 });
2216 }
dfda979e 2217
b04ea584 2218 if (defined $replacement_conf) {
8baf8bc7 2219 PVE::QemuConfig->write_config($vmid, $replacement_conf);
dfda979e
DJ
2220 } else {
2221 PVE::QemuConfig->destroy_config($vmid);
2222 }
1e3baf05
DM
2223}
2224
1e3baf05
DM
2225sub parse_vm_config {
2226 my ($filename, $raw) = @_;
2227
d1c1af4b 2228 return if !defined($raw);
1e3baf05 2229
554ac7e7 2230 my $res = {
fc1ddcdc 2231 digest => Digest::SHA::sha1_hex($raw),
0d18dcfc 2232 snapshots => {},
0d732d16 2233 pending => {},
554ac7e7 2234 };
1e3baf05 2235
19672434 2236 $filename =~ m|/qemu-server/(\d+)\.conf$|
1e3baf05
DM
2237 || die "got strange filename '$filename'";
2238
2239 my $vmid = $1;
2240
0d18dcfc 2241 my $conf = $res;
b0ec896e 2242 my $descr;
e297c490 2243 my $section = '';
0581fe4f 2244
0d18dcfc
DM
2245 my @lines = split(/\n/, $raw);
2246 foreach my $line (@lines) {
1e3baf05 2247 next if $line =~ m/^\s*$/;
be190583 2248
eab09f4e 2249 if ($line =~ m/^\[PENDING\]\s*$/i) {
e297c490 2250 $section = 'pending';
b0ec896e
DM
2251 if (defined($descr)) {
2252 $descr =~ s/\s+$//;
2253 $conf->{description} = $descr;
2254 }
2255 $descr = undef;
e297c490 2256 $conf = $res->{$section} = {};
eab09f4e
AD
2257 next;
2258
0d732d16 2259 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
e297c490 2260 $section = $1;
b0ec896e
DM
2261 if (defined($descr)) {
2262 $descr =~ s/\s+$//;
2263 $conf->{description} = $descr;
2264 }
2265 $descr = undef;
e297c490 2266 $conf = $res->{snapshots}->{$section} = {};
0d18dcfc
DM
2267 next;
2268 }
1e3baf05 2269
0581fe4f 2270 if ($line =~ m/^\#(.*)\s*$/) {
b0ec896e 2271 $descr = '' if !defined($descr);
0581fe4f
DM
2272 $descr .= PVE::Tools::decode_text($1) . "\n";
2273 next;
2274 }
2275
1e3baf05 2276 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
b0ec896e 2277 $descr = '' if !defined($descr);
0581fe4f 2278 $descr .= PVE::Tools::decode_text($2);
0d18dcfc
DM
2279 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2280 $conf->{snapstate} = $1;
1e3baf05
DM
2281 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2282 my $key = $1;
2283 my $value = $2;
0d18dcfc 2284 $conf->{$key} = $value;
ef824322 2285 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
e297c490 2286 my $value = $1;
ef824322
DM
2287 if ($section eq 'pending') {
2288 $conf->{delete} = $value; # we parse this later
2289 } else {
2290 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
eab09f4e 2291 }
15cf7698 2292 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
1e3baf05
DM
2293 my $key = $1;
2294 my $value = $2;
2295 eval { $value = check_type($key, $value); };
2296 if ($@) {
2297 warn "vm $vmid - unable to parse value of '$key' - $@";
2298 } else {
b799312f 2299 $key = 'ide2' if $key eq 'cdrom';
1e3baf05 2300 my $fmt = $confdesc->{$key}->{format};
b799312f 2301 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
1e3baf05
DM
2302 my $v = parse_drive($key, $value);
2303 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2304 $v->{file} = $volid;
71c58bb7 2305 $value = print_drive($v);
1e3baf05
DM
2306 } else {
2307 warn "vm $vmid - unable to parse value of '$key'\n";
2308 next;
2309 }
2310 }
2311
b799312f 2312 $conf->{$key} = $value;
1e3baf05 2313 }
f8d2a1ce
FE
2314 } else {
2315 warn "vm $vmid - unable to parse config: $line\n";
1e3baf05
DM
2316 }
2317 }
2318
b0ec896e
DM
2319 if (defined($descr)) {
2320 $descr =~ s/\s+$//;
2321 $conf->{description} = $descr;
2322 }
0d18dcfc 2323 delete $res->{snapstate}; # just to be sure
1e3baf05
DM
2324
2325 return $res;
2326}
2327
1858638f
DM
2328sub write_vm_config {
2329 my ($filename, $conf) = @_;
1e3baf05 2330
0d18dcfc
DM
2331 delete $conf->{snapstate}; # just to be sure
2332
1858638f
DM
2333 if ($conf->{cdrom}) {
2334 die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2335 $conf->{ide2} = $conf->{cdrom};
2336 delete $conf->{cdrom};
2337 }
1e3baf05
DM
2338
2339 # we do not use 'smp' any longer
1858638f
DM
2340 if ($conf->{sockets}) {
2341 delete $conf->{smp};
2342 } elsif ($conf->{smp}) {
2343 $conf->{sockets} = $conf->{smp};
2344 delete $conf->{cores};
2345 delete $conf->{smp};
1e3baf05
DM
2346 }
2347
ee2f90b1 2348 my $used_volids = {};
0d18dcfc 2349
ee2f90b1 2350 my $cleanup_config = sub {
ef824322 2351 my ($cref, $pending, $snapname) = @_;
1858638f 2352
ee2f90b1
DM
2353 foreach my $key (keys %$cref) {
2354 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
ef824322 2355 $key eq 'snapstate' || $key eq 'pending';
ee2f90b1 2356 my $value = $cref->{$key};
ef824322
DM
2357 if ($key eq 'delete') {
2358 die "propertry 'delete' is only allowed in [PENDING]\n"
2359 if !$pending;
2360 # fixme: check syntax?
2361 next;
2362 }
ee2f90b1
DM
2363 eval { $value = check_type($key, $value); };
2364 die "unable to parse value of '$key' - $@" if $@;
1858638f 2365
ee2f90b1
DM
2366 $cref->{$key} = $value;
2367
74479ee9 2368 if (!$snapname && is_valid_drivename($key)) {
ed221350 2369 my $drive = parse_drive($key, $value);
ee2f90b1
DM
2370 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2371 }
1e3baf05 2372 }
ee2f90b1
DM
2373 };
2374
2375 &$cleanup_config($conf);
ef824322
DM
2376
2377 &$cleanup_config($conf->{pending}, 1);
2378
ee2f90b1 2379 foreach my $snapname (keys %{$conf->{snapshots}}) {
15c6e277 2380 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
ef824322 2381 &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
1e3baf05
DM
2382 }
2383
1858638f
DM
2384 # remove 'unusedX' settings if we re-add a volume
2385 foreach my $key (keys %$conf) {
2386 my $value = $conf->{$key};
ee2f90b1 2387 if ($key =~ m/^unused/ && $used_volids->{$value}) {
1858638f 2388 delete $conf->{$key};
1e3baf05 2389 }
1858638f 2390 }
be190583 2391
0d18dcfc 2392 my $generate_raw_config = sub {
b0ec896e 2393 my ($conf, $pending) = @_;
0581fe4f 2394
0d18dcfc
DM
2395 my $raw = '';
2396
2397 # add description as comment to top of file
b0ec896e
DM
2398 if (defined(my $descr = $conf->{description})) {
2399 if ($descr) {
2400 foreach my $cl (split(/\n/, $descr)) {
2401 $raw .= '#' . PVE::Tools::encode_text($cl) . "\n";
2402 }
2403 } else {
2404 $raw .= "#\n" if $pending;
2405 }
0d18dcfc
DM
2406 }
2407
2408 foreach my $key (sort keys %$conf) {
4df98f2f 2409 next if $key =~ /^(digest|description|pending|snapshots)$/;
0d18dcfc
DM
2410 $raw .= "$key: $conf->{$key}\n";
2411 }
2412 return $raw;
2413 };
0581fe4f 2414
0d18dcfc 2415 my $raw = &$generate_raw_config($conf);
ef824322
DM
2416
2417 if (scalar(keys %{$conf->{pending}})){
2418 $raw .= "\n[PENDING]\n";
b0ec896e 2419 $raw .= &$generate_raw_config($conf->{pending}, 1);
ef824322
DM
2420 }
2421
0d18dcfc
DM
2422 foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2423 $raw .= "\n[$snapname]\n";
2424 $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
1858638f 2425 }
1e3baf05 2426
1858638f
DM
2427 return $raw;
2428}
1e3baf05 2429
19672434 2430sub load_defaults {
1e3baf05
DM
2431
2432 my $res = {};
2433
2434 # we use static defaults from our JSON schema configuration
2435 foreach my $key (keys %$confdesc) {
2436 if (defined(my $default = $confdesc->{$key}->{default})) {
2437 $res->{$key} = $default;
2438 }
2439 }
19672434 2440
1e3baf05
DM
2441 return $res;
2442}
2443
2444sub config_list {
2445 my $vmlist = PVE::Cluster::get_vmlist();
2446 my $res = {};
2447 return $res if !$vmlist || !$vmlist->{ids};
2448 my $ids = $vmlist->{ids};
38277afc 2449 my $nodename = nodename();
1e3baf05 2450
1e3baf05
DM
2451 foreach my $vmid (keys %$ids) {
2452 my $d = $ids->{$vmid};
2453 next if !$d->{node} || $d->{node} ne $nodename;
5ee957cc 2454 next if !$d->{type} || $d->{type} ne 'qemu';
1e3baf05
DM
2455 $res->{$vmid}->{exists} = 1;
2456 }
2457 return $res;
2458}
2459
64e13401
DM
2460# test if VM uses local resources (to prevent migration)
2461sub check_local_resources {
2462 my ($conf, $noerr) = @_;
2463
ca6abacf 2464 my @loc_res = ();
19672434 2465
ca6abacf
TM
2466 push @loc_res, "hostusb" if $conf->{hostusb}; # old syntax
2467 push @loc_res, "hostpci" if $conf->{hostpci}; # old syntax
64e13401 2468
ca6abacf 2469 push @loc_res, "ivshmem" if $conf->{ivshmem};
6dbcb073 2470
0d29ab3b 2471 foreach my $k (keys %$conf) {
a9ce7583 2472 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
d44712fc
EK
2473 # sockets are safe: they will recreated be on the target side post-migrate
2474 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
ca6abacf 2475 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
64e13401
DM
2476 }
2477
ca6abacf 2478 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
64e13401 2479
ca6abacf 2480 return \@loc_res;
64e13401
DM
2481}
2482
719893a9 2483# check if used storages are available on all nodes (use by migrate)
47152e2e
DM
2484sub check_storage_availability {
2485 my ($storecfg, $conf, $node) = @_;
2486
912792e2 2487 PVE::QemuConfig->foreach_volume($conf, sub {
47152e2e
DM
2488 my ($ds, $drive) = @_;
2489
2490 my $volid = $drive->{file};
2491 return if !$volid;
2492
2493 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2494 return if !$sid;
2495
2496 # check if storage is available on both nodes
0d2db084
FE
2497 my $scfg = PVE::Storage::storage_check_enabled($storecfg, $sid);
2498 PVE::Storage::storage_check_enabled($storecfg, $sid, $node);
24b84b47 2499
3148f0b0
TL
2500 my ($vtype) = PVE::Storage::parse_volname($storecfg, $volid);
2501
2502 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2503 if !$scfg->{content}->{$vtype};
47152e2e
DM
2504 });
2505}
2506
719893a9
DM
2507# list nodes where all VM images are available (used by has_feature API)
2508sub shared_nodes {
2509 my ($conf, $storecfg) = @_;
2510
2511 my $nodelist = PVE::Cluster::get_nodelist();
2512 my $nodehash = { map { $_ => 1 } @$nodelist };
38277afc 2513 my $nodename = nodename();
be190583 2514
912792e2 2515 PVE::QemuConfig->foreach_volume($conf, sub {
719893a9
DM
2516 my ($ds, $drive) = @_;
2517
2518 my $volid = $drive->{file};
2519 return if !$volid;
2520
2521 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2522 if ($storeid) {
2523 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2524 if ($scfg->{disable}) {
2525 $nodehash = {};
2526 } elsif (my $avail = $scfg->{nodes}) {
2527 foreach my $node (keys %$nodehash) {
2528 delete $nodehash->{$node} if !$avail->{$node};
2529 }
2530 } elsif (!$scfg->{shared}) {
2531 foreach my $node (keys %$nodehash) {
2532 delete $nodehash->{$node} if $node ne $nodename
2533 }
2534 }
2535 }
2536 });
2537
2538 return $nodehash
2539}
2540
f25852c2
TM
2541sub check_local_storage_availability {
2542 my ($conf, $storecfg) = @_;
2543
2544 my $nodelist = PVE::Cluster::get_nodelist();
2545 my $nodehash = { map { $_ => {} } @$nodelist };
2546
912792e2 2547 PVE::QemuConfig->foreach_volume($conf, sub {
f25852c2
TM
2548 my ($ds, $drive) = @_;
2549
2550 my $volid = $drive->{file};
2551 return if !$volid;
2552
2553 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2554 if ($storeid) {
2555 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2556
2557 if ($scfg->{disable}) {
2558 foreach my $node (keys %$nodehash) {
32075a2c 2559 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2560 }
2561 } elsif (my $avail = $scfg->{nodes}) {
2562 foreach my $node (keys %$nodehash) {
2563 if (!$avail->{$node}) {
32075a2c 2564 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2565 }
2566 }
2567 }
2568 }
2569 });
2570
32075a2c
TL
2571 foreach my $node (values %$nodehash) {
2572 if (my $unavail = $node->{unavailable_storages}) {
2573 $node->{unavailable_storages} = [ sort keys %$unavail ];
2574 }
2575 }
2576
f25852c2
TM
2577 return $nodehash
2578}
2579
babf613a 2580# Compat only, use assert_config_exists_on_node and vm_running_locally where possible
1e3baf05 2581sub check_running {
7e8dcf2c 2582 my ($vmid, $nocheck, $node) = @_;
1e3baf05 2583
babf613a
SR
2584 PVE::QemuConfig::assert_config_exists_on_node($vmid, $node) if !$nocheck;
2585 return PVE::QemuServer::Helpers::vm_running_locally($vmid);
1e3baf05
DM
2586}
2587
2588sub vzlist {
19672434 2589
1e3baf05
DM
2590 my $vzlist = config_list();
2591
d036e418 2592 my $fd = IO::Dir->new($PVE::QemuServer::Helpers::var_run_tmpdir) || return $vzlist;
1e3baf05 2593
19672434 2594 while (defined(my $de = $fd->read)) {
1e3baf05
DM
2595 next if $de !~ m/^(\d+)\.pid$/;
2596 my $vmid = $1;
6b64503e
DM
2597 next if !defined($vzlist->{$vmid});
2598 if (my $pid = check_running($vmid)) {
1e3baf05
DM
2599 $vzlist->{$vmid}->{pid} = $pid;
2600 }
2601 }
2602
2603 return $vzlist;
2604}
2605
b1a70cab
DM
2606our $vmstatus_return_properties = {
2607 vmid => get_standard_option('pve-vmid'),
2608 status => {
2609 description => "Qemu process status.",
2610 type => 'string',
2611 enum => ['stopped', 'running'],
2612 },
2613 maxmem => {
2614 description => "Maximum memory in bytes.",
2615 type => 'integer',
2616 optional => 1,
2617 renderer => 'bytes',
2618 },
2619 maxdisk => {
2620 description => "Root disk size in bytes.",
2621 type => 'integer',
2622 optional => 1,
2623 renderer => 'bytes',
2624 },
2625 name => {
2626 description => "VM name.",
2627 type => 'string',
2628 optional => 1,
2629 },
2630 qmpstatus => {
2631 description => "Qemu QMP agent status.",
2632 type => 'string',
2633 optional => 1,
2634 },
2635 pid => {
2636 description => "PID of running qemu process.",
2637 type => 'integer',
2638 optional => 1,
2639 },
2640 uptime => {
2641 description => "Uptime.",
2642 type => 'integer',
2643 optional => 1,
2644 renderer => 'duration',
2645 },
2646 cpus => {
2647 description => "Maximum usable CPUs.",
2648 type => 'number',
2649 optional => 1,
2650 },
e6ed61b4 2651 lock => {
11efdfa5 2652 description => "The current config lock, if any.",
e6ed61b4
DC
2653 type => 'string',
2654 optional => 1,
b8e7068a
DC
2655 },
2656 tags => {
2657 description => "The current configured tags, if any",
2658 type => 'string',
2659 optional => 1,
2660 },
949112c3
FE
2661 'running-machine' => {
2662 description => "The currently running machine type (if running).",
2663 type => 'string',
2664 optional => 1,
2665 },
2666 'running-qemu' => {
2667 description => "The currently running QEMU version (if running).",
2668 type => 'string',
2669 optional => 1,
2670 },
b1a70cab
DM
2671};
2672
1e3baf05
DM
2673my $last_proc_pid_stat;
2674
03a33f30
DM
2675# get VM status information
2676# This must be fast and should not block ($full == false)
2677# We only query KVM using QMP if $full == true (this can be slow)
1e3baf05 2678sub vmstatus {
03a33f30 2679 my ($opt_vmid, $full) = @_;
1e3baf05
DM
2680
2681 my $res = {};
2682
19672434 2683 my $storecfg = PVE::Storage::config();
1e3baf05
DM
2684
2685 my $list = vzlist();
3618ee99
EK
2686 my $defaults = load_defaults();
2687
694fcad4 2688 my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
1e3baf05 2689
ae4915a2
DM
2690 my $cpucount = $cpuinfo->{cpus} || 1;
2691
1e3baf05
DM
2692 foreach my $vmid (keys %$list) {
2693 next if $opt_vmid && ($vmid ne $opt_vmid);
2694
9f78b695 2695 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2696
ad2cad72 2697 my $d = { vmid => int($vmid) };
8a0addab 2698 $d->{pid} = int($list->{$vmid}->{pid}) if $list->{$vmid}->{pid};
1e3baf05
DM
2699
2700 # fixme: better status?
2701 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
2702
776c5f50 2703 my $size = PVE::QemuServer::Drive::bootdisk_size($storecfg, $conf);
af990afe
DM
2704 if (defined($size)) {
2705 $d->{disk} = 0; # no info available
1e3baf05
DM
2706 $d->{maxdisk} = $size;
2707 } else {
2708 $d->{disk} = 0;
2709 $d->{maxdisk} = 0;
2710 }
2711
3618ee99
EK
2712 $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
2713 * ($conf->{cores} || $defaults->{cores});
ae4915a2 2714 $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
d7c8364b 2715 $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
ae4915a2 2716
1e3baf05 2717 $d->{name} = $conf->{name} || "VM $vmid";
3618ee99
EK
2718 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
2719 : $defaults->{memory}*(1024*1024);
1e3baf05 2720
8b1accf7 2721 if ($conf->{balloon}) {
4bdb0514 2722 $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3618ee99
EK
2723 $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
2724 : $defaults->{shares};
8b1accf7
DM
2725 }
2726
1e3baf05
DM
2727 $d->{uptime} = 0;
2728 $d->{cpu} = 0;
1e3baf05
DM
2729 $d->{mem} = 0;
2730
2731 $d->{netout} = 0;
2732 $d->{netin} = 0;
2733
2734 $d->{diskread} = 0;
2735 $d->{diskwrite} = 0;
2736
75a2a423 2737 $d->{template} = 1 if PVE::QemuConfig->is_template($conf);
4d8c851b 2738
8107b378 2739 $d->{serial} = 1 if conf_has_serial($conf);
e6ed61b4 2740 $d->{lock} = $conf->{lock} if $conf->{lock};
b8e7068a 2741 $d->{tags} = $conf->{tags} if defined($conf->{tags});
8107b378 2742
1e3baf05
DM
2743 $res->{$vmid} = $d;
2744 }
2745
2746 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
2747 foreach my $dev (keys %$netdev) {
2748 next if $dev !~ m/^tap([1-9]\d*)i/;
2749 my $vmid = $1;
2750 my $d = $res->{$vmid};
2751 next if !$d;
19672434 2752
1e3baf05
DM
2753 $d->{netout} += $netdev->{$dev}->{receive};
2754 $d->{netin} += $netdev->{$dev}->{transmit};
604ea644
AD
2755
2756 if ($full) {
ad2cad72
FE
2757 $d->{nics}->{$dev}->{netout} = int($netdev->{$dev}->{receive});
2758 $d->{nics}->{$dev}->{netin} = int($netdev->{$dev}->{transmit});
604ea644
AD
2759 }
2760
1e3baf05
DM
2761 }
2762
1e3baf05
DM
2763 my $ctime = gettimeofday;
2764
2765 foreach my $vmid (keys %$list) {
2766
2767 my $d = $res->{$vmid};
2768 my $pid = $d->{pid};
2769 next if !$pid;
2770
694fcad4
DM
2771 my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
2772 next if !$pstat; # not running
19672434 2773
694fcad4 2774 my $used = $pstat->{utime} + $pstat->{stime};
1e3baf05 2775
694fcad4 2776 $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
1e3baf05 2777
694fcad4 2778 if ($pstat->{vsize}) {
6b64503e 2779 $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
1e3baf05
DM
2780 }
2781
2782 my $old = $last_proc_pid_stat->{$pid};
2783 if (!$old) {
19672434
DM
2784 $last_proc_pid_stat->{$pid} = {
2785 time => $ctime,
1e3baf05
DM
2786 used => $used,
2787 cpu => 0,
1e3baf05
DM
2788 };
2789 next;
2790 }
2791
7f0b5beb 2792 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz};
1e3baf05
DM
2793
2794 if ($dtime > 1000) {
2795 my $dutime = $used - $old->{used};
2796
ae4915a2 2797 $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
1e3baf05 2798 $last_proc_pid_stat->{$pid} = {
19672434 2799 time => $ctime,
1e3baf05
DM
2800 used => $used,
2801 cpu => $d->{cpu},
1e3baf05
DM
2802 };
2803 } else {
2804 $d->{cpu} = $old->{cpu};
1e3baf05
DM
2805 }
2806 }
2807
f5eb281a 2808 return $res if !$full;
03a33f30
DM
2809
2810 my $qmpclient = PVE::QMPClient->new();
2811
64e7fcf2
DM
2812 my $ballooncb = sub {
2813 my ($vmid, $resp) = @_;
2814
2815 my $info = $resp->{'return'};
38babf81
DM
2816 return if !$info->{max_mem};
2817
64e7fcf2
DM
2818 my $d = $res->{$vmid};
2819
38babf81
DM
2820 # use memory assigned to VM
2821 $d->{maxmem} = $info->{max_mem};
2822 $d->{balloon} = $info->{actual};
2823
2824 if (defined($info->{total_mem}) && defined($info->{free_mem})) {
2825 $d->{mem} = $info->{total_mem} - $info->{free_mem};
2826 $d->{freemem} = $info->{free_mem};
64e7fcf2
DM
2827 }
2828
604ea644 2829 $d->{ballooninfo} = $info;
64e7fcf2
DM
2830 };
2831
03a33f30
DM
2832 my $blockstatscb = sub {
2833 my ($vmid, $resp) = @_;
2834 my $data = $resp->{'return'} || [];
2835 my $totalrdbytes = 0;
2836 my $totalwrbytes = 0;
604ea644 2837
03a33f30
DM
2838 for my $blockstat (@$data) {
2839 $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
2840 $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
604ea644
AD
2841
2842 $blockstat->{device} =~ s/drive-//;
2843 $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
03a33f30
DM
2844 }
2845 $res->{$vmid}->{diskread} = $totalrdbytes;
2846 $res->{$vmid}->{diskwrite} = $totalwrbytes;
2847 };
2848
949112c3
FE
2849 my $machinecb = sub {
2850 my ($vmid, $resp) = @_;
2851 my $data = $resp->{'return'} || [];
2852
2853 $res->{$vmid}->{'running-machine'} =
2854 PVE::QemuServer::Machine::current_from_query_machines($data);
2855 };
2856
2857 my $versioncb = sub {
2858 my ($vmid, $resp) = @_;
2859 my $data = $resp->{'return'} // {};
2860 my $version = 'unknown';
2861
2862 if (my $v = $data->{qemu}) {
2863 $version = $v->{major} . "." . $v->{minor} . "." . $v->{micro};
2864 }
2865
2866 $res->{$vmid}->{'running-qemu'} = $version;
2867 };
2868
03a33f30
DM
2869 my $statuscb = sub {
2870 my ($vmid, $resp) = @_;
64e7fcf2 2871
03a33f30 2872 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
949112c3
FE
2873 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
2874 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
64e7fcf2
DM
2875 # this fails if ballon driver is not loaded, so this must be
2876 # the last commnand (following command are aborted if this fails).
38babf81 2877 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
03a33f30
DM
2878
2879 my $status = 'unknown';
2880 if (!defined($status = $resp->{'return'}->{status})) {
2881 warn "unable to get VM status\n";
2882 return;
2883 }
2884
2885 $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
2886 };
2887
2888 foreach my $vmid (keys %$list) {
2889 next if $opt_vmid && ($vmid ne $opt_vmid);
2890 next if !$res->{$vmid}->{pid}; # not running
2891 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2892 }
2893
b017fbda 2894 $qmpclient->queue_execute(undef, 2);
03a33f30 2895
6891fd70
SR
2896 foreach my $vmid (keys %$list) {
2897 next if $opt_vmid && ($vmid ne $opt_vmid);
e5b18771
FG
2898 next if !$res->{$vmid}->{pid}; #not running
2899
6891fd70
SR
2900 # we can't use the $qmpclient since it might have already aborted on
2901 # 'query-balloon', but this might also fail for older versions...
2902 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
2903 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
2904 }
2905
03a33f30
DM
2906 foreach my $vmid (keys %$list) {
2907 next if $opt_vmid && ($vmid ne $opt_vmid);
2908 $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
2909 }
2910
1e3baf05
DM
2911 return $res;
2912}
2913
8107b378
DC
2914sub conf_has_serial {
2915 my ($conf) = @_;
2916
2917 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2918 if ($conf->{"serial$i"}) {
2919 return 1;
2920 }
2921 }
2922
2923 return 0;
2924}
2925
d5535a00
TL
2926sub conf_has_audio {
2927 my ($conf, $id) = @_;
2928
2929 $id //= 0;
2930 my $audio = $conf->{"audio$id"};
d1c1af4b 2931 return if !defined($audio);
d5535a00 2932
4df98f2f 2933 my $audioproperties = parse_property_string($audio_fmt, $audio);
d5535a00
TL
2934 my $audiodriver = $audioproperties->{driver} // 'spice';
2935
2936 return {
2937 dev => $audioproperties->{device},
b0f96836 2938 dev_id => "audiodev$id",
d5535a00
TL
2939 backend => $audiodriver,
2940 backend_id => "$audiodriver-backend${id}",
2941 };
2942}
2943
b01de199 2944sub audio_devs {
1cc5ed1b 2945 my ($audio, $audiopciaddr, $machine_version) = @_;
b01de199
TL
2946
2947 my $devs = [];
2948
2949 my $id = $audio->{dev_id};
1cc5ed1b
AL
2950 my $audiodev = "";
2951 if (min_version($machine_version, 4, 2)) {
2952 $audiodev = ",audiodev=$audio->{backend_id}";
2953 }
b01de199
TL
2954
2955 if ($audio->{dev} eq 'AC97') {
1cc5ed1b 2956 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
b01de199
TL
2957 } elsif ($audio->{dev} =~ /intel\-hda$/) {
2958 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
1cc5ed1b
AL
2959 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
2960 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
b01de199
TL
2961 } else {
2962 die "unkown audio device '$audio->{dev}', implement me!";
2963 }
2964
2965 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2966
2967 return $devs;
2968}
2969
f9dde219
SR
2970sub get_tpm_paths {
2971 my ($vmid) = @_;
2972 return {
2973 socket => "/var/run/qemu-server/$vmid.swtpm",
2974 pid => "/var/run/qemu-server/$vmid.swtpm.pid",
2975 };
2976}
2977
2978sub add_tpm_device {
2979 my ($vmid, $devices, $conf) = @_;
2980
2981 return if !$conf->{tpmstate0};
2982
2983 my $paths = get_tpm_paths($vmid);
2984
2985 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
2986 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
2987 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
2988}
2989
2990sub start_swtpm {
2991 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
2992
2993 return if !$tpmdrive;
2994
2995 my $state;
2996 my $tpm = parse_drive("tpmstate0", $tpmdrive);
2997 my ($storeid, $volname) = PVE::Storage::parse_volume_id($tpm->{file}, 1);
2998 if ($storeid) {
2999 $state = PVE::Storage::map_volume($storecfg, $tpm->{file});
3000 } else {
3001 $state = $tpm->{file};
3002 }
3003
3004 my $paths = get_tpm_paths($vmid);
3005
3006 # during migration, we will get state from remote
3007 #
3008 if (!$migration) {
3009 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3010 my $setup_cmd = [
3011 "swtpm_setup",
3012 "--tpmstate",
3013 "file://$state",
3014 "--createek",
3015 "--create-ek-cert",
3016 "--create-platform-cert",
3017 "--lock-nvram",
3018 "--config",
3019 "/etc/swtpm_setup.conf", # do not use XDG configs
3020 "--runas",
3021 "0", # force creation as root, error if not possible
3022 "--not-overwrite", # ignore existing state, do not modify
3023 ];
3024
3025 push @$setup_cmd, "--tpm2" if $tpm->{version} eq 'v2.0';
3026 # TPM 2.0 supports ECC crypto, use if possible
3027 push @$setup_cmd, "--ecc" if $tpm->{version} eq 'v2.0';
3028
3029 run_command($setup_cmd, outfunc => sub {
3030 print "swtpm_setup: $1\n";
3031 });
3032 }
3033
3034 my $emulator_cmd = [
3035 "swtpm",
3036 "socket",
3037 "--tpmstate",
3038 "backend-uri=file://$state,mode=0600",
3039 "--ctrl",
3040 "type=unixio,path=$paths->{socket},mode=0600",
3041 "--pid",
3042 "file=$paths->{pid}",
3043 "--terminate", # terminate on QEMU disconnect
3044 "--daemon",
3045 ];
3046 push @$emulator_cmd, "--tpm2" if $tpm->{version} eq 'v2.0';
3047 run_command($emulator_cmd, outfunc => sub { print $1; });
3048
3049 # return untainted PID of swtpm daemon so it can be killed on error
3050 file_read_firstline($paths->{pid}) =~ m/(\d+)/;
3051 return $1;
3052}
3053
86b8228b
DM
3054sub vga_conf_has_spice {
3055 my ($vga) = @_;
3056
55655ebc
DC
3057 my $vgaconf = parse_vga($vga);
3058 my $vgatype = $vgaconf->{type};
3059 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
590e698c
DM
3060
3061 return $1 || 1;
86b8228b
DM
3062}
3063
d731ecbe
WB
3064sub is_native($) {
3065 my ($arch) = @_;
3066 return get_host_arch() eq $arch;
3067}
3068
045749f2
TL
3069sub get_vm_arch {
3070 my ($conf) = @_;
3071 return $conf->{arch} // get_host_arch();
3072}
3073
d731ecbe
WB
3074my $default_machines = {
3075 x86_64 => 'pc',
3076 aarch64 => 'virt',
3077};
3078
0761e619
TL
3079sub get_installed_machine_version {
3080 my ($kvmversion) = @_;
3081 $kvmversion = kvm_user_version() if !defined($kvmversion);
3082 $kvmversion =~ m/^(\d+\.\d+)/;
3083 return $1;
3084}
3085
3086sub windows_get_pinned_machine_version {
3087 my ($machine, $base_version, $kvmversion) = @_;
3088
3089 my $pin_version = $base_version;
3090 if (!defined($base_version) ||
3091 !PVE::QemuServer::Machine::can_run_pve_machine_version($base_version, $kvmversion)
3092 ) {
3093 $pin_version = get_installed_machine_version($kvmversion);
3094 }
3095 if (!$machine || $machine eq 'pc') {
3096 $machine = "pc-i440fx-$pin_version";
3097 } elsif ($machine eq 'q35') {
3098 $machine = "pc-q35-$pin_version";
3099 } elsif ($machine eq 'virt') {
3100 $machine = "virt-$pin_version";
3101 } else {
3102 warn "unknown machine type '$machine', not touching that!\n";
3103 }
3104
3105 return $machine;
3106}
3107
045749f2 3108sub get_vm_machine {
ac0077cc 3109 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
045749f2
TL
3110
3111 my $machine = $forcemachine || $conf->{machine};
d731ecbe 3112
9471e48b 3113 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
4dd1e83c
TL
3114 $kvmversion //= kvm_user_version();
3115 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3116 # layout which confuses windows quite a bit and may result in various regressions..
3117 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3118 if (windows_version($conf->{ostype})) {
0761e619 3119 $machine = windows_get_pinned_machine_version($machine, '5.1', $kvmversion);
4dd1e83c 3120 }
045749f2
TL
3121 $arch //= 'x86_64';
3122 $machine ||= $default_machines->{$arch};
ac0077cc 3123 if ($add_pve_version) {
ac0077cc
SR
3124 my $pvever = PVE::QemuServer::Machine::get_pve_version($kvmversion);
3125 $machine .= "+pve$pvever";
3126 }
3127 }
3128
d4be7f31
SR
3129 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3130 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3131 $machine = $1 if $is_pxe;
3132
ac0077cc
SR
3133 # for version-pinned machines that do not include a pve-version (e.g.
3134 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3135 $machine .= '+pve0';
d4be7f31
SR
3136
3137 $machine .= '.pxe' if $is_pxe;
045749f2
TL
3138 }
3139
3140 return $machine;
d731ecbe
WB
3141}
3142
96ed3574
WB
3143sub get_ovmf_files($) {
3144 my ($arch) = @_;
3145
3146 my $ovmf = $OVMF->{$arch}
3147 or die "no OVMF images known for architecture '$arch'\n";
3148
3149 return @$ovmf;
3150}
3151
6908fd9b
WB
3152my $Arch2Qemu = {
3153 aarch64 => '/usr/bin/qemu-system-aarch64',
3154 x86_64 => '/usr/bin/qemu-system-x86_64',
3155};
3156sub get_command_for_arch($) {
3157 my ($arch) = @_;
3158 return '/usr/bin/kvm' if is_native($arch);
3159
3160 my $cmd = $Arch2Qemu->{$arch}
3161 or die "don't know how to emulate architecture '$arch'\n";
3162 return $cmd;
3163}
3164
05a4c550
SR
3165# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3166# to use in a QEMU command line (-cpu element), first array_intersect the result
3167# of query_supported_ with query_understood_. This is necessary because:
3168#
3169# a) query_understood_ returns flags the host cannot use and
3170# b) query_supported_ (rather the QMP call) doesn't actually return CPU
3171# flags, but CPU settings - with most of them being flags. Those settings
3172# (and some flags, curiously) cannot be specified as a "-cpu" argument.
3173#
3174# query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3175# expensive. If you need the value returned from this, you can get it much
3176# cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3177# $accel being 'kvm' or 'tcg'.
3178#
3179# pvestatd calls this function on startup and whenever the QEMU/KVM version
3180# changes, automatically populating pmxcfs.
3181#
3182# Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3183# since kvm and tcg machines support different flags
3184#
3185sub query_supported_cpu_flags {
52cffab6 3186 my ($arch) = @_;
05a4c550 3187
52cffab6
SR
3188 $arch //= get_host_arch();
3189 my $default_machine = $default_machines->{$arch};
3190
3191 my $flags = {};
05a4c550
SR
3192
3193 # FIXME: Once this is merged, the code below should work for ARM as well:
3194 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3195 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3196 $arch eq "aarch64";
3197
3198 my $kvm_supported = defined(kvm_version());
3199 my $qemu_cmd = get_command_for_arch($arch);
3200 my $fakevmid = -1;
3201 my $pidfile = PVE::QemuServer::Helpers::pidfile_name($fakevmid);
3202
3203 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3204 my $query_supported_run_qemu = sub {
3205 my ($kvm) = @_;
3206
3207 my $flags = {};
3208 my $cmd = [
3209 $qemu_cmd,
3210 '-machine', $default_machine,
3211 '-display', 'none',
378ad769 3212 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
05a4c550
SR
3213 '-mon', 'chardev=qmp,mode=control',
3214 '-pidfile', $pidfile,
3215 '-S', '-daemonize'
3216 ];
3217
3218 if (!$kvm) {
3219 push @$cmd, '-accel', 'tcg';
3220 }
3221
3222 my $rc = run_command($cmd, noerr => 1, quiet => 0);
3223 die "QEMU flag querying VM exited with code " . $rc if $rc;
3224
3225 eval {
3226 my $cmd_result = mon_cmd(
3227 $fakevmid,
3228 'query-cpu-model-expansion',
3229 type => 'full',
3230 model => { name => 'host' }
3231 );
3232
3233 my $props = $cmd_result->{model}->{props};
3234 foreach my $prop (keys %$props) {
3235 next if $props->{$prop} ne '1';
3236 # QEMU returns some flags multiple times, with '_', '.' or '-'
3237 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3238 # We only keep those with underscores, to match /proc/cpuinfo
3239 $prop =~ s/\.|-/_/g;
3240 $flags->{$prop} = 1;
3241 }
3242 };
3243 my $err = $@;
3244
3245 # force stop with 10 sec timeout and 'nocheck'
3246 # always stop, even if QMP failed
3247 vm_stop(undef, $fakevmid, 1, 1, 10, 0, 1);
3248
3249 die $err if $err;
3250
3251 return [ sort keys %$flags ];
3252 };
3253
3254 # We need to query QEMU twice, since KVM and TCG have different supported flags
3255 PVE::QemuConfig->lock_config($fakevmid, sub {
3256 $flags->{tcg} = eval { $query_supported_run_qemu->(0) };
3257 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3258
3259 if ($kvm_supported) {
3260 $flags->{kvm} = eval { $query_supported_run_qemu->(1) };
3261 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3262 }
3263 });
3264
3265 return $flags;
3266}
3267
3268# Understood CPU flags are written to a file at 'pve-qemu' compile time
3269my $understood_cpu_flag_dir = "/usr/share/kvm";
3270sub query_understood_cpu_flags {
3271 my $arch = get_host_arch();
3272 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3273
3274 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3275 if ! -e $filepath;
3276
3277 my $raw = file_get_contents($filepath);
3278 $raw =~ s/^\s+|\s+$//g;
3279 my @flags = split(/\s+/, $raw);
3280
3281 return \@flags;
3282}
3283
d3f9db4d
TL
3284my sub get_cpuunits {
3285 my ($conf) = @_;
3286 return $conf->{cpuunits} // (PVE::CGroup::cgroup_mode() == 2 ? 100 : 1024);
3287}
1e3baf05 3288sub config_to_command {
5921764c
SR
3289 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3290 $pbs_backing) = @_;
1e3baf05
DM
3291
3292 my $cmd = [];
8c559505
DM
3293 my $globalFlags = [];
3294 my $machineFlags = [];
3295 my $rtcFlags = [];
5bdcf937 3296 my $devices = [];
b78ebef7 3297 my $pciaddr = '';
5bdcf937 3298 my $bridges = {};
b42d3cf9 3299 my $ostype = $conf->{ostype};
4317f69f 3300 my $winversion = windows_version($ostype);
d731ecbe 3301 my $kvm = $conf->{kvm};
38277afc 3302 my $nodename = nodename();
d731ecbe 3303
045749f2 3304 my $arch = get_vm_arch($conf);
1476b99f
DC
3305 my $kvm_binary = get_command_for_arch($arch);
3306 my $kvmver = kvm_user_version($kvm_binary);
045749f2 3307
a04dd5c4
SR
3308 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3309 $kvmver //= "undefined";
3310 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3311 }
3312
9471e48b
TL
3313 my $add_pve_version = min_version($kvmver, 4, 1);
3314
3315 my $machine_type = get_vm_machine($conf, $forcemachine, $arch, $add_pve_version);
4df98f2f 3316 my $machine_version = extract_version($machine_type, $kvmver);
d731ecbe 3317 $kvm //= 1 if is_native($arch);
4317f69f 3318
a77a53ae 3319 $machine_version =~ m/(\d+)\.(\d+)/;
ac0077cc 3320 my ($machine_major, $machine_minor) = ($1, $2);
ac0077cc 3321
b516c848
SR
3322 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3323 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3324 } elsif (!min_version($kvmver, $machine_major, $machine_minor)) {
4df98f2f
TL
3325 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3326 ." please upgrade node '$nodename'\n"
b516c848 3327 } elsif (!PVE::QemuServer::Machine::can_run_pve_machine_version($machine_version, $kvmver)) {
ac0077cc 3328 my $max_pve_version = PVE::QemuServer::Machine::get_pve_version($machine_version);
4df98f2f
TL
3329 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3330 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3331 ." node '$nodename'\n";
ac0077cc
SR
3332 }
3333
3334 # if a specific +pve version is required for a feature, use $version_guard
3335 # instead of min_version to allow machines to be run with the minimum
3336 # required version
3337 my $required_pve_version = 0;
3338 my $version_guard = sub {
3339 my ($major, $minor, $pve) = @_;
3340 return 0 if !min_version($machine_version, $major, $minor, $pve);
47f35977
SR
3341 my $max_pve = PVE::QemuServer::Machine::get_pve_version("$major.$minor");
3342 return 1 if min_version($machine_version, $major, $minor, $max_pve+1);
ac0077cc
SR
3343 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3344 return 1;
3345 };
a77a53ae 3346
4df98f2f
TL
3347 if ($kvm && !defined kvm_version()) {
3348 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3349 ." or enable in BIOS.\n";
d731ecbe 3350 }
bfcd9b7e 3351
3392d6ca 3352 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
4d3f29ed 3353 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
249c4a6c
AD
3354 my $use_old_bios_files = undef;
3355 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
db656e5f 3356
d3f9db4d 3357 my $cpuunits = get_cpuunits($conf);
f08e17c7 3358
1476b99f 3359 push @$cmd, $kvm_binary;
1e3baf05
DM
3360
3361 push @$cmd, '-id', $vmid;
3362
e4d4cda1
HR
3363 my $vmname = $conf->{name} || "vm$vmid";
3364
3365 push @$cmd, '-name', $vmname;
3366
27b25d03
SR
3367 push @$cmd, '-no-shutdown';
3368
1e3baf05
DM
3369 my $use_virtio = 0;
3370
d036e418 3371 my $qmpsocket = PVE::QemuServer::Helpers::qmp_socket($vmid);
378ad769 3372 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
c971c4f2
AD
3373 push @$cmd, '-mon', "chardev=qmp,mode=control";
3374
2ea5fb7e 3375 if (min_version($machine_version, 2, 12)) {
b4496b9e 3376 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
71bd73b5
DC
3377 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3378 }
1e3baf05 3379
d036e418 3380 push @$cmd, '-pidfile' , PVE::QemuServer::Helpers::pidfile_name($vmid);
19672434 3381
1e3baf05
DM
3382 push @$cmd, '-daemonize';
3383
2796e7d5 3384 if ($conf->{smbios1}) {
1f30ac3a
CE
3385 my $smbios_conf = parse_smbios1($conf->{smbios1});
3386 if ($smbios_conf->{base64}) {
3387 # Do not pass base64 flag to qemu
3388 delete $smbios_conf->{base64};
3389 my $smbios_string = "";
3390 foreach my $key (keys %$smbios_conf) {
3391 my $value;
3392 if ($key eq "uuid") {
3393 $value = $smbios_conf->{uuid}
3394 } else {
3395 $value = decode_base64($smbios_conf->{$key});
3396 }
3397 # qemu accepts any binary data, only commas need escaping by double comma
3398 $value =~ s/,/,,/g;
3399 $smbios_string .= "," . $key . "=" . $value if $value;
3400 }
3401 push @$cmd, '-smbios', "type=1" . $smbios_string;
3402 } else {
3403 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3404 }
2796e7d5
DM
3405 }
3406
3edb45e7 3407 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
818c3b8d
TL
3408 my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch);
3409 die "uefi base image '$ovmf_code' not found\n" if ! -f $ovmf_code;
2ddc0a5c 3410
818c3b8d 3411 my ($path, $format);
b4dc6475 3412 my $read_only_str = '';
b57d4863
SR
3413 if (my $efidisk = $conf->{efidisk0}) {
3414 my $d = parse_drive('efidisk0', $efidisk);
2ddc0a5c 3415 my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
13bca7b4 3416 $format = $d->{format};
2ddc0a5c
DC
3417 if ($storeid) {
3418 $path = PVE::Storage::path($storecfg, $d->{file});
13bca7b4
WB
3419 if (!defined($format)) {
3420 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3421 $format = qemu_img_format($scfg, $volname);
3422 }
2ddc0a5c
DC
3423 } else {
3424 $path = $d->{file};
13bca7b4
WB
3425 die "efidisk format must be specified\n"
3426 if !defined($format);
2ddc0a5c 3427 }
b4dc6475
FG
3428
3429 $read_only_str = ',readonly=on' if drive_is_read_only($conf, $d);
2ddc0a5c 3430 } else {
4dcce9ee
TL
3431 warn "no efidisk configured! Using temporary efivars disk.\n";
3432 $path = "/tmp/$vmid-ovmf.fd";
96ed3574 3433 PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
13bca7b4 3434 $format = 'raw';
2ddc0a5c 3435 }
4dcce9ee 3436
818ce80e
DC
3437 my $size_str = "";
3438
3439 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3440 $size_str = ",size=" . (-s $ovmf_vars);
3441 }
3442
738dc81c
TL
3443 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3444 my $cache = "";
3445 if ($path =~ m/^rbd:/) {
3446 $cache = ',cache=writeback';
3447 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3448 }
6aaad230 3449
378ad769 3450 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
b4dc6475 3451 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
a783c78e
AD
3452 }
3453
7583d156
DC
3454 # load q35 config
3455 if ($q35) {
3456 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
2ea5fb7e 3457 if (min_version($machine_version, 4, 0)) {
7583d156
DC
3458 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3459 } else {
3460 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3461 }
3462 }
da8b4189 3463
844d8fa6
DC
3464 if ($conf->{vmgenid}) {
3465 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3466 }
3467
d40e5e18 3468 # add usb controllers
4df98f2f
TL
3469 my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers(
3470 $conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
d40e5e18 3471 push @$devices, @usbcontrollers if @usbcontrollers;
55655ebc 3472 my $vga = parse_vga($conf->{vga});
2fa3151e 3473
55655ebc
DC
3474 my $qxlnum = vga_conf_has_spice($conf->{vga});
3475 $vga->{type} = 'qxl' if $qxlnum;
2fa3151e 3476
55655ebc 3477 if (!$vga->{type}) {
869ad4a7
WB
3478 if ($arch eq 'aarch64') {
3479 $vga->{type} = 'virtio';
2ea5fb7e 3480 } elsif (min_version($machine_version, 2, 9)) {
55655ebc 3481 $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3482 } else {
55655ebc 3483 $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3484 }
5acbfe9e
DM
3485 }
3486
1e3baf05 3487 # enable absolute mouse coordinates (needed by vnc)
5acbfe9e
DM
3488 my $tablet;
3489 if (defined($conf->{tablet})) {
3490 $tablet = $conf->{tablet};
3491 } else {
3492 $tablet = $defaults->{tablet};
590e698c 3493 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
55655ebc 3494 $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
5acbfe9e
DM
3495 }
3496
d559309f
WB
3497 if ($tablet) {
3498 push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
3499 my $kbd = print_keyboarddevice_full($conf, $arch);
3500 push @$devices, '-device', $kbd if defined($kbd);
3501 }
b467f79a 3502
e5d611c3 3503 my $bootorder = device_bootorder($conf);
2141a802 3504
74c17b7a 3505 # host pci device passthrough
13d68979 3506 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE::QemuServer::PCI::print_hostpci_devices(
41af2dfc 3507 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
1e3baf05
DM
3508
3509 # usb devices
ae36393d 3510 my $usb_dev_features = {};
2ea5fb7e 3511 $usb_dev_features->{spice_usb3} = 1 if min_version($machine_version, 4, 0);
ae36393d 3512
4df98f2f 3513 my @usbdevices = PVE::QemuServer::USB::get_usb_devices(
2141a802 3514 $conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
d40e5e18 3515 push @$devices, @usbdevices if @usbdevices;
2141a802 3516
1e3baf05 3517 # serial devices
bae179aa 3518 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
34978be3 3519 if (my $path = $conf->{"serial$i"}) {
9f9d2fb2
DM
3520 if ($path eq 'socket') {
3521 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
378ad769 3522 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
91b01bbb
WB
3523 # On aarch64, serial0 is the UART device. Qemu only allows
3524 # connecting UART devices via the '-serial' command line, as
3525 # the device has a fixed slot on the hardware...
3526 if ($arch eq 'aarch64' && $i == 0) {
3527 push @$devices, '-serial', "chardev:serial$i";
3528 } else {
3529 push @$devices, '-device', "isa-serial,chardev=serial$i";
3530 }
9f9d2fb2
DM
3531 } else {
3532 die "no such serial device\n" if ! -c $path;
3533 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3534 push @$devices, '-device', "isa-serial,chardev=serial$i";
3535 }
34978be3 3536 }
1e3baf05
DM
3537 }
3538
3539 # parallel devices
1989a89c 3540 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
34978be3 3541 if (my $path = $conf->{"parallel$i"}) {
19672434 3542 die "no such parallel device\n" if ! -c $path;
32e69805 3543 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
4c5dbaf6 3544 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
5bdcf937 3545 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
34978be3 3546 }
1e3baf05
DM
3547 }
3548
b01de199 3549 if (min_version($machine_version, 4, 0) && (my $audio = conf_has_audio($conf))) {
2e7b5925 3550 my $audiopciaddr = print_pci_addr("audio0", $bridges, $arch, $machine_type);
1cc5ed1b 3551 my $audio_devs = audio_devs($audio, $audiopciaddr, $machine_version);
b01de199 3552 push @$devices, @$audio_devs;
2e7b5925 3553 }
19672434 3554
f9dde219
SR
3555 add_tpm_device($vmid, $devices, $conf);
3556
1e3baf05
DM
3557 my $sockets = 1;
3558 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3559 $sockets = $conf->{sockets} if $conf->{sockets};
3560
3561 my $cores = $conf->{cores} || 1;
3bd18e48 3562
de9d1e55 3563 my $maxcpus = $sockets * $cores;
76267728 3564
de9d1e55 3565 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
76267728 3566
de9d1e55
AD
3567 my $allowed_vcpus = $cpuinfo->{cpus};
3568
6965d5d1 3569 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
de9d1e55
AD
3570 if ($allowed_vcpus < $maxcpus);
3571
2ea5fb7e 3572 if($hotplug_features->{cpu} && min_version($machine_version, 2, 7)) {
1e3baf05 3573
69c81430
AD
3574 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3575 for (my $i = 2; $i <= $vcpus; $i++) {
3576 my $cpustr = print_cpu_device($conf,$i);
3577 push @$cmd, '-device', $cpustr;
3578 }
3579
3580 } else {
3581
3582 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3583 }
1e3baf05
DM
3584 push @$cmd, '-nodefaults';
3585
dbea4415 3586 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
1e3baf05 3587
6b64503e 3588 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
1e3baf05 3589
6b64503e 3590 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
1e3baf05 3591
84902837 3592 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
4df98f2f
TL
3593 push @$devices, '-device', print_vga_device(
3594 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
d036e418 3595 my $socket = PVE::QemuServer::Helpers::vnc_socket($vmid);
378ad769 3596 push @$cmd, '-vnc', "unix:$socket,password=on";
b7be4ba9 3597 } else {
55655ebc 3598 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
b7be4ba9
AD
3599 push @$cmd, '-nographic';
3600 }
3601
1e3baf05 3602 # time drift fix
6b64503e 3603 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
8c559505 3604 my $useLocaltime = $conf->{localtime};
1e3baf05 3605
4317f69f
AD
3606 if ($winversion >= 5) { # windows
3607 $useLocaltime = 1 if !defined($conf->{localtime});
7a131888 3608
4317f69f
AD
3609 # use time drift fix when acpi is enabled
3610 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3611 $tdf = 1 if !defined($conf->{tdf});
462e8d19 3612 }
4317f69f 3613 }
462e8d19 3614
4317f69f
AD
3615 if ($winversion >= 6) {
3616 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3617 push @$cmd, '-no-hpet';
1e3baf05
DM
3618 }
3619
8c559505
DM
3620 push @$rtcFlags, 'driftfix=slew' if $tdf;
3621
2f6f002c 3622 if ($conf->{startdate} && $conf->{startdate} ne 'now') {
8c559505
DM
3623 push @$rtcFlags, "base=$conf->{startdate}";
3624 } elsif ($useLocaltime) {
3625 push @$rtcFlags, 'base=localtime';
3626 }
1e3baf05 3627
58c64ad5
SR
3628 if ($forcecpu) {
3629 push @$cmd, '-cpu', $forcecpu;
3630 } else {
2f6f002c 3631 push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
58c64ad5 3632 }
519ed28c 3633
0567a4d5 3634 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3635
1e3baf05
DM
3636 push @$cmd, '-S' if $conf->{freeze};
3637
b20df606 3638 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3639
48657158
MD
3640 my $guest_agent = parse_guest_agent($conf);
3641
3642 if ($guest_agent->{enabled}) {
d036e418 3643 my $qgasocket = PVE::QemuServer::Helpers::qmp_socket($vmid, 1);
378ad769 3644 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
48657158 3645
60f03a11 3646 if (!$guest_agent->{type} || $guest_agent->{type} eq 'virtio') {
48657158
MD
3647 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
3648 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3649 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3650 } elsif ($guest_agent->{type} eq 'isa') {
3651 push @$devices, '-device', "isa-serial,chardev=qga0";
3652 }
ab6a046f
AD
3653 }
3654
e5d611c3
TL
3655 my $rng = $conf->{rng0} ? parse_rng($conf->{rng0}) : undef;
3656 if ($rng && $version_guard->(4, 1, 2)) {
05853188
SR
3657 check_rng_source($rng->{source});
3658
2cf61f33
SR
3659 my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
3660 my $period = $rng->{period} // $rng_fmt->{period}->{default};
2cf61f33
SR
3661 my $limiter_str = "";
3662 if ($max_bytes) {
3663 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3664 }
3665
2cf61f33 3666 my $rng_addr = print_pci_addr("rng0", $bridges, $arch, $machine_type);
2cf61f33
SR
3667 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3668 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3669 }
3670
1d794448 3671 my $spice_port;
2fa3151e 3672
590e698c
DM
3673 if ($qxlnum) {
3674 if ($qxlnum > 1) {
ac087616 3675 if ($winversion){
2f6f002c 3676 for (my $i = 1; $i < $qxlnum; $i++){
4df98f2f
TL
3677 push @$devices, '-device', print_vga_device(
3678 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3679 }
3680 } else {
3681 # assume other OS works like Linux
55655ebc
DC
3682 my ($ram, $vram) = ("134217728", "67108864");
3683 if ($vga->{memory}) {
3684 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3685 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3686 }
3687 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3688 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
3689 }
3690 }
3691
d559309f 3692 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 3693
af0eba7e 3694 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
3695 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3696 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4d316a63
AL
3697
3698 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3699 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3700 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3701
91152441
WB
3702 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3703 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 3704
4df98f2f
TL
3705 my $spice_enhancement_str = $conf->{spice_enhancements} // '';
3706 my $spice_enhancement = parse_property_string($spice_enhancements_fmt, $spice_enhancement_str);
caab114a
TL
3707 if ($spice_enhancement->{foldersharing}) {
3708 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3709 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3710 }
c4df18db 3711
caab114a 3712 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
4df98f2f
TL
3713 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3714 if $spice_enhancement->{videostreaming};
3715
caab114a 3716 push @$devices, '-spice', "$spice_opts";
1011b570
DM
3717 }
3718
8d9ae0d2
DM
3719 # enable balloon by default, unless explicitly disabled
3720 if (!defined($conf->{balloon}) || $conf->{balloon}) {
d559309f 3721 $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
8d9ae0d2
DM
3722 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3723 }
1e3baf05 3724
0ea9541d
DM
3725 if ($conf->{watchdog}) {
3726 my $wdopts = parse_watchdog($conf->{watchdog});
d559309f 3727 $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 3728 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
3729 push @$devices, '-device', "$watchdog$pciaddr";
3730 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
3731 }
3732
1e3baf05 3733 my $vollist = [];
941e0c42 3734 my $scsicontroller = {};
26ee04b6 3735 my $ahcicontroller = {};
cdd20088 3736 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 3737
5881b913
DM
3738 # Add iscsi initiator name if available
3739 if (my $initiator = get_initiator_name()) {
3740 push @$devices, '-iscsi', "initiator-name=$initiator";
3741 }
3742
912792e2 3743 PVE::QemuConfig->foreach_volume($conf, sub {
1e3baf05
DM
3744 my ($ds, $drive) = @_;
3745
ff1a2432 3746 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
3f11f0d7 3747 check_volume_storage_type($storecfg, $drive->{file});
1e3baf05 3748 push @$vollist, $drive->{file};
ff1a2432 3749 }
afdb31d5 3750
4dcce9ee
TL
3751 # ignore efidisk here, already added in bios/fw handling code above
3752 return if $drive->{interface} eq 'efidisk';
f9dde219
SR
3753 # similar for TPM
3754 return if $drive->{interface} eq 'tpmstate';
4dcce9ee 3755
1e3baf05 3756 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82 3757
2141a802 3758 $drive->{bootindex} = $bootorder->{$ds} if $bootorder->{$ds};
3b408e82 3759
2f6f002c 3760 if ($drive->{interface} eq 'virtio'){
51f492cd
AD
3761 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
3762 }
3763
2f6f002c 3764 if ($drive->{interface} eq 'scsi') {
cdd20088 3765
ee034f5c 3766 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 3767
b8fb1c03
SR
3768 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3769 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3770
d559309f 3771 $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 3772 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
3773
3774 my $iothread = '';
3775 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
3776 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3777 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d
DC
3778 } elsif ($drive->{iothread}) {
3779 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
fc8b40fd
AD
3780 }
3781
6e11f143
AD
3782 my $queues = '';
3783 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
3784 $queues = ",num_queues=$drive->{queues}";
370b05e7 3785 }
6e11f143 3786
4df98f2f
TL
3787 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
3788 if !$scsicontroller->{$controller};
cdd20088 3789 $scsicontroller->{$controller}=1;
2f6f002c 3790 }
3b408e82 3791
26ee04b6 3792 if ($drive->{interface} eq 'sata') {
2f6f002c
TL
3793 my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
3794 $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
4df98f2f
TL
3795 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
3796 if !$ahcicontroller->{$controller};
2f6f002c 3797 $ahcicontroller->{$controller}=1;
26ee04b6 3798 }
46f58b5f 3799
5921764c
SR
3800 my $pbs_conf = $pbs_backing->{$ds};
3801 my $pbs_name = undef;
3802 if ($pbs_conf) {
3803 $pbs_name = "drive-$ds-pbs";
3804 push @$devices, '-blockdev', print_pbs_blockdev($pbs_conf, $pbs_name);
3805 }
3806
6d5673c3
SR
3807 my $drive_cmd = print_drive_commandline_full(
3808 $storecfg, $vmid, $drive, $pbs_name, min_version($kvmver, 6, 0));
3dc33a72
FG
3809
3810 # extra protection for templates, but SATA and IDE don't support it..
75748d44 3811 $drive_cmd .= ',readonly=on' if drive_is_read_only($conf, $drive);
4ef13a7f 3812
15b21acc 3813 push @$devices, '-drive',$drive_cmd;
4df98f2f
TL
3814 push @$devices, '-device', print_drivedevice_full(
3815 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
3816 });
3817
cc4d6182 3818 for (my $i = 0; $i < $MAX_NETS; $i++) {
2141a802
SR
3819 my $netname = "net$i";
3820
3821 next if !$conf->{$netname};
3822 my $d = parse_net($conf->{$netname});
d0a86b24 3823 next if !$d;
1e3baf05 3824
d0a86b24 3825 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 3826
2141a802 3827 $d->{bootindex} = $bootorder->{$netname} if $bootorder->{$netname};
1e3baf05 3828
2141a802 3829 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, $netname);
d0a86b24 3830 push @$devices, '-netdev', $netdevfull;
5bdcf937 3831
d0a86b24 3832 my $netdevicefull = print_netdevice_full(
2141a802 3833 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
4df98f2f 3834
d0a86b24 3835 push @$devices, '-device', $netdevicefull;
5bdcf937 3836 }
1e3baf05 3837
6dbcb073 3838 if ($conf->{ivshmem}) {
4df98f2f 3839 my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 3840
6dbcb073
DC
3841 my $bus;
3842 if ($q35) {
3843 $bus = print_pcie_addr("ivshmem");
3844 } else {
3845 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
3846 }
e3c27a6a
TL
3847
3848 my $ivshmem_name = $ivshmem->{name} // $vmid;
3849 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3850
6dbcb073 3851 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4df98f2f
TL
3852 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
3853 .",size=$ivshmem->{size}M";
6dbcb073
DC
3854 }
3855
2513b862
DC
3856 # pci.4 is nested in pci.1
3857 $bridges->{1} = 1 if $bridges->{4};
3858
db656e5f
DM
3859 if (!$q35) {
3860 # add pci bridges
2ea5fb7e 3861 if (min_version($machine_version, 2, 3)) {
fc79e813
AD
3862 $bridges->{1} = 1;
3863 $bridges->{2} = 1;
3864 }
3865
6731a4cf
AD
3866 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3867
2513b862
DC
3868 }
3869
3870 for my $k (sort {$b cmp $a} keys %$bridges) {
3871 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
13d68979
SR
3872
3873 my $k_name = $k;
3874 if ($k == 2 && $legacy_igd) {
3875 $k_name = "$k-igd";
3876 }
3877 $pciaddr = print_pci_addr("pci.$k_name", undef, $arch, $machine_type);
3878
2513b862
DC
3879 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3880 if ($q35) {
3881 # add after -readconfig pve-q35.cfg
3882 splice @$devices, 2, 0, '-device', $devstr;
3883 } else {
3884 unshift @$devices, '-device', $devstr if $k > 0;
f8e83f05 3885 }
19672434
DM
3886 }
3887
ac0077cc
SR
3888 if (!$kvm) {
3889 push @$machineFlags, 'accel=tcg';
3890 }
3891
3892 my $machine_type_min = $machine_type;
3893 if ($add_pve_version) {
3894 $machine_type_min =~ s/\+pve\d+$//;
3895 $machine_type_min .= "+pve$required_pve_version";
3896 }
3897 push @$machineFlags, "type=${machine_type_min}";
3898
5bdcf937 3899 push @$cmd, @$devices;
2f6f002c
TL
3900 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
3901 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
3902 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
8c559505 3903
7ceade4c
DC
3904 if (my $vmstate = $conf->{vmstate}) {
3905 my $statepath = PVE::Storage::path($storecfg, $vmstate);
24d1f93a 3906 push @$vollist, $vmstate;
7ceade4c 3907 push @$cmd, '-loadstate', $statepath;
b85666cf 3908 print "activating and using '$vmstate' as vmstate\n";
7ceade4c
DC
3909 }
3910
85fcf79e
FG
3911 if (PVE::QemuConfig->is_template($conf)) {
3912 # needed to workaround base volumes being read-only
3913 push @$cmd, '-snapshot';
3914 }
3915
76350670
DC
3916 # add custom args
3917 if ($conf->{args}) {
3918 my $aa = PVE::Tools::split_args($conf->{args});
3919 push @$cmd, @$aa;
3920 }
3921
1d794448 3922 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 3923}
19672434 3924
05853188
SR
3925sub check_rng_source {
3926 my ($source) = @_;
3927
3928 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3929 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
3930 if ! -e $source;
3931
3932 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
3933 if ($source eq '/dev/hwrng' && file_read_firstline($rng_current) eq 'none') {
4df98f2f
TL
3934 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
3935 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
3936 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
3937 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
3938 ." to the host.\n";
05853188
SR
3939 }
3940}
3941
943340a6 3942sub spice_port {
1011b570 3943 my ($vmid) = @_;
943340a6 3944
0a13e08e 3945 my $res = mon_cmd($vmid, 'query-spice');
943340a6
DM
3946
3947 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
3948}
3949
86fdcfb2
DA
3950sub vm_devices_list {
3951 my ($vmid) = @_;
3952
0a13e08e 3953 my $res = mon_cmd($vmid, 'query-pci');
f721624b 3954 my $devices_to_check = [];
ceea9078
DM
3955 my $devices = {};
3956 foreach my $pcibus (@$res) {
f721624b
DC
3957 push @$devices_to_check, @{$pcibus->{devices}},
3958 }
3959
3960 while (@$devices_to_check) {
3961 my $to_check = [];
3962 for my $d (@$devices_to_check) {
3963 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3964 next if !$d->{'pci_bridge'};
3965
3966 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
3967 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 3968 }
f721624b 3969 $devices_to_check = $to_check;
f78cc802
AD
3970 }
3971
0a13e08e 3972 my $resblock = mon_cmd($vmid, 'query-block');
f78cc802
AD
3973 foreach my $block (@$resblock) {
3974 if($block->{device} =~ m/^drive-(\S+)/){
3975 $devices->{$1} = 1;
1dc4f496
DM
3976 }
3977 }
86fdcfb2 3978
0a13e08e 3979 my $resmice = mon_cmd($vmid, 'query-mice');
3d7389fe
DM
3980 foreach my $mice (@$resmice) {
3981 if ($mice->{name} eq 'QEMU HID Tablet') {
3982 $devices->{tablet} = 1;
3983 last;
3984 }
3985 }
3986
deb091c5
DC
3987 # for usb devices there is no query-usb
3988 # but we can iterate over the entries in
3989 # qom-list path=/machine/peripheral
0a13e08e 3990 my $resperipheral = mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
deb091c5
DC
3991 foreach my $per (@$resperipheral) {
3992 if ($per->{name} =~ m/^usb\d+$/) {
3993 $devices->{$per->{name}} = 1;
3994 }
3995 }
3996
1dc4f496 3997 return $devices;
86fdcfb2
DA
3998}
3999
ec21aa11 4000sub vm_deviceplug {
d559309f 4001 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 4002
3392d6ca 4003 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f 4004
95d6343b
DA
4005 my $devices_list = vm_devices_list($vmid);
4006 return 1 if defined($devices_list->{$deviceid});
4007
4df98f2f
TL
4008 # add PCI bridge if we need it for the device
4009 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
fee46675 4010
3d7389fe 4011 if ($deviceid eq 'tablet') {
fee46675 4012
d559309f
WB
4013 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
4014
4015 } elsif ($deviceid eq 'keyboard') {
4016
4017 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
3d7389fe 4018
4eb68604
DC
4019 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4020
f745762b 4021 die "usb hotplug currently not reliable\n";
50bbe377
TL
4022 # since we can't reliably hot unplug all added usb devices and usb
4023 # passthrough breaks live migration we disable usb hotplugging for now
4024 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
4eb68604 4025
fee46675 4026 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
40f28a9f 4027
22de899a
AD
4028 qemu_iothread_add($vmid, $deviceid, $device);
4029
fee46675 4030 qemu_driveadd($storecfg, $vmid, $device);
acfc6ef8 4031 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
fee46675 4032
5e5dcb73 4033 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4034 eval { qemu_deviceaddverify($vmid, $deviceid); };
4035 if (my $err = $@) {
63c2da2f
DM
4036 eval { qemu_drivedel($vmid, $deviceid); };
4037 warn $@ if $@;
fee46675 4038 die $err;
5e5dcb73 4039 }
cfc817c7 4040
2733141c 4041 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
fee46675 4042
fc8b40fd 4043
cdd20088 4044 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
d559309f 4045 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 4046 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c
AD
4047
4048 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 4049
fc8b40fd
AD
4050 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
4051 qemu_iothread_add($vmid, $deviceid, $device);
4052 $devicefull .= ",iothread=iothread-$deviceid";
4053 }
4054
6e11f143
AD
4055 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
4056 $devicefull .= ",num_queues=$device->{queues}";
4057 }
4058
cfc817c7 4059 qemu_deviceadd($vmid, $devicefull);
fee46675 4060 qemu_deviceaddverify($vmid, $deviceid);
cfc817c7 4061
fee46675
DM
4062 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4063
d559309f 4064 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 4065 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 4066
acfc6ef8 4067 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
fee46675
DM
4068 eval { qemu_deviceadd($vmid, $devicefull); };
4069 if (my $err = $@) {
63c2da2f
DM
4070 eval { qemu_drivedel($vmid, $deviceid); };
4071 warn $@ if $@;
fee46675 4072 die $err;
a4f091a0 4073 }
a4f091a0 4074
fee46675
DM
4075 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4076
d1c1af4b 4077 return if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 4078
3392d6ca 4079 my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
95d3be58
DC
4080 my $use_old_bios_files = undef;
4081 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 4082
4df98f2f
TL
4083 my $netdevicefull = print_netdevice_full(
4084 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
95d3be58 4085 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
4086 eval {
4087 qemu_deviceaddverify($vmid, $deviceid);
4088 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
4089 };
fee46675
DM
4090 if (my $err = $@) {
4091 eval { qemu_netdevdel($vmid, $deviceid); };
4092 warn $@ if $@;
4093 die $err;
95d3be58 4094 }
2630d2a9 4095
fee46675 4096 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
b467f79a 4097
40f28a9f 4098 my $bridgeid = $2;
d559309f 4099 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 4100 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 4101
40f28a9f 4102 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4103 qemu_deviceaddverify($vmid, $deviceid);
4104
4105 } else {
a1b7d579 4106 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
4107 }
4108
5e5dcb73 4109 return 1;
a4dea331
DA
4110}
4111
3eec5767 4112# fixme: this should raise exceptions on error!
ec21aa11 4113sub vm_deviceunplug {
f19d1c47 4114 my ($vmid, $conf, $deviceid) = @_;
873c2d69 4115
95d6343b
DA
4116 my $devices_list = vm_devices_list($vmid);
4117 return 1 if !defined($devices_list->{$deviceid});
4118
2141a802
SR
4119 my $bootdisks = PVE::QemuServer::Drive::get_bootdisks($conf);
4120 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
63c2da2f 4121
d559309f 4122 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3d7389fe 4123 qemu_devicedel($vmid, $deviceid);
4eb68604 4124 } elsif ($deviceid =~ m/^usb\d+$/) {
f745762b 4125 die "usb hotplug currently not reliable\n";
50bbe377
TL
4126 # when unplugging usb devices this way, there may be remaining usb
4127 # controllers/hubs so we disable it for now
4128 #qemu_devicedel($vmid, $deviceid);
4129 #qemu_devicedelverify($vmid, $deviceid);
63c2da2f 4130 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
9a66c311 4131 my $device = parse_drive($deviceid, $conf->{$deviceid});
f19d1c47 4132
a8d0fec3
TL
4133 qemu_devicedel($vmid, $deviceid);
4134 qemu_devicedelverify($vmid, $deviceid);
4135 qemu_drivedel($vmid, $deviceid);
9a66c311 4136 qemu_iothread_del($vmid, $deviceid, $device);
2733141c 4137 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
63c2da2f 4138 qemu_devicedel($vmid, $deviceid);
8ce30dde 4139 qemu_devicedelverify($vmid, $deviceid);
63c2da2f 4140 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
9a66c311 4141 my $device = parse_drive($deviceid, $conf->{$deviceid});
cfc817c7 4142
a8d0fec3
TL
4143 qemu_devicedel($vmid, $deviceid);
4144 qemu_drivedel($vmid, $deviceid);
a1b7d579 4145 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 4146
9a66c311
FG
4147 qemu_iothread_del($vmid, "virtioscsi$device->{index}", $device)
4148 if $conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single');
63c2da2f 4149 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a8d0fec3
TL
4150 qemu_devicedel($vmid, $deviceid);
4151 qemu_devicedelverify($vmid, $deviceid);
4152 qemu_netdevdel($vmid, $deviceid);
63c2da2f
DM
4153 } else {
4154 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
4155 }
4156
5e5dcb73
DA
4157 return 1;
4158}
4159
4160sub qemu_deviceadd {
4161 my ($vmid, $devicefull) = @_;
873c2d69 4162
d695b5b7
AD
4163 $devicefull = "driver=".$devicefull;
4164 my %options = split(/[=,]/, $devicefull);
f19d1c47 4165
0a13e08e 4166 mon_cmd($vmid, "device_add" , %options);
5e5dcb73 4167}
afdb31d5 4168
5e5dcb73 4169sub qemu_devicedel {
fee46675 4170 my ($vmid, $deviceid) = @_;
63c2da2f 4171
0a13e08e 4172 my $ret = mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
4173}
4174
22de899a 4175sub qemu_iothread_add {
a8d0fec3 4176 my ($vmid, $deviceid, $device) = @_;
22de899a
AD
4177
4178 if ($device->{iothread}) {
4179 my $iothreads = vm_iothreads_list($vmid);
4180 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4181 }
4182}
4183
4184sub qemu_iothread_del {
a8d0fec3 4185 my ($vmid, $deviceid, $device) = @_;
22de899a 4186
22de899a
AD
4187 if ($device->{iothread}) {
4188 my $iothreads = vm_iothreads_list($vmid);
4189 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4190 }
4191}
4192
4d3f29ed 4193sub qemu_objectadd {
a8d0fec3 4194 my ($vmid, $objectid, $qomtype) = @_;
4d3f29ed 4195
0a13e08e 4196 mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4d3f29ed
AD
4197
4198 return 1;
4199}
4200
4201sub qemu_objectdel {
a8d0fec3 4202 my ($vmid, $objectid) = @_;
4d3f29ed 4203
0a13e08e 4204 mon_cmd($vmid, "object-del", id => $objectid);
4d3f29ed
AD
4205
4206 return 1;
4207}
4208
5e5dcb73 4209sub qemu_driveadd {
fee46675 4210 my ($storecfg, $vmid, $device) = @_;
5e5dcb73 4211
6d5673c3
SR
4212 my $kvmver = get_running_qemu_version($vmid);
4213 my $io_uring = min_version($kvmver, 6, 0);
4214 my $drive = print_drive_commandline_full($storecfg, $vmid, $device, undef, $io_uring);
7a69fc3c 4215 $drive =~ s/\\/\\\\/g;
0a13e08e 4216 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_add auto \"$drive\"");
fee46675 4217
5e5dcb73 4218 # If the command succeeds qemu prints: "OK"
fee46675
DM
4219 return 1 if $ret =~ m/OK/s;
4220
4221 die "adding drive failed: $ret\n";
5e5dcb73 4222}
afdb31d5 4223
5e5dcb73 4224sub qemu_drivedel {
a8d0fec3 4225 my ($vmid, $deviceid) = @_;
873c2d69 4226
0a13e08e 4227 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-$deviceid");
5e5dcb73 4228 $ret =~ s/^\s+//;
a1b7d579 4229
63c2da2f 4230 return 1 if $ret eq "";
a1b7d579 4231
63c2da2f 4232 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
4233 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4234
63c2da2f 4235 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 4236}
f19d1c47 4237
5e5dcb73 4238sub qemu_deviceaddverify {
fee46675 4239 my ($vmid, $deviceid) = @_;
873c2d69 4240
5e5dcb73
DA
4241 for (my $i = 0; $i <= 5; $i++) {
4242 my $devices_list = vm_devices_list($vmid);
4243 return 1 if defined($devices_list->{$deviceid});
4244 sleep 1;
afdb31d5 4245 }
fee46675
DM
4246
4247 die "error on hotplug device '$deviceid'\n";
5e5dcb73 4248}
afdb31d5 4249
5e5dcb73
DA
4250
4251sub qemu_devicedelverify {
63c2da2f
DM
4252 my ($vmid, $deviceid) = @_;
4253
a1b7d579 4254 # need to verify that the device is correctly removed as device_del
63c2da2f 4255 # is async and empty return is not reliable
5e5dcb73 4256
5e5dcb73
DA
4257 for (my $i = 0; $i <= 5; $i++) {
4258 my $devices_list = vm_devices_list($vmid);
4259 return 1 if !defined($devices_list->{$deviceid});
4260 sleep 1;
afdb31d5 4261 }
63c2da2f
DM
4262
4263 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
4264}
4265
cdd20088 4266sub qemu_findorcreatescsihw {
d559309f 4267 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 4268
ee034f5c 4269 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
4270
4271 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
4272 my $devices_list = vm_devices_list($vmid);
4273
a8d0fec3 4274 if (!defined($devices_list->{$scsihwid})) {
d559309f 4275 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 4276 }
fee46675 4277
cfc817c7
DA
4278 return 1;
4279}
4280
8ce30dde
AD
4281sub qemu_deletescsihw {
4282 my ($conf, $vmid, $opt) = @_;
4283
4284 my $device = parse_drive($opt, $conf->{$opt});
4285
a1511b3c 4286 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
4287 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
4288 return 1;
4289 }
4290
ee034f5c 4291 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
4292
4293 my $devices_list = vm_devices_list($vmid);
4294 foreach my $opt (keys %{$devices_list}) {
e0fd2b2f
FE
4295 if (is_valid_drivename($opt)) {
4296 my $drive = parse_drive($opt, $conf->{$opt});
a8d0fec3 4297 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
8ce30dde
AD
4298 return 1;
4299 }
4300 }
4301 }
4302
4303 my $scsihwid="scsihw$controller";
4304
4305 vm_deviceunplug($vmid, $conf, $scsihwid);
4306
4307 return 1;
4308}
4309
281fedb3 4310sub qemu_add_pci_bridge {
d559309f 4311 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
4312
4313 my $bridges = {};
281fedb3
DM
4314
4315 my $bridgeid;
4316
d559309f 4317 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4318
4319 while (my ($k, $v) = each %$bridges) {
4320 $bridgeid = $k;
4321 }
fee46675 4322 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4323
40f28a9f
AD
4324 my $bridge = "pci.$bridgeid";
4325 my $devices_list = vm_devices_list($vmid);
4326
281fedb3 4327 if (!defined($devices_list->{$bridge})) {
d559309f 4328 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4329 }
281fedb3 4330
40f28a9f
AD
4331 return 1;
4332}
4333
25088687
DM
4334sub qemu_set_link_status {
4335 my ($vmid, $device, $up) = @_;
4336
0a13e08e 4337 mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4338 up => $up ? JSON::true : JSON::false);
4339}
4340
2630d2a9 4341sub qemu_netdevadd {
d559309f 4342 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4343
d559309f 4344 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4345 my %options = split(/[=,]/, $netdev);
2630d2a9 4346
bf5aef9b
DC
4347 if (defined(my $vhost = $options{vhost})) {
4348 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4349 }
4350
4351 if (defined(my $queues = $options{queues})) {
4352 $options{queues} = $queues + 0;
4353 }
4354
0a13e08e 4355 mon_cmd($vmid, "netdev_add", %options);
73aa03b8 4356 return 1;
2630d2a9
DA
4357}
4358
4359sub qemu_netdevdel {
4360 my ($vmid, $deviceid) = @_;
4361
0a13e08e 4362 mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4363}
4364
16521d63 4365sub qemu_usb_hotplug {
d559309f 4366 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4367
4368 return if !$device;
4369
4370 # remove the old one first
4371 vm_deviceunplug($vmid, $conf, $deviceid);
4372
4373 # check if xhci controller is necessary and available
4374 if ($device->{usb3}) {
4375
4376 my $devicelist = vm_devices_list($vmid);
4377
4378 if (!$devicelist->{xhci}) {
d559309f 4379 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4380 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4381 }
4382 }
4383 my $d = parse_usb_device($device->{host});
4384 $d->{usb3} = $device->{usb3};
4385
4386 # add the new one
d559309f 4387 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4388}
4389
838776ab 4390sub qemu_cpu_hotplug {
8edc9c08 4391 my ($vmid, $conf, $vcpus) = @_;
838776ab 4392
3392d6ca 4393 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
1e881b75 4394
8edc9c08
AD
4395 my $sockets = 1;
4396 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4397 $sockets = $conf->{sockets} if $conf->{sockets};
4398 my $cores = $conf->{cores} || 1;
4399 my $maxcpus = $sockets * $cores;
838776ab 4400
8edc9c08 4401 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4402
8edc9c08
AD
4403 die "you can't add more vcpus than maxcpus\n"
4404 if $vcpus > $maxcpus;
3a11fadb 4405
8edc9c08 4406 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4407
eba3e64d 4408 if ($vcpus < $currentvcpus) {
1e881b75 4409
2ea5fb7e 4410 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
1e881b75
AD
4411
4412 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4413 qemu_devicedel($vmid, "cpu$i");
4414 my $retry = 0;
4415 my $currentrunningvcpus = undef;
4416 while (1) {
65af8c31 4417 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
1e881b75 4418 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4419 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4420 $retry++;
4421 sleep 1;
4422 }
4423 #update conf after each succesfull cpu unplug
4424 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4425 PVE::QemuConfig->write_config($vmid, $conf);
4426 }
4427 } else {
961af8a3 4428 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4429 }
4430
4431 return;
4432 }
838776ab 4433
65af8c31 4434 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
961af8a3 4435 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4436 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4437
2ea5fb7e 4438 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
eba3e64d
AD
4439
4440 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4441 my $cpustr = print_cpu_device($conf, $i);
4442 qemu_deviceadd($vmid, $cpustr);
4443
4444 my $retry = 0;
4445 my $currentrunningvcpus = undef;
4446 while (1) {
65af8c31 4447 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
eba3e64d 4448 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4449 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4450 sleep 1;
4451 $retry++;
4452 }
4453 #update conf after each succesfull cpu hotplug
4454 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4455 PVE::QemuConfig->write_config($vmid, $conf);
4456 }
4457 } else {
4458
4459 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
0a13e08e 4460 mon_cmd($vmid, "cpu-add", id => int($i));
eba3e64d 4461 }
838776ab
AD
4462 }
4463}
4464
affd2f88 4465sub qemu_block_set_io_throttle {
277ca170
WB
4466 my ($vmid, $deviceid,
4467 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4468 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4469 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4470 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4471
f3f323a3
AD
4472 return if !check_running($vmid) ;
4473
0a13e08e 4474 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
277ca170
WB
4475 bps => int($bps),
4476 bps_rd => int($bps_rd),
4477 bps_wr => int($bps_wr),
4478 iops => int($iops),
4479 iops_rd => int($iops_rd),
4480 iops_wr => int($iops_wr),
4481 bps_max => int($bps_max),
4482 bps_rd_max => int($bps_rd_max),
4483 bps_wr_max => int($bps_wr_max),
4484 iops_max => int($iops_max),
4485 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4486 iops_wr_max => int($iops_wr_max),
4487 bps_max_length => int($bps_max_length),
4488 bps_rd_max_length => int($bps_rd_max_length),
4489 bps_wr_max_length => int($bps_wr_max_length),
4490 iops_max_length => int($iops_max_length),
4491 iops_rd_max_length => int($iops_rd_max_length),
4492 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4493 );
f3f323a3 4494
affd2f88
AD
4495}
4496
c1175c92
AD
4497sub qemu_block_resize {
4498 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4499
ed221350 4500 my $running = check_running($vmid);
c1175c92 4501
7246e8f9 4502 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4503
4504 return if !$running;
4505
375db731
FE
4506 my $padding = (1024 - $size % 1024) % 1024;
4507 $size = $size + $padding;
4508
190c8461
SR
4509 mon_cmd(
4510 $vmid,
4511 "block_resize",
4512 device => $deviceid,
4513 size => int($size),
4514 timeout => 60,
4515 );
c1175c92
AD
4516}
4517
1ab0057c
AD
4518sub qemu_volume_snapshot {
4519 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4520
ed221350 4521 my $running = check_running($vmid);
1ab0057c 4522
e5eaa028 4523 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
0a13e08e 4524 mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4525 } else {
4526 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4527 }
1ab0057c
AD
4528}
4529
fc46aff9
AD
4530sub qemu_volume_snapshot_delete {
4531 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4532
ed221350 4533 my $running = check_running($vmid);
fc46aff9 4534
a2f1554b
AD
4535 if($running) {
4536
4537 $running = undef;
4538 my $conf = PVE::QemuConfig->load_config($vmid);
912792e2 4539 PVE::QemuConfig->foreach_volume($conf, sub {
a2f1554b
AD
4540 my ($ds, $drive) = @_;
4541 $running = 1 if $drive->{file} eq $volid;
4542 });
4543 }
4544
1ef7592f 4545 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
0a13e08e 4546 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4547 } else {
4548 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4549 }
fc46aff9
AD
4550}
4551
264e519f 4552sub set_migration_caps {
27a5be53 4553 my ($vmid, $savevm) = @_;
a89fded1 4554
acc10e51
SR
4555 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4556
27a5be53
SR
4557 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm' : 'pbs-dirty-bitmap-migration';
4558 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4559
8b8345f3 4560 my $cap_ref = [];
a89fded1
AD
4561
4562 my $enabled_cap = {
8b8345f3 4563 "auto-converge" => 1,
0b0a47e8 4564 "xbzrle" => 1,
8b8345f3
DM
4565 "x-rdma-pin-all" => 0,
4566 "zero-blocks" => 0,
acc10e51 4567 "compress" => 0,
27a5be53 4568 "dirty-bitmaps" => $dirty_bitmaps,
a89fded1
AD
4569 };
4570
0a13e08e 4571 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
a89fded1 4572
8b8345f3 4573 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4574 push @$cap_ref, {
4575 capability => $supported_capability->{capability},
22430fa2
DM
4576 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4577 };
a89fded1
AD
4578 }
4579
0a13e08e 4580 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
8b8345f3 4581}
a89fded1 4582
912792e2
FE
4583sub foreach_volid {
4584 my ($conf, $func, @param) = @_;
4585
4586 my $volhash = {};
4587
4588 my $test_volid = sub {
ae180b8f 4589 my ($key, $drive, $snapname) = @_;
912792e2 4590
ae180b8f 4591 my $volid = $drive->{file};
912792e2
FE
4592 return if !$volid;
4593
4594 $volhash->{$volid}->{cdrom} //= 1;
ae180b8f 4595 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
912792e2 4596
ae180b8f 4597 my $replicate = $drive->{replicate} // 1;
912792e2
FE
4598 $volhash->{$volid}->{replicate} //= 0;
4599 $volhash->{$volid}->{replicate} = 1 if $replicate;
4600
4601 $volhash->{$volid}->{shared} //= 0;
ae180b8f 4602 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
912792e2
FE
4603
4604 $volhash->{$volid}->{referenced_in_config} //= 0;
4605 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4606
4607 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4608 if defined($snapname);
ae180b8f
FE
4609
4610 my $size = $drive->{size};
4611 $volhash->{$volid}->{size} //= $size if $size;
4612
4613 $volhash->{$volid}->{is_vmstate} //= 0;
4614 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate';
4615
f9dde219
SR
4616 $volhash->{$volid}->{is_tpmstate} //= 0;
4617 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0';
4618
ae180b8f
FE
4619 $volhash->{$volid}->{is_unused} //= 0;
4620 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
a6be63ac
FE
4621
4622 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
912792e2
FE
4623 };
4624
ae180b8f
FE
4625 my $include_opts = {
4626 extra_keys => ['vmstate'],
4627 include_unused => 1,
4628 };
4629
0b953b8e 4630 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
912792e2
FE
4631 foreach my $snapname (keys %{$conf->{snapshots}}) {
4632 my $snap = $conf->{snapshots}->{$snapname};
0b953b8e 4633 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
912792e2
FE
4634 }
4635
4636 foreach my $volid (keys %$volhash) {
4637 &$func($volid, $volhash->{$volid}, @param);
4638 }
4639}
4640
81d95ae1 4641my $fast_plug_option = {
7498eb64 4642 'lock' => 1,
81d95ae1 4643 'name' => 1,
a1b7d579 4644 'onboot' => 1,
81d95ae1
DM
4645 'shares' => 1,
4646 'startup' => 1,
b0ec896e 4647 'description' => 1,
ec647db4 4648 'protection' => 1,
8cad5e9b 4649 'vmstatestorage' => 1,
9e784b11 4650 'hookscript' => 1,
b8e7068a 4651 'tags' => 1,
81d95ae1
DM
4652};
4653
3a11fadb
DM
4654# hotplug changes in [PENDING]
4655# $selection hash can be used to only apply specified options, for
4656# example: { cores => 1 } (only apply changed 'cores')
4657# $errors ref is used to return error messages
c427973b 4658sub vmconfig_hotplug_pending {
3a11fadb 4659 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4660
8e90138a 4661 my $defaults = load_defaults();
045749f2
TL
4662 my $arch = get_vm_arch($conf);
4663 my $machine_type = get_vm_machine($conf, undef, $arch);
c427973b
DM
4664
4665 # commit values which do not have any impact on running VM first
3a11fadb
DM
4666 # Note: those option cannot raise errors, we we do not care about
4667 # $selection and always apply them.
4668
4669 my $add_error = sub {
4670 my ($opt, $msg) = @_;
4671 $errors->{$opt} = "hotplug problem - $msg";
4672 };
c427973b
DM
4673
4674 my $changes = 0;
4675 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4676 if ($fast_plug_option->{$opt}) {
c427973b
DM
4677 $conf->{$opt} = $conf->{pending}->{$opt};
4678 delete $conf->{pending}->{$opt};
4679 $changes = 1;
4680 }
4681 }
4682
4683 if ($changes) {
ffda963f 4684 PVE::QemuConfig->write_config($vmid, $conf);
c427973b
DM
4685 }
4686
b3c2bdd1 4687 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4688
5b65b00d 4689 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
98bc3aeb 4690 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4691 foreach my $opt (sort keys %$pending_delete_hash) {
3a11fadb 4692 next if $selection && !$selection->{$opt};
d321c4a9 4693 my $force = $pending_delete_hash->{$opt}->{force};
3a11fadb 4694 eval {
51a6f637
AD
4695 if ($opt eq 'hotplug') {
4696 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4697 } elsif ($opt eq 'tablet') {
b3c2bdd1 4698 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4699 if ($defaults->{tablet}) {
d559309f
WB
4700 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4701 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4702 if $arch eq 'aarch64';
3a11fadb 4703 } else {
d559309f
WB
4704 vm_deviceunplug($vmid, $conf, 'tablet');
4705 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4706 }
4eb68604 4707 } elsif ($opt =~ m/^usb\d+/) {
f745762b 4708 die "skip\n";
50bbe377
TL
4709 # since we cannot reliably hot unplug usb devices we are disabling it
4710 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4711 #vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4712 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4713 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4714 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4715 } elsif ($opt eq 'balloon') {
81d95ae1 4716 # enable balloon device is not hotpluggable
75b51053
DC
4717 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4718 # here we reset the ballooning value to memory
4719 my $balloon = $conf->{memory} || $defaults->{memory};
0a13e08e 4720 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4721 } elsif ($fast_plug_option->{$opt}) {
4722 # do nothing
3eec5767 4723 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4724 die "skip\n" if !$hotplug_features->{network};
3eec5767 4725 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4726 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4727 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4728 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4729 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4730 } elsif ($opt =~ m/^memory$/) {
4731 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4732 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3 4733 } elsif ($opt eq 'cpuunits') {
d3f9db4d 4734 $cgroup->change_cpu_shares(undef, 1024);
58be00f1 4735 } elsif ($opt eq 'cpulimit') {
5b65b00d 4736 $cgroup->change_cpu_quota(-1, 100000);
3d7389fe 4737 } else {
e56beeda 4738 die "skip\n";
3d7389fe 4739 }
3a11fadb
DM
4740 };
4741 if (my $err = $@) {
e56beeda
DM
4742 &$add_error($opt, $err) if $err ne "skip\n";
4743 } else {
3a11fadb 4744 delete $conf->{$opt};
98bc3aeb 4745 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
3d7389fe 4746 }
3d7389fe
DM
4747 }
4748
e5a66e48 4749 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
9ed7a77c 4750 $apply_pending_cloudinit = sub {
e5a66e48
WB
4751 return if $apply_pending_cloudinit_done; # once is enough
4752 $apply_pending_cloudinit_done = 1; # once is enough
4753
9ed7a77c 4754 my ($key, $value) = @_;
9ed7a77c
WB
4755
4756 my @cloudinit_opts = keys %$confdesc_cloudinit;
4757 foreach my $opt (keys %{$conf->{pending}}) {
4758 next if !grep { $_ eq $opt } @cloudinit_opts;
4759 $conf->{$opt} = delete $conf->{pending}->{$opt};
4760 }
4761
e6ec384f
AD
4762 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4763 foreach my $opt (sort keys %$pending_delete_hash) {
4764 next if !grep { $_ eq $opt } @cloudinit_opts;
4765 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4766 delete $conf->{$opt};
4767 }
4768
9ed7a77c
WB
4769 my $new_conf = { %$conf };
4770 $new_conf->{$key} = $value;
4771 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4772 };
4773
3d7389fe 4774 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4775 next if $selection && !$selection->{$opt};
3d7389fe 4776 my $value = $conf->{pending}->{$opt};
3a11fadb 4777 eval {
51a6f637
AD
4778 if ($opt eq 'hotplug') {
4779 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4780 } elsif ($opt eq 'tablet') {
b3c2bdd1 4781 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4782 if ($value == 1) {
d559309f
WB
4783 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4784 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4785 if $arch eq 'aarch64';
3a11fadb 4786 } elsif ($value == 0) {
d559309f
WB
4787 vm_deviceunplug($vmid, $conf, 'tablet');
4788 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4789 }
4eb68604 4790 } elsif ($opt =~ m/^usb\d+$/) {
f745762b 4791 die "skip\n";
50bbe377
TL
4792 # since we cannot reliably hot unplug usb devices we disable it for now
4793 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4794 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4795 #die "skip\n" if !$d;
4796 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 4797 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4798 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
4799 qemu_cpu_hotplug($vmid, $conf, $value);
4800 } elsif ($opt eq 'balloon') {
81d95ae1 4801 # enable/disable balloning device is not hotpluggable
8fe689e7 4802 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 4803 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
4804 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4805
3a11fadb 4806 # allow manual ballooning if shares is set to zero
4cc1efa6 4807 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069 4808 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
0a13e08e 4809 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
9c2f7069 4810 }
a1b7d579 4811 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 4812 # some changes can be done without hotplug
a1b7d579 4813 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 4814 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 4815 } elsif (is_valid_drivename($opt)) {
f9dde219 4816 die "skip\n" if $opt eq 'efidisk0' || $opt eq 'tpmstate0';
a05cff86 4817 # some changes can be done without hotplug
9ed7a77c
WB
4818 my $drive = parse_drive($opt, $value);
4819 if (drive_is_cloudinit($drive)) {
4820 &$apply_pending_cloudinit($opt, $value);
4821 }
b3c2bdd1 4822 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
9e7bce2c 4823 $vmid, $opt, $value, $arch, $machine_type);
4d3f29ed
AD
4824 } elsif ($opt =~ m/^memory$/) { #dimms
4825 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4826 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3 4827 } elsif ($opt eq 'cpuunits') {
d3f9db4d 4828 $cgroup->change_cpu_shares($conf->{pending}->{$opt}, 1024);
58be00f1 4829 } elsif ($opt eq 'cpulimit') {
c6f773b8 4830 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
5b65b00d 4831 $cgroup->change_cpu_quota($cpulimit, 100000);
3a11fadb 4832 } else {
e56beeda 4833 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 4834 }
3a11fadb
DM
4835 };
4836 if (my $err = $@) {
e56beeda
DM
4837 &$add_error($opt, $err) if $err ne "skip\n";
4838 } else {
3a11fadb
DM
4839 $conf->{$opt} = $value;
4840 delete $conf->{pending}->{$opt};
3d7389fe 4841 }
3d7389fe 4842 }
4df15a03
OB
4843
4844 PVE::QemuConfig->write_config($vmid, $conf);
c427973b 4845}
055d554d 4846
3dc38fbb
WB
4847sub try_deallocate_drive {
4848 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4849
4850 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4851 my $volid = $drive->{file};
4852 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4853 my $sid = PVE::Storage::parse_volume_id($volid);
4854 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
4855
4856 # check if the disk is really unused
cee01bcb 4857 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
e0fd2b2f 4858 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 4859 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 4860 return 1;
40b977f3
WL
4861 } else {
4862 # If vm is not owner of this disk remove from config
4863 return 1;
3dc38fbb
WB
4864 }
4865 }
4866
d1c1af4b 4867 return;
3dc38fbb
WB
4868}
4869
4870sub vmconfig_delete_or_detach_drive {
4871 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4872
4873 my $drive = parse_drive($opt, $conf->{$opt});
4874
4875 my $rpcenv = PVE::RPCEnvironment::get();
4876 my $authuser = $rpcenv->get_user();
4877
4878 if ($force) {
4879 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
4880 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4881 } else {
4882 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4883 }
4884}
4885
98bc3aeb
OB
4886
4887
055d554d 4888sub vmconfig_apply_pending {
eb5e482d
OB
4889 my ($vmid, $conf, $storecfg, $errors) = @_;
4890
4891 my $add_apply_error = sub {
4892 my ($opt, $msg) = @_;
4893 my $err_msg = "unable to apply pending change $opt : $msg";
4894 $errors->{$opt} = $err_msg;
4895 warn $err_msg;
4896 };
c427973b
DM
4897
4898 # cold plug
055d554d 4899
98bc3aeb 4900 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4901 foreach my $opt (sort keys %$pending_delete_hash) {
fb4d1ba2 4902 my $force = $pending_delete_hash->{$opt}->{force};
eb5e482d 4903 eval {
3d48b95a
OB
4904 if ($opt =~ m/^unused/) {
4905 die "internal error";
4906 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 4907 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
eb5e482d
OB
4908 }
4909 };
4910 if (my $err = $@) {
4911 $add_apply_error->($opt, $err);
055d554d 4912 } else {
98bc3aeb 4913 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 4914 delete $conf->{$opt};
055d554d
DM
4915 }
4916 }
4917
3d48b95a 4918 PVE::QemuConfig->cleanup_pending($conf);
055d554d
DM
4919
4920 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3d48b95a 4921 next if $opt eq 'delete'; # just to be sure
eb5e482d 4922 eval {
3d48b95a 4923 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 4924 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
eb5e482d
OB
4925 }
4926 };
4927 if (my $err = $@) {
4928 $add_apply_error->($opt, $err);
055d554d 4929 } else {
eb5e482d 4930 $conf->{$opt} = delete $conf->{pending}->{$opt};
055d554d 4931 }
055d554d 4932 }
3d48b95a
OB
4933
4934 # write all changes at once to avoid unnecessary i/o
4935 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
4936}
4937
3eec5767 4938sub vmconfig_update_net {
d559309f 4939 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
4940
4941 my $newnet = parse_net($value);
4942
4943 if ($conf->{$opt}) {
4944 my $oldnet = parse_net($conf->{$opt});
4945
0f1af9e7
OB
4946 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4947 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4948 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
3eec5767
DM
4949 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4950
4951 # for non online change, we try to hot-unplug
7196b757 4952 die "skip\n" if !$hotplug;
3eec5767
DM
4953 vm_deviceunplug($vmid, $conf, $opt);
4954 } else {
4955
4956 die "internal error" if $opt !~ m/net(\d+)/;
4957 my $iface = "tap${vmid}i$1";
a1b7d579 4958
0f1af9e7
OB
4959 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4960 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4961 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4962 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 4963 PVE::Network::tap_unplug($iface);
28e129cc
AD
4964
4965 if ($have_sdn) {
4966 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4967 } else {
4968 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4969 }
0f1af9e7 4970 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4f4fbeb0
WB
4971 # Rate can be applied on its own but any change above needs to
4972 # include the rate in tap_plug since OVS resets everything.
4973 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 4974 }
38c590d9 4975
0f1af9e7 4976 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
25088687
DM
4977 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4978 }
4979
38c590d9 4980 return 1;
3eec5767
DM
4981 }
4982 }
a1b7d579 4983
7196b757 4984 if ($hotplug) {
d559309f 4985 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
4986 } else {
4987 die "skip\n";
4988 }
3eec5767
DM
4989}
4990
a05cff86 4991sub vmconfig_update_disk {
9e7bce2c 4992 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
a05cff86
DM
4993
4994 my $drive = parse_drive($opt, $value);
4995
4df98f2f
TL
4996 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
4997 my $media = $drive->{media} || 'disk';
4998 my $oldmedia = $old_drive->{media} || 'disk';
4999 die "unable to change media type\n" if $media ne $oldmedia;
a05cff86 5000
4df98f2f 5001 if (!drive_is_cdrom($old_drive)) {
a05cff86 5002
4df98f2f 5003 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 5004
4df98f2f 5005 die "skip\n" if !$hotplug;
a05cff86 5006
4df98f2f
TL
5007 # unplug and register as unused
5008 vm_deviceunplug($vmid, $conf, $opt);
5009 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 5010
4df98f2f
TL
5011 } else {
5012 # update existing disk
5013
5014 # skip non hotpluggable value
5015 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5016 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5017 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5018 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
5019 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
5020 die "skip\n";
5021 }
a05cff86 5022
4df98f2f
TL
5023 # apply throttle
5024 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5025 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5026 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5027 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5028 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5029 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5030 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5031 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5032 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5033 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5034 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5035 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5036 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5037 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5038 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5039 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5040 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5041 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5042
5043 qemu_block_set_io_throttle(
5044 $vmid,"drive-$opt",
5045 ($drive->{mbps} || 0)*1024*1024,
5046 ($drive->{mbps_rd} || 0)*1024*1024,
5047 ($drive->{mbps_wr} || 0)*1024*1024,
5048 $drive->{iops} || 0,
5049 $drive->{iops_rd} || 0,
5050 $drive->{iops_wr} || 0,
5051 ($drive->{mbps_max} || 0)*1024*1024,
5052 ($drive->{mbps_rd_max} || 0)*1024*1024,
5053 ($drive->{mbps_wr_max} || 0)*1024*1024,
5054 $drive->{iops_max} || 0,
5055 $drive->{iops_rd_max} || 0,
5056 $drive->{iops_wr_max} || 0,
5057 $drive->{bps_max_length} || 1,
5058 $drive->{bps_rd_max_length} || 1,
5059 $drive->{bps_wr_max_length} || 1,
5060 $drive->{iops_max_length} || 1,
5061 $drive->{iops_rd_max_length} || 1,
5062 $drive->{iops_wr_max_length} || 1,
5063 );
a05cff86 5064
4df98f2f 5065 }
a1b7d579 5066
4df98f2f
TL
5067 return 1;
5068 }
4de1bb25 5069
4df98f2f 5070 } else { # cdrom
a1b7d579 5071
4df98f2f
TL
5072 if ($drive->{file} eq 'none') {
5073 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5074 if (drive_is_cloudinit($old_drive)) {
5075 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5076 }
5077 } else {
5078 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
ce9fce79 5079
4df98f2f
TL
5080 # force eject if locked
5081 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
ce9fce79 5082
4df98f2f
TL
5083 if ($path) {
5084 mon_cmd($vmid, "blockdev-change-medium",
5085 id => "$opt", filename => "$path");
4de1bb25 5086 }
a05cff86 5087 }
4df98f2f
TL
5088
5089 return 1;
a05cff86
DM
5090 }
5091 }
5092
a1b7d579 5093 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 5094 # hotplug new disks
f7b4356f 5095 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 5096 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
5097}
5098
13cfe3b7 5099# called in locked context by incoming migration
ba5396b5
FG
5100sub vm_migrate_get_nbd_disks {
5101 my ($storecfg, $conf, $replicated_volumes) = @_;
13cfe3b7
FG
5102
5103 my $local_volumes = {};
912792e2 5104 PVE::QemuConfig->foreach_volume($conf, sub {
13cfe3b7
FG
5105 my ($ds, $drive) = @_;
5106
5107 return if drive_is_cdrom($drive);
5108
5109 my $volid = $drive->{file};
5110
5111 return if !$volid;
5112
5113 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5114
5115 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5116 return if $scfg->{shared};
ba5396b5
FG
5117
5118 # replicated disks re-use existing state via bitmap
5119 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5120 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
13cfe3b7 5121 });
ba5396b5
FG
5122 return $local_volumes;
5123}
5124
5125# called in locked context by incoming migration
5126sub vm_migrate_alloc_nbd_disks {
5127 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
13cfe3b7
FG
5128
5129 my $format = undef;
5130
5131 my $nbd = {};
ba5396b5
FG
5132 foreach my $opt (sort keys %$source_volumes) {
5133 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
5134
5135 if ($use_existing) {
5136 $nbd->{$opt}->{drivestr} = print_drive($drive);
5137 $nbd->{$opt}->{volid} = $volid;
5138 $nbd->{$opt}->{replicated} = 1;
13cfe3b7
FG
5139 next;
5140 }
13cfe3b7
FG
5141
5142 # If a remote storage is specified and the format of the original
5143 # volume is not available there, fall back to the default format.
5144 # Otherwise use the same format as the original.
bf8fc5a3
FG
5145 if (!$storagemap->{identity}) {
5146 $storeid = map_storage($storagemap, $storeid);
13cfe3b7
FG
5147 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5148 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5149 my $fileFormat = qemu_img_format($scfg, $volname);
5150 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
5151 } else {
5152 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5153 $format = qemu_img_format($scfg, $volname);
5154 }
5155
4df98f2f
TL
5156 my $size = $drive->{size} / 1024;
5157 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
13cfe3b7
FG
5158 my $newdrive = $drive;
5159 $newdrive->{format} = $format;
5160 $newdrive->{file} = $newvolid;
5161 my $drivestr = print_drive($newdrive);
ba5396b5
FG
5162 $nbd->{$opt}->{drivestr} = $drivestr;
5163 $nbd->{$opt}->{volid} = $newvolid;
13cfe3b7
FG
5164 }
5165
5166 return $nbd;
5167}
5168
5169# see vm_start_nolock for parameters, additionally:
5170# migrate_opts:
bf8fc5a3 5171# storagemap = parsed storage map for allocating NBD disks
3898a563
FG
5172sub vm_start {
5173 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5174
84da8217 5175 return PVE::QemuConfig->lock_config($vmid, sub {
3898a563
FG
5176 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5177
4ef13a7f
FG
5178 die "you can't start a vm if it's a template\n"
5179 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
3898a563 5180
d544e0e0 5181 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended');
8e0c97bb
SR
5182 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup');
5183
5184 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5185
5186 if ($has_backup_lock && $running) {
5187 # a backup is currently running, attempt to start the guest in the
5188 # existing QEMU instance
5189 return vm_resume($vmid);
5190 }
3898a563
FG
5191
5192 PVE::QemuConfig->check_lock($conf)
d544e0e0
FE
5193 if !($params->{skiplock} || $has_suspended_lock);
5194
5195 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
3898a563 5196
8e0c97bb 5197 die "VM $vmid already running\n" if $running;
3898a563 5198
ba5396b5
FG
5199 if (my $storagemap = $migrate_opts->{storagemap}) {
5200 my $replicated = $migrate_opts->{replicated_volumes};
5201 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5202 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5203
5204 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5205 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5206 }
5207 }
13cfe3b7 5208
84da8217 5209 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
3898a563
FG
5210 });
5211}
5212
5213
0c498cca
FG
5214# params:
5215# statefile => 'tcp', 'unix' for migration or path/volid for RAM state
5216# skiplock => 0/1, skip checking for config lock
4ef13a7f 5217# skiptemplate => 0/1, skip checking whether VM is template
0c498cca 5218# forcemachine => to force Qemu machine (rollback/migration)
58c64ad5 5219# forcecpu => a QEMU '-cpu' argument string to override get_cpu_options
0c498cca
FG
5220# timeout => in seconds
5221# paused => start VM in paused state (backup)
3898a563 5222# resume => resume from hibernation
5921764c
SR
5223# pbs-backing => {
5224# sata0 => {
5225# repository
5226# snapshot
5227# keyfile
5228# archive
5229# },
5230# virtio2 => ...
5231# }
0c498cca 5232# migrate_opts:
ba5396b5 5233# nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
0c498cca
FG
5234# migratedfrom => source node
5235# spice_ticket => used for spice migration, passed via tunnel/stdin
5236# network => CIDR of migration network
5237# type => secure/insecure - tunnel over encrypted connection or plain-text
0c498cca
FG
5238# nbd_proto_version => int, 0 for TCP, 1 for UNIX
5239# replicated_volumes = which volids should be re-used with bitmaps for nbd migration
3898a563
FG
5240sub vm_start_nolock {
5241 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
1e3baf05 5242
3898a563
FG
5243 my $statefile = $params->{statefile};
5244 my $resume = $params->{resume};
3dcb98d5 5245
3898a563
FG
5246 my $migratedfrom = $migrate_opts->{migratedfrom};
5247 my $migration_type = $migrate_opts->{type};
7ceade4c 5248
84da8217
FG
5249 my $res = {};
5250
3898a563
FG
5251 # clean up leftover reboot request files
5252 eval { clear_reboot_request($vmid); };
5253 warn $@ if $@;
1e3baf05 5254
3898a563
FG
5255 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5256 vmconfig_apply_pending($vmid, $conf, $storecfg);
5257 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5258 }
64457ed4 5259
104f47a9
ML
5260 # don't regenerate the ISO if the VM is started as part of a live migration
5261 # this way we can reuse the old ISO with the correct config
5262 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid) if !$migratedfrom;
055d554d 5263
3898a563 5264 my $defaults = load_defaults();
0c9a7596 5265
3898a563
FG
5266 # set environment variable useful inside network script
5267 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
6c47d546 5268
3898a563 5269 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
9e784b11 5270
3898a563 5271 my $forcemachine = $params->{forcemachine};
ea1c2110 5272 my $forcecpu = $params->{forcecpu};
3898a563 5273 if ($resume) {
ea1c2110 5274 # enforce machine and CPU type on suspended vm to ensure HW compatibility
3898a563 5275 $forcemachine = $conf->{runningmachine};
ea1c2110 5276 $forcecpu = $conf->{runningcpu};
3898a563
FG
5277 print "Resuming suspended VM\n";
5278 }
7ceade4c 5279
5921764c
SR
5280 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid,
5281 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
6c47d546 5282
3898a563
FG
5283 my $migration_ip;
5284 my $get_migration_ip = sub {
5285 my ($nodename) = @_;
b24e1ac2 5286
3898a563 5287 return $migration_ip if defined($migration_ip);
b24e1ac2 5288
3898a563 5289 my $cidr = $migrate_opts->{network};
0c498cca 5290
3898a563
FG
5291 if (!defined($cidr)) {
5292 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5293 $cidr = $dc_conf->{migration}->{network};
5294 }
b24e1ac2 5295
3898a563
FG
5296 if (defined($cidr)) {
5297 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
b24e1ac2 5298
3898a563
FG
5299 die "could not get IP: no address configured on local " .
5300 "node for network '$cidr'\n" if scalar(@$ips) == 0;
b24e1ac2 5301
3898a563
FG
5302 die "could not get IP: multiple addresses configured on local " .
5303 "node for network '$cidr'\n" if scalar(@$ips) > 1;
b24e1ac2 5304
3898a563
FG
5305 $migration_ip = @$ips[0];
5306 }
b24e1ac2 5307
3898a563
FG
5308 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
5309 if !defined($migration_ip);
b24e1ac2 5310
3898a563
FG
5311 return $migration_ip;
5312 };
b24e1ac2 5313
3898a563
FG
5314 my $migrate_uri;
5315 if ($statefile) {
5316 if ($statefile eq 'tcp') {
5317 my $localip = "localhost";
5318 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5319 my $nodename = nodename();
2de2d6f7 5320
3898a563
FG
5321 if (!defined($migration_type)) {
5322 if (defined($datacenterconf->{migration}->{type})) {
5323 $migration_type = $datacenterconf->{migration}->{type};
5324 } else {
5325 $migration_type = 'secure';
b7a5a225 5326 }
3898a563 5327 }
b7a5a225 5328
3898a563
FG
5329 if ($migration_type eq 'insecure') {
5330 $localip = $get_migration_ip->($nodename);
5331 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5332 }
2de2d6f7 5333
3898a563
FG
5334 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5335 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5336 $migrate_uri = "tcp:${localip}:${migrate_port}";
5337 push @$cmd, '-incoming', $migrate_uri;
5338 push @$cmd, '-S';
1c9d54bf 5339
3898a563
FG
5340 } elsif ($statefile eq 'unix') {
5341 # should be default for secure migrations as a ssh TCP forward
5342 # tunnel is not deterministic reliable ready and fails regurarly
5343 # to set up in time, so use UNIX socket forwards
5344 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5345 unlink $socket_addr;
54323eed 5346
3898a563 5347 $migrate_uri = "unix:$socket_addr";
1c9d54bf 5348
3898a563
FG
5349 push @$cmd, '-incoming', $migrate_uri;
5350 push @$cmd, '-S';
1c9d54bf 5351
3898a563
FG
5352 } elsif (-e $statefile) {
5353 push @$cmd, '-loadstate', $statefile;
5354 } else {
5355 my $statepath = PVE::Storage::path($storecfg, $statefile);
5356 push @$vollist, $statefile;
5357 push @$cmd, '-loadstate', $statepath;
5358 }
5359 } elsif ($params->{paused}) {
5360 push @$cmd, '-S';
5361 }
5362
5363 # host pci devices
74c17b7a 5364 for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
3898a563
FG
5365 my $d = parse_hostpci($conf->{"hostpci$i"});
5366 next if !$d;
5367 my $pcidevices = $d->{pciid};
5368 foreach my $pcidevice (@$pcidevices) {
5369 my $pciid = $pcidevice->{id};
5370
5371 my $info = PVE::SysFSTools::pci_device_info("$pciid");
5372 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5373 die "no pci device info for device '$pciid'\n" if !$info;
5374
5375 if ($d->{mdev}) {
5376 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5377 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5c1d42b7 5378 } else {
50bbe377 5379 die "can't unbind/bind PCI group to VFIO '$pciid'\n"
3898a563 5380 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
50bbe377
TL
5381 die "can't reset PCI device '$pciid'\n"
5382 if $info->{has_fl_reset} && !PVE::SysFSTools::pci_dev_reset($info);
1e3baf05 5383 }
3898a563
FG
5384 }
5385 }
1e3baf05 5386
3898a563 5387 PVE::Storage::activate_volumes($storecfg, $vollist);
1e3baf05 5388
3898a563
FG
5389 eval {
5390 run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
5391 outfunc => sub {}, errfunc => sub {});
5392 };
5393 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5394 # timeout should be more than enough here...
5395 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5396
d3f9db4d 5397 my $cpuunits = get_cpuunits($conf);
3898a563
FG
5398
5399 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5400 my %run_params = (
5401 timeout => $statefile ? undef : $start_timeout,
5402 umask => 0077,
5403 noerr => 1,
5404 );
1e3baf05 5405
3898a563
FG
5406 # when migrating, prefix QEMU output so other side can pick up any
5407 # errors that might occur and show the user
5408 if ($migratedfrom) {
5409 $run_params{quiet} = 1;
5410 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5411 }
8bf30c2a 5412
3898a563
FG
5413 my %properties = (
5414 Slice => 'qemu.slice',
354e61aa
SR
5415 KillMode => 'process',
5416 SendSIGKILL => 0,
5417 TimeoutStopUSec => ULONG_MAX, # infinity
3898a563 5418 );
7023f3ea 5419
6cbd3eb8 5420 if (PVE::CGroup::cgroup_mode() == 2) {
6c71a52a 5421 $cpuunits = 10000 if $cpuunits >= 10000; # else we get an error
6cbd3eb8
AD
5422 $properties{CPUWeight} = $cpuunits;
5423 } else {
5424 $properties{CPUShares} = $cpuunits;
5425 }
5426
3898a563
FG
5427 if (my $cpulimit = $conf->{cpulimit}) {
5428 $properties{CPUQuota} = int($cpulimit * 100);
5429 }
5430 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
7023f3ea 5431
3898a563
FG
5432 my $run_qemu = sub {
5433 PVE::Tools::run_fork sub {
5434 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
6e0216d8 5435
f9dde219
SR
5436 my $tpmpid;
5437 if (my $tpm = $conf->{tpmstate0}) {
5438 # start the TPM emulator so QEMU can connect on start
5439 $tpmpid = start_swtpm($storecfg, $vmid, $tpm, $migratedfrom);
5440 }
5441
3898a563 5442 my $exitcode = run_command($cmd, %run_params);
f9dde219 5443 if ($exitcode) {
13268327 5444 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
f9dde219
SR
5445 kill 'TERM', $tpmpid if $tpmpid;
5446 die "QEMU exited with code $exitcode\n";
5447 }
503308ed 5448 };
3898a563 5449 };
503308ed 5450
3898a563 5451 if ($conf->{hugepages}) {
7023f3ea 5452
3898a563
FG
5453 my $code = sub {
5454 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5455 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
7023f3ea 5456
3898a563
FG
5457 PVE::QemuServer::Memory::hugepages_mount();
5458 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
7023f3ea 5459
503308ed 5460 eval { $run_qemu->() };
3898a563 5461 if (my $err = $@) {
f36e9894
SR
5462 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology)
5463 if !$conf->{keephugepages};
3898a563
FG
5464 die $err;
5465 }
77cde36b 5466
f36e9894
SR
5467 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology)
5468 if !$conf->{keephugepages};
3898a563
FG
5469 };
5470 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
1e3baf05 5471
3898a563
FG
5472 } else {
5473 eval { $run_qemu->() };
5474 }
afdb31d5 5475
3898a563
FG
5476 if (my $err = $@) {
5477 # deactivate volumes if start fails
5478 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5479 die "start failed: $err";
5480 }
62de2cbd 5481
3898a563 5482 print "migration listens on $migrate_uri\n" if $migrate_uri;
84da8217 5483 $res->{migrate_uri} = $migrate_uri;
eb8cddb5 5484
3898a563
FG
5485 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5486 eval { mon_cmd($vmid, "cont"); };
5487 warn $@ if $@;
5488 }
2189246c 5489
3898a563 5490 #start nbd server for storage migration
13cfe3b7 5491 if (my $nbd = $migrate_opts->{nbd}) {
3898a563 5492 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
2189246c 5493
3898a563
FG
5494 my $migrate_storage_uri;
5495 # nbd_protocol_version > 0 for unix socket support
5496 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5497 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5498 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix', data => { path => $socket_path } } );
5499 $migrate_storage_uri = "nbd:unix:$socket_path";
5500 } else {
5501 my $nodename = nodename();
5502 my $localip = $get_migration_ip->($nodename);
5503 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5504 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5505
4df98f2f
TL
5506 mon_cmd($vmid, "nbd-server-start", addr => {
5507 type => 'inet',
5508 data => {
5509 host => "${localip}",
5510 port => "${storage_migrate_port}",
5511 },
5512 });
3898a563
FG
5513 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5514 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
2189246c
AD
5515 }
5516
84da8217
FG
5517 $res->{migrate_storage_uri} = $migrate_storage_uri;
5518
13cfe3b7 5519 foreach my $opt (sort keys %$nbd) {
ba5396b5
FG
5520 my $drivestr = $nbd->{$opt}->{drivestr};
5521 my $volid = $nbd->{$opt}->{volid};
3898a563 5522 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
84da8217
FG
5523 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5524 print "storage migration listens on $nbd_uri volume:$drivestr\n";
ba5396b5
FG
5525 print "re-using replicated volume: $opt - $volid\n"
5526 if $nbd->{$opt}->{replicated};
84da8217
FG
5527
5528 $res->{drives}->{$opt} = $nbd->{$opt};
5529 $res->{drives}->{$opt}->{nbd_uri} = $nbd_uri;
3898a563
FG
5530 }
5531 }
a89fded1 5532
3898a563
FG
5533 if ($migratedfrom) {
5534 eval {
5535 set_migration_caps($vmid);
5536 };
5537 warn $@ if $@;
5538
5539 if ($spice_port) {
5540 print "spice listens on port $spice_port\n";
84da8217 5541 $res->{spice_port} = $spice_port;
3898a563 5542 if ($migrate_opts->{spice_ticket}) {
4df98f2f
TL
5543 mon_cmd($vmid, "set_password", protocol => 'spice', password =>
5544 $migrate_opts->{spice_ticket});
3898a563 5545 mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9 5546 }
3898a563 5547 }
95a4b4a9 5548
3898a563
FG
5549 } else {
5550 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5551 if !$statefile && $conf->{balloon};
25088687 5552
3898a563
FG
5553 foreach my $opt (keys %$conf) {
5554 next if $opt !~ m/^net\d+$/;
5555 my $nicconf = parse_net($conf->{$opt});
5556 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
e18b0b99 5557 }
3898a563 5558 }
a1b7d579 5559
3898a563
FG
5560 mon_cmd($vmid, 'qom-set',
5561 path => "machine/peripheral/balloon0",
5562 property => "guest-stats-polling-interval",
5563 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
eb065317 5564
3898a563
FG
5565 if ($resume) {
5566 print "Resumed VM, removing state\n";
5567 if (my $vmstate = $conf->{vmstate}) {
5568 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5569 PVE::Storage::vdisk_free($storecfg, $vmstate);
7ceade4c 5570 }
ea1c2110 5571 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
3898a563
FG
5572 PVE::QemuConfig->write_config($vmid, $conf);
5573 }
7ceade4c 5574
3898a563 5575 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
84da8217
FG
5576
5577 return $res;
1e3baf05
DM
5578}
5579
1e3baf05 5580sub vm_commandline {
b14477e7 5581 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5582
ffda963f 5583 my $conf = PVE::QemuConfig->load_config($vmid);
092868c4 5584 my $forcemachine;
ea1c2110 5585 my $forcecpu;
1e3baf05 5586
b14477e7
RV
5587 if ($snapname) {
5588 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5589 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5590
ea1c2110
SR
5591 # check for machine or CPU overrides in snapshot
5592 $forcemachine = $snapshot->{runningmachine};
5593 $forcecpu = $snapshot->{runningcpu};
092868c4 5594
87d92707 5595 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5596
b14477e7
RV
5597 $conf = $snapshot;
5598 }
5599
1e3baf05
DM
5600 my $defaults = load_defaults();
5601
ea1c2110
SR
5602 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults,
5603 $forcemachine, $forcecpu);
1e3baf05 5604
5930c1ff 5605 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5606}
5607
5608sub vm_reset {
5609 my ($vmid, $skiplock) = @_;
5610
ffda963f 5611 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5612
ffda963f 5613 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5614
ffda963f 5615 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5616
0a13e08e 5617 mon_cmd($vmid, "system_reset");
ff1a2432
DM
5618 });
5619}
5620
5621sub get_vm_volumes {
5622 my ($conf) = @_;
1e3baf05 5623
ff1a2432 5624 my $vollist = [];
d5769dc2 5625 foreach_volid($conf, sub {
392f8b5d 5626 my ($volid, $attr) = @_;
ff1a2432 5627
d5769dc2 5628 return if $volid =~ m|^/|;
ff1a2432 5629
d5769dc2
DM
5630 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5631 return if !$sid;
ff1a2432
DM
5632
5633 push @$vollist, $volid;
1e3baf05 5634 });
ff1a2432
DM
5635
5636 return $vollist;
5637}
5638
5639sub vm_stop_cleanup {
70b04821 5640 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5641
745fed70 5642 eval {
ff1a2432 5643
254575e9
DM
5644 if (!$keepActive) {
5645 my $vollist = get_vm_volumes($conf);
5646 PVE::Storage::deactivate_volumes($storecfg, $vollist);
f9dde219
SR
5647
5648 if (my $tpmdrive = $conf->{tpmstate0}) {
5649 my $tpm = parse_drive("tpmstate0", $tpmdrive);
5650 my ($storeid, $volname) = PVE::Storage::parse_volume_id($tpm->{file}, 1);
5651 if ($storeid) {
5652 PVE::Storage::unmap_volume($storecfg, $tpm->{file});
5653 }
5654 }
254575e9 5655 }
a1b7d579 5656
ab6a046f 5657 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5658 unlink "/var/run/qemu-server/${vmid}.$ext";
5659 }
a1b7d579 5660
6dbcb073 5661 if ($conf->{ivshmem}) {
4df98f2f 5662 my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5663 # just delete it for now, VMs which have this already open do not
5664 # are affected, but new VMs will get a separated one. If this
5665 # becomes an issue we either add some sort of ref-counting or just
5666 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5667 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5668 }
5669
6ab45bd7
DC
5670 foreach my $key (keys %$conf) {
5671 next if $key !~ m/^hostpci(\d+)$/;
5672 my $hostpciindex = $1;
5673 my $d = parse_hostpci($conf->{$key});
5674 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5675
5676 foreach my $pci (@{$d->{pciid}}) {
2fd24788 5677 my $pciid = $pci->{id};
6ab45bd7
DC
5678 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5679 }
5680 }
5681
70b04821 5682 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5683 };
5684 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5685}
5686
575d19da
DC
5687# call only in locked context
5688sub _do_vm_stop {
5689 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
9269013a 5690
575d19da
DC
5691 my $pid = check_running($vmid, $nocheck);
5692 return if !$pid;
1e3baf05 5693
575d19da
DC
5694 my $conf;
5695 if (!$nocheck) {
5696 $conf = PVE::QemuConfig->load_config($vmid);
5697 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5698 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5699 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5700 $timeout = $opts->{down} if $opts->{down};
e6c3b671 5701 }
575d19da
DC
5702 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
5703 }
19672434 5704
575d19da
DC
5705 eval {
5706 if ($shutdown) {
a2af1bbe 5707 if (defined($conf) && get_qga_key($conf, 'enabled')) {
0a13e08e 5708 mon_cmd($vmid, "guest-shutdown", timeout => $timeout);
9269013a 5709 } else {
0a13e08e 5710 mon_cmd($vmid, "system_powerdown");
1e3baf05
DM
5711 }
5712 } else {
0a13e08e 5713 mon_cmd($vmid, "quit");
1e3baf05 5714 }
575d19da
DC
5715 };
5716 my $err = $@;
1e3baf05 5717
575d19da
DC
5718 if (!$err) {
5719 $timeout = 60 if !defined($timeout);
1e3baf05
DM
5720
5721 my $count = 0;
e6c3b671 5722 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5723 $count++;
5724 sleep 1;
5725 }
5726
5727 if ($count >= $timeout) {
575d19da
DC
5728 if ($force) {
5729 warn "VM still running - terminating now with SIGTERM\n";
5730 kill 15, $pid;
5731 } else {
5732 die "VM quit/powerdown failed - got timeout\n";
5733 }
5734 } else {
5735 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5736 return;
1e3baf05 5737 }
575d19da 5738 } else {
d60cbb97
TL
5739 if (!check_running($vmid, $nocheck)) {
5740 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5741 return;
5742 }
5743 if ($force) {
575d19da
DC
5744 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5745 kill 15, $pid;
5746 } else {
5747 die "VM quit/powerdown failed\n";
5748 }
5749 }
5750
5751 # wait again
5752 $timeout = 10;
5753
5754 my $count = 0;
5755 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5756 $count++;
5757 sleep 1;
5758 }
5759
5760 if ($count >= $timeout) {
5761 warn "VM still running - terminating now with SIGKILL\n";
5762 kill 9, $pid;
5763 sleep 1;
5764 }
1e3baf05 5765
575d19da
DC
5766 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5767}
5768
5769# Note: use $nocheck to skip tests if VM configuration file exists.
5770# We need that when migration VMs to other nodes (files already moved)
5771# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5772sub vm_stop {
5773 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5774
5775 $force = 1 if !defined($force) && !$shutdown;
5776
5777 if ($migratedfrom){
5778 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5779 kill 15, $pid if $pid;
5780 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5781 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
5782 return;
5783 }
5784
5785 PVE::QemuConfig->lock_config($vmid, sub {
5786 _do_vm_stop($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
ff1a2432 5787 });
1e3baf05
DM
5788}
5789
165411f0
DC
5790sub vm_reboot {
5791 my ($vmid, $timeout) = @_;
5792
5793 PVE::QemuConfig->lock_config($vmid, sub {
66026117 5794 eval {
165411f0 5795
66026117
OB
5796 # only reboot if running, as qmeventd starts it again on a stop event
5797 return if !check_running($vmid);
165411f0 5798
66026117 5799 create_reboot_request($vmid);
165411f0 5800
66026117
OB
5801 my $storecfg = PVE::Storage::config();
5802 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
165411f0 5803
66026117
OB
5804 };
5805 if (my $err = $@) {
3c1c3fe6 5806 # avoid that the next normal shutdown will be confused for a reboot
66026117
OB
5807 clear_reboot_request($vmid);
5808 die $err;
5809 }
165411f0
DC
5810 });
5811}
5812
75c24bba 5813# note: if using the statestorage parameter, the caller has to check privileges
1e3baf05 5814sub vm_suspend {
48b4cdc2 5815 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
5816
5817 my $conf;
5818 my $path;
5819 my $storecfg;
5820 my $vmstate;
1e3baf05 5821
ffda963f 5822 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5823
159719e5 5824 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5825
159719e5 5826 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 5827 PVE::QemuConfig->check_lock($conf)
159719e5
DC
5828 if !($skiplock || $is_backing_up);
5829
5830 die "cannot suspend to disk during backup\n"
5831 if $is_backing_up && $includestate;
bcb7c9cf 5832
159719e5
DC
5833 if ($includestate) {
5834 $conf->{lock} = 'suspending';
5835 my $date = strftime("%Y-%m-%d", localtime(time()));
5836 $storecfg = PVE::Storage::config();
75c24bba
DC
5837 if (!$statestorage) {
5838 $statestorage = find_vmstate_storage($conf, $storecfg);
5839 # check permissions for the storage
5840 my $rpcenv = PVE::RPCEnvironment::get();
5841 if ($rpcenv->{type} ne 'cli') {
5842 my $authuser = $rpcenv->get_user();
5843 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5844 }
5845 }
5846
5847
4df98f2f
TL
5848 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate(
5849 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
5850 $path = PVE::Storage::path($storecfg, $vmstate);
5851 PVE::QemuConfig->write_config($vmid, $conf);
5852 } else {
0a13e08e 5853 mon_cmd($vmid, "stop");
159719e5 5854 }
1e3baf05 5855 });
159719e5
DC
5856
5857 if ($includestate) {
5858 # save vm state
5859 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
5860
5861 eval {
27a5be53 5862 set_migration_caps($vmid, 1);
0a13e08e 5863 mon_cmd($vmid, "savevm-start", statefile => $path);
159719e5 5864 for(;;) {
0a13e08e 5865 my $state = mon_cmd($vmid, "query-savevm");
159719e5
DC
5866 if (!$state->{status}) {
5867 die "savevm not active\n";
5868 } elsif ($state->{status} eq 'active') {
5869 sleep(1);
5870 next;
5871 } elsif ($state->{status} eq 'completed') {
b0a9a385 5872 print "State saved, quitting\n";
159719e5
DC
5873 last;
5874 } elsif ($state->{status} eq 'failed' && $state->{error}) {
5875 die "query-savevm failed with error '$state->{error}'\n"
5876 } else {
5877 die "query-savevm returned status '$state->{status}'\n";
5878 }
5879 }
5880 };
5881 my $err = $@;
5882
5883 PVE::QemuConfig->lock_config($vmid, sub {
5884 $conf = PVE::QemuConfig->load_config($vmid);
5885 if ($err) {
5886 # cleanup, but leave suspending lock, to indicate something went wrong
5887 eval {
0a13e08e 5888 mon_cmd($vmid, "savevm-end");
159719e5
DC
5889 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5890 PVE::Storage::vdisk_free($storecfg, $vmstate);
ea1c2110 5891 delete $conf->@{qw(vmstate runningmachine runningcpu)};
159719e5
DC
5892 PVE::QemuConfig->write_config($vmid, $conf);
5893 };
5894 warn $@ if $@;
5895 die $err;
5896 }
5897
5898 die "lock changed unexpectedly\n"
5899 if !PVE::QemuConfig->has_lock($conf, 'suspending');
5900
0a13e08e 5901 mon_cmd($vmid, "quit");
159719e5
DC
5902 $conf->{lock} = 'suspended';
5903 PVE::QemuConfig->write_config($vmid, $conf);
5904 });
5905 }
1e3baf05
DM
5906}
5907
5908sub vm_resume {
289e0b85 5909 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5910
ffda963f 5911 PVE::QemuConfig->lock_config($vmid, sub {
0a13e08e 5912 my $res = mon_cmd($vmid, 'query-status');
c2786bed 5913 my $resume_cmd = 'cont';
8e0c97bb 5914 my $reset = 0;
c2786bed 5915
8e0c97bb
SR
5916 if ($res->{status}) {
5917 return if $res->{status} eq 'running'; # job done, go home
5918 $resume_cmd = 'system_wakeup' if $res->{status} eq 'suspended';
5919 $reset = 1 if $res->{status} eq 'shutdown';
c2786bed
DC
5920 }
5921
289e0b85 5922 if (!$nocheck) {
1e3baf05 5923
ffda963f 5924 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5925
e79706d4
FG
5926 PVE::QemuConfig->check_lock($conf)
5927 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5928 }
3e24733b 5929
8e0c97bb
SR
5930 if ($reset) {
5931 # required if a VM shuts down during a backup and we get a resume
5932 # request before the backup finishes for example
5933 mon_cmd($vmid, "system_reset");
5934 }
0a13e08e 5935 mon_cmd($vmid, $resume_cmd);
1e3baf05
DM
5936 });
5937}
5938
5fdbe4f0
DM
5939sub vm_sendkey {
5940 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5941
ffda963f 5942 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5943
ffda963f 5944 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5945
7b7c6d1b 5946 # there is no qmp command, so we use the human monitor command
0a13e08e 5947 my $res = PVE::QemuServer::Monitor::hmp_cmd($vmid, "sendkey $key");
d30820d6 5948 die $res if $res ne '';
1e3baf05
DM
5949 });
5950}
5951
3e16d5fc
DM
5952# vzdump restore implementaion
5953
ed221350 5954sub tar_archive_read_firstfile {
3e16d5fc 5955 my $archive = shift;
afdb31d5 5956
3e16d5fc
DM
5957 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5958
5959 # try to detect archive type first
387ba257 5960 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 5961 die "unable to open file '$archive'\n";
387ba257 5962 my $firstfile = <$fh>;
3e16d5fc 5963 kill 15, $pid;
387ba257 5964 close $fh;
3e16d5fc
DM
5965
5966 die "ERROR: archive contaions no data\n" if !$firstfile;
5967 chomp $firstfile;
5968
5969 return $firstfile;
5970}
5971
ed221350
DM
5972sub tar_restore_cleanup {
5973 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
5974
5975 print STDERR "starting cleanup\n";
5976
5977 if (my $fd = IO::File->new($statfile, "r")) {
5978 while (defined(my $line = <$fd>)) {
5979 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5980 my $volid = $2;
5981 eval {
5982 if ($volid =~ m|^/|) {
5983 unlink $volid || die 'unlink failed\n';
5984 } else {
ed221350 5985 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 5986 }
afdb31d5 5987 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
5988 };
5989 print STDERR "unable to cleanup '$volid' - $@" if $@;
5990 } else {
5991 print STDERR "unable to parse line in statfile - $line";
afdb31d5 5992 }
3e16d5fc
DM
5993 }
5994 $fd->close();
5995 }
5996}
5997
d1e92cf6 5998sub restore_file_archive {
a0d1b1a2 5999 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 6000
a2ec5a67
FG
6001 return restore_vma_archive($archive, $vmid, $user, $opts)
6002 if $archive eq '-';
6003
c6d51783
AA
6004 my $info = PVE::Storage::archive_info($archive);
6005 my $format = $opts->{format} // $info->{format};
6006 my $comp = $info->{compression};
91bd6c90
DM
6007
6008 # try to detect archive format
6009 if ($format eq 'tar') {
6010 return restore_tar_archive($archive, $vmid, $user, $opts);
6011 } else {
6012 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
6013 }
6014}
6015
d1e92cf6
DM
6016# hepler to remove disks that will not be used after restore
6017my $restore_cleanup_oldconf = sub {
6018 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6019
912792e2 6020 PVE::QemuConfig->foreach_volume($oldconf, sub {
d1e92cf6
DM
6021 my ($ds, $drive) = @_;
6022
6023 return if drive_is_cdrom($drive, 1);
6024
6025 my $volid = $drive->{file};
6026 return if !$volid || $volid =~ m|^/|;
6027
6028 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
6029 return if !$path || !$owner || ($owner != $vmid);
6030
6031 # Note: only delete disk we want to restore
6032 # other volumes will become unused
6033 if ($virtdev_hash->{$ds}) {
6034 eval { PVE::Storage::vdisk_free($storecfg, $volid); };
6035 if (my $err = $@) {
6036 warn $err;
6037 }
6038 }
6039 });
6040
6041 # delete vmstate files, after the restore we have no snapshots anymore
6042 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
6043 my $snap = $oldconf->{snapshots}->{$snapname};
6044 if ($snap->{vmstate}) {
6045 eval { PVE::Storage::vdisk_free($storecfg, $snap->{vmstate}); };
6046 if (my $err = $@) {
6047 warn $err;
6048 }
6049 }
6050 }
6051};
6052
9f3d73bc
DM
6053# Helper to parse vzdump backup device hints
6054#
6055# $rpcenv: Environment, used to ckeck storage permissions
6056# $user: User ID, to check storage permissions
6057# $storecfg: Storage configuration
6058# $fh: the file handle for reading the configuration
6059# $devinfo: should contain device sizes for all backu-up'ed devices
6060# $options: backup options (pool, default storage)
6061#
6062# Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6063my $parse_backup_hints = sub {
6064 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
d1e92cf6 6065
9f3d73bc 6066 my $virtdev_hash = {};
d1e92cf6 6067
9f3d73bc
DM
6068 while (defined(my $line = <$fh>)) {
6069 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6070 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6071 die "archive does not contain data for drive '$virtdev'\n"
6072 if !$devinfo->{$devname};
6073
6074 if (defined($options->{storage})) {
6075 $storeid = $options->{storage} || 'local';
6076 } elsif (!$storeid) {
6077 $storeid = 'local';
d1e92cf6 6078 }
9f3d73bc
DM
6079 $format = 'raw' if !$format;
6080 $devinfo->{$devname}->{devname} = $devname;
6081 $devinfo->{$devname}->{virtdev} = $virtdev;
6082 $devinfo->{$devname}->{format} = $format;
6083 $devinfo->{$devname}->{storeid} = $storeid;
6084
6085 # check permission on storage
6086 my $pool = $options->{pool}; # todo: do we need that?
6087 if ($user ne 'root@pam') {
6088 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
d1e92cf6 6089 }
d1e92cf6 6090
9f3d73bc
DM
6091 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6092 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6093 my $virtdev = $1;
6094 my $drive = parse_drive($virtdev, $2);
6095 if (drive_is_cloudinit($drive)) {
6096 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
5364990d
TL
6097 $storeid = $options->{storage} if defined ($options->{storage});
6098 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
9f3d73bc 6099 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
d1e92cf6 6100
9f3d73bc
DM
6101 $virtdev_hash->{$virtdev} = {
6102 format => $format,
5364990d 6103 storeid => $storeid,
9f3d73bc
DM
6104 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
6105 is_cloudinit => 1,
6106 };
d1e92cf6 6107 }
9f3d73bc
DM
6108 }
6109 }
d1e92cf6 6110
9f3d73bc
DM
6111 return $virtdev_hash;
6112};
d1e92cf6 6113
9f3d73bc
DM
6114# Helper to allocate and activate all volumes required for a restore
6115#
6116# $storecfg: Storage configuration
6117# $virtdev_hash: as returned by parse_backup_hints()
6118#
6119# Returns: { $virtdev => $volid }
6120my $restore_allocate_devices = sub {
6121 my ($storecfg, $virtdev_hash, $vmid) = @_;
d1e92cf6 6122
9f3d73bc
DM
6123 my $map = {};
6124 foreach my $virtdev (sort keys %$virtdev_hash) {
6125 my $d = $virtdev_hash->{$virtdev};
6126 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
6127 my $storeid = $d->{storeid};
6128 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
d1e92cf6 6129
9f3d73bc
DM
6130 # test if requested format is supported
6131 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
6132 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6133 $d->{format} = $defFormat if !$supported;
d1e92cf6 6134
9f3d73bc
DM
6135 my $name;
6136 if ($d->{is_cloudinit}) {
6137 $name = "vm-$vmid-cloudinit";
c997e24a
ML
6138 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6139 if ($scfg->{path}) {
6140 $name .= ".$d->{format}";
6141 }
d1e92cf6
DM
6142 }
6143
4df98f2f
TL
6144 my $volid = PVE::Storage::vdisk_alloc(
6145 $storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
d1e92cf6 6146
9f3d73bc
DM
6147 print STDERR "new volume ID is '$volid'\n";
6148 $d->{volid} = $volid;
d1e92cf6 6149
9f3d73bc 6150 PVE::Storage::activate_volumes($storecfg, [$volid]);
d1e92cf6 6151
9f3d73bc 6152 $map->{$virtdev} = $volid;
d1e92cf6
DM
6153 }
6154
9f3d73bc
DM
6155 return $map;
6156};
d1e92cf6 6157
c62d7cf5 6158sub restore_update_config_line {
eabac302 6159 my ($cookie, $map, $line, $unique) = @_;
91bd6c90 6160
98a4b3fb
FE
6161 return '' if $line =~ m/^\#qmdump\#/;
6162 return '' if $line =~ m/^\#vzdump\#/;
6163 return '' if $line =~ m/^lock:/;
6164 return '' if $line =~ m/^unused\d+:/;
6165 return '' if $line =~ m/^parent:/;
6166
6167 my $res = '';
91bd6c90 6168
b5b99790 6169 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
6170 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6171 # try to convert old 1.X settings
6172 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6173 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
6174 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 6175 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
6176 my $net = {
6177 model => $model,
6178 bridge => "vmbr$ind",
6179 macaddr => $macaddr,
6180 };
6181 my $netstr = print_net($net);
6182
98a4b3fb 6183 $res .= "net$cookie->{netcount}: $netstr\n";
91bd6c90
DM
6184 $cookie->{netcount}++;
6185 }
6186 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6187 my ($id, $netstr) = ($1, $2);
6188 my $net = parse_net($netstr);
b5b99790 6189 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90 6190 $netstr = print_net($net);
98a4b3fb 6191 $res .= "$id: $netstr\n";
f9dde219 6192 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
91bd6c90 6193 my $virtdev = $1;
907ea891 6194 my $value = $3;
d9faf790
WB
6195 my $di = parse_drive($virtdev, $value);
6196 if (defined($di->{backup}) && !$di->{backup}) {
98a4b3fb 6197 $res .= "#$line";
c0f7406e 6198 } elsif ($map->{$virtdev}) {
8fd57431 6199 delete $di->{format}; # format can change on restore
91bd6c90 6200 $di->{file} = $map->{$virtdev};
71c58bb7 6201 $value = print_drive($di);
98a4b3fb 6202 $res .= "$virtdev: $value\n";
91bd6c90 6203 } else {
98a4b3fb 6204 $res .= $line;
91bd6c90 6205 }
1a0c2f03 6206 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 6207 my $vmgenid = $1;
6ee499ff 6208 if ($vmgenid ne '0') {
1a0c2f03 6209 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
6210 $vmgenid = generate_uuid();
6211 }
98a4b3fb 6212 $res .= "vmgenid: $vmgenid\n";
19a5dd55
WL
6213 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6214 my ($uuid, $uuid_str);
6215 UUID::generate($uuid);
6216 UUID::unparse($uuid, $uuid_str);
6217 my $smbios1 = parse_smbios1($2);
6218 $smbios1->{uuid} = $uuid_str;
98a4b3fb 6219 $res .= $1.print_smbios1($smbios1)."\n";
91bd6c90 6220 } else {
98a4b3fb 6221 $res .= $line;
91bd6c90 6222 }
98a4b3fb
FE
6223
6224 return $res;
c62d7cf5 6225}
9f3d73bc
DM
6226
6227my $restore_deactivate_volumes = sub {
6228 my ($storecfg, $devinfo) = @_;
6229
6230 my $vollist = [];
6231 foreach my $devname (keys %$devinfo) {
6232 my $volid = $devinfo->{$devname}->{volid};
6233 push @$vollist, $volid if $volid;
6234 }
6235
6236 PVE::Storage::deactivate_volumes($storecfg, $vollist);
6237};
6238
6239my $restore_destroy_volumes = sub {
6240 my ($storecfg, $devinfo) = @_;
6241
6242 foreach my $devname (keys %$devinfo) {
6243 my $volid = $devinfo->{$devname}->{volid};
6244 next if !$volid;
6245 eval {
6246 if ($volid =~ m|^/|) {
6247 unlink $volid || die 'unlink failed\n';
6248 } else {
6249 PVE::Storage::vdisk_free($storecfg, $volid);
6250 }
6251 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6252 };
6253 print STDERR "unable to cleanup '$volid' - $@" if $@;
6254 }
6255};
91bd6c90
DM
6256
6257sub scan_volids {
9a8ba127 6258 my ($cfg, $vmid) = @_;
91bd6c90 6259
9a8ba127 6260 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid, undef, 'images');
91bd6c90
DM
6261
6262 my $volid_hash = {};
6263 foreach my $storeid (keys %$info) {
6264 foreach my $item (@{$info->{$storeid}}) {
6265 next if !($item->{volid} && $item->{size});
5996a936 6266 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
6267 $volid_hash->{$item->{volid}} = $item;
6268 }
6269 }
6270
6271 return $volid_hash;
6272}
6273
68b108ee 6274sub update_disk_config {
91bd6c90 6275 my ($vmid, $conf, $volid_hash) = @_;
be190583 6276
91bd6c90 6277 my $changes;
9b29cbd0 6278 my $prefix = "VM $vmid";
91bd6c90 6279
c449137a
DC
6280 # used and unused disks
6281 my $referenced = {};
91bd6c90 6282
5996a936
DM
6283 # Note: it is allowed to define multiple storages with same path (alias), so
6284 # we need to check both 'volid' and real 'path' (two different volid can point
6285 # to the same path).
6286
c449137a 6287 my $referencedpath = {};
be190583 6288
91bd6c90 6289 # update size info
0c4fef3f 6290 PVE::QemuConfig->foreach_volume($conf, sub {
ca04977c 6291 my ($opt, $drive) = @_;
91bd6c90 6292
ca04977c
FE
6293 my $volid = $drive->{file};
6294 return if !$volid;
4df98f2f 6295 my $volume = $volid_hash->{$volid};
91bd6c90 6296
ca04977c
FE
6297 # mark volid as "in-use" for next step
6298 $referenced->{$volid} = 1;
4df98f2f 6299 if ($volume && (my $path = $volume->{path})) {
ca04977c 6300 $referencedpath->{$path} = 1;
91bd6c90 6301 }
ca04977c
FE
6302
6303 return if drive_is_cdrom($drive);
4df98f2f 6304 return if !$volume;
ca04977c 6305
4df98f2f 6306 my ($updated, $msg) = PVE::QemuServer::Drive::update_disksize($drive, $volume->{size});
ca04977c
FE
6307 if (defined($updated)) {
6308 $changes = 1;
6309 $conf->{$opt} = print_drive($updated);
9b29cbd0 6310 print "$prefix ($opt): $msg\n";
ca04977c
FE
6311 }
6312 });
91bd6c90 6313
5996a936 6314 # remove 'unusedX' entry if volume is used
ca04977c
FE
6315 PVE::QemuConfig->foreach_unused_volume($conf, sub {
6316 my ($opt, $drive) = @_;
6317
6318 my $volid = $drive->{file};
6319 return if !$volid;
6320
f7d1505b
TL
6321 my $path;
6322 $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 6323 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
68b108ee 6324 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5996a936
DM
6325 $changes = 1;
6326 delete $conf->{$opt};
6327 }
c449137a
DC
6328
6329 $referenced->{$volid} = 1;
6330 $referencedpath->{$path} = 1 if $path;
ca04977c 6331 });
5996a936 6332
91bd6c90
DM
6333 foreach my $volid (sort keys %$volid_hash) {
6334 next if $volid =~ m/vm-$vmid-state-/;
c449137a 6335 next if $referenced->{$volid};
5996a936
DM
6336 my $path = $volid_hash->{$volid}->{path};
6337 next if !$path; # just to be sure
c449137a 6338 next if $referencedpath->{$path};
91bd6c90 6339 $changes = 1;
53b81297 6340 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
68b108ee 6341 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
c449137a 6342 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
6343 }
6344
6345 return $changes;
6346}
6347
6348sub rescan {
9224dcee 6349 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 6350
20519efc 6351 my $cfg = PVE::Storage::config();
91bd6c90 6352
53b81297 6353 print "rescan volumes...\n";
9a8ba127 6354 my $volid_hash = scan_volids($cfg, $vmid);
91bd6c90
DM
6355
6356 my $updatefn = sub {
6357 my ($vmid) = @_;
6358
ffda963f 6359 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 6360
ffda963f 6361 PVE::QemuConfig->check_lock($conf);
91bd6c90 6362
03da3f0d
DM
6363 my $vm_volids = {};
6364 foreach my $volid (keys %$volid_hash) {
6365 my $info = $volid_hash->{$volid};
6366 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
6367 }
6368
68b108ee 6369 my $changes = update_disk_config($vmid, $conf, $vm_volids);
91bd6c90 6370
9224dcee 6371 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
6372 };
6373
6374 if (defined($vmid)) {
6375 if ($nolock) {
6376 &$updatefn($vmid);
6377 } else {
ffda963f 6378 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
6379 }
6380 } else {
6381 my $vmlist = config_list();
6382 foreach my $vmid (keys %$vmlist) {
6383 if ($nolock) {
6384 &$updatefn($vmid);
6385 } else {
ffda963f 6386 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 6387 }
91bd6c90
DM
6388 }
6389 }
6390}
6391
9f3d73bc
DM
6392sub restore_proxmox_backup_archive {
6393 my ($archive, $vmid, $user, $options) = @_;
6394
6395 my $storecfg = PVE::Storage::config();
6396
6397 my ($storeid, $volname) = PVE::Storage::parse_volume_id($archive);
6398 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6399
9f3d73bc 6400 my $fingerprint = $scfg->{fingerprint};
503e96f8 6401 my $keyfile = PVE::Storage::PBSPlugin::pbs_encryption_key_file_name($storecfg, $storeid);
9f3d73bc 6402
fbec3f89 6403 my $repo = PVE::PBSClient::get_repository($scfg);
dea4b04c 6404
26731a3c 6405 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
9f3d73bc
DM
6406 my $password = PVE::Storage::PBSPlugin::pbs_get_password($scfg, $storeid);
6407 local $ENV{PBS_PASSWORD} = $password;
6408 local $ENV{PBS_FINGERPRINT} = $fingerprint if defined($fingerprint);
6409
6410 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6411 PVE::Storage::parse_volname($storecfg, $archive);
6412
6413 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6414
6415 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6416
6417 my $tmpdir = "/var/tmp/vzdumptmp$$";
6418 rmtree $tmpdir;
6419 mkpath $tmpdir;
6420
6421 my $conffile = PVE::QemuConfig->config_file($vmid);
9f3d73bc
DM
6422 # disable interrupts (always do cleanups)
6423 local $SIG{INT} =
6424 local $SIG{TERM} =
6425 local $SIG{QUIT} =
6426 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
6427
6428 # Note: $oldconf is undef if VM does not exists
6429 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6430 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
98a4b3fb 6431 my $new_conf_raw = '';
9f3d73bc
DM
6432
6433 my $rpcenv = PVE::RPCEnvironment::get();
6434 my $devinfo = {};
6435
6436 eval {
6437 # enable interrupts
6438 local $SIG{INT} =
6439 local $SIG{TERM} =
6440 local $SIG{QUIT} =
6441 local $SIG{HUP} =
6442 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
6443
6444 my $cfgfn = "$tmpdir/qemu-server.conf";
6445 my $firewall_config_fn = "$tmpdir/fw.conf";
6446 my $index_fn = "$tmpdir/index.json";
6447
6448 my $cmd = "restore";
6449
6450 my $param = [$pbs_backup_name, "index.json", $index_fn];
6451 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6452 my $index = PVE::Tools::file_get_contents($index_fn);
6453 $index = decode_json($index);
6454
6455 # print Dumper($index);
6456 foreach my $info (@{$index->{files}}) {
6457 if ($info->{filename} =~ m/^(drive-\S+).img.fidx$/) {
6458 my $devname = $1;
6459 if ($info->{size} =~ m/^(\d+)$/) { # untaint size
6460 $devinfo->{$devname}->{size} = $1;
6461 } else {
6462 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6463 }
6464 }
6465 }
6466
4df98f2f
TL
6467 my $is_qemu_server_backup = scalar(
6468 grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}}
6469 );
9f3d73bc
DM
6470 if (!$is_qemu_server_backup) {
6471 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6472 }
6473 my $has_firewall_config = scalar(grep { $_->{filename} eq 'fw.conf.blob' } @{$index->{files}});
6474
6475 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6476 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6477
6478 if ($has_firewall_config) {
6479 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6480 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6481
6482 my $pve_firewall_dir = '/etc/pve/firewall';
6483 mkdir $pve_firewall_dir; # make sure the dir exists
6484 PVE::Tools::file_copy($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6485 }
6486
6487 my $fh = IO::File->new($cfgfn, "r") ||
a1cbe55c 6488 die "unable to read qemu-server.conf - $!\n";
9f3d73bc
DM
6489
6490 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6491
6492 # fixme: rate limit?
6493
6494 # create empty/temp config
6495 PVE::Tools::file_set_contents($conffile, "memory: 128\nlock: create");
6496
6497 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6498
6499 # allocate volumes
6500 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6501
6f94e162
SR
6502 foreach my $virtdev (sort keys %$virtdev_hash) {
6503 my $d = $virtdev_hash->{$virtdev};
6504 next if $d->{is_cloudinit}; # no need to restore cloudinit
9f3d73bc 6505
55c7f9cf 6506 # this fails if storage is unavailable
6f94e162 6507 my $volid = $d->{volid};
6f94e162 6508 my $path = PVE::Storage::path($storecfg, $volid);
9f3d73bc 6509
f9dde219
SR
6510 # for live-restore we only want to preload the efidisk and TPM state
6511 next if $options->{live} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
55c7f9cf 6512
6f94e162
SR
6513 my $pbs_restore_cmd = [
6514 '/usr/bin/pbs-restore',
6515 '--repository', $repo,
6516 $pbs_backup_name,
6517 "$d->{devname}.img.fidx",
6518 $path,
6519 '--verbose',
6520 ];
55fb78aa 6521
6f94e162
SR
6522 push @$pbs_restore_cmd, '--format', $d->{format} if $d->{format};
6523 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e $keyfile;
9f3d73bc 6524
6f94e162
SR
6525 if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
6526 push @$pbs_restore_cmd, '--skip-zero';
26731a3c 6527 }
6f94e162
SR
6528
6529 my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
6530 print "restore proxmox backup image: $dbg_cmdstring\n";
6531 run_command($pbs_restore_cmd);
9f3d73bc
DM
6532 }
6533
6534 $fh->seek(0, 0) || die "seek failed - $!\n";
6535
9f3d73bc
DM
6536 my $cookie = { netcount => 0 };
6537 while (defined(my $line = <$fh>)) {
c62d7cf5 6538 $new_conf_raw .= restore_update_config_line(
98a4b3fb 6539 $cookie,
98a4b3fb
FE
6540 $map,
6541 $line,
6542 $options->{unique},
6543 );
9f3d73bc
DM
6544 }
6545
6546 $fh->close();
9f3d73bc
DM
6547 };
6548 my $err = $@;
6549
26731a3c
SR
6550 if ($err || !$options->{live}) {
6551 $restore_deactivate_volumes->($storecfg, $devinfo);
6552 }
9f3d73bc
DM
6553
6554 rmtree $tmpdir;
6555
6556 if ($err) {
9f3d73bc
DM
6557 $restore_destroy_volumes->($storecfg, $devinfo);
6558 die $err;
6559 }
6560
f7551170
SR
6561 if ($options->{live}) {
6562 # keep lock during live-restore
6563 $new_conf_raw .= "\nlock: create";
6564 }
6565
98a4b3fb 6566 PVE::Tools::file_set_contents($conffile, $new_conf_raw);
9f3d73bc
DM
6567
6568 PVE::Cluster::cfs_update(); # make sure we read new file
6569
6570 eval { rescan($vmid, 1); };
6571 warn $@ if $@;
26731a3c
SR
6572
6573 PVE::AccessControl::add_vm_to_pool($vmid, $options->{pool}) if $options->{pool};
6574
6575 if ($options->{live}) {
fefd65a1
SR
6576 # enable interrupts
6577 local $SIG{INT} =
6578 local $SIG{TERM} =
6579 local $SIG{QUIT} =
6580 local $SIG{HUP} =
6581 local $SIG{PIPE} = sub { die "got signal ($!) - abort\n"; };
26731a3c 6582
fefd65a1
SR
6583 my $conf = PVE::QemuConfig->load_config($vmid);
6584 die "cannot do live-restore for template\n" if PVE::QemuConfig->is_template($conf);
26731a3c 6585
f9dde219
SR
6586 # these special drives are already restored before start
6587 delete $devinfo->{'drive-efidisk0'};
6588 delete $devinfo->{'drive-tpmstate0-backup'};
fefd65a1 6589 pbs_live_restore($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
f7551170
SR
6590
6591 PVE::QemuConfig->remove_lock($vmid, "create");
26731a3c
SR
6592 }
6593}
6594
6595sub pbs_live_restore {
6596 my ($vmid, $conf, $storecfg, $restored_disks, $repo, $keyfile, $snap) = @_;
6597
88cabb62 6598 print "starting VM for live-restore\n";
daf829ec 6599 print "repository: '$repo', snapshot: '$snap'\n";
26731a3c
SR
6600
6601 my $pbs_backing = {};
8986e36e 6602 for my $ds (keys %$restored_disks) {
26731a3c 6603 $ds =~ m/^drive-(.*)$/;
88cabb62
SR
6604 my $confname = $1;
6605 $pbs_backing->{$confname} = {
26731a3c
SR
6606 repository => $repo,
6607 snapshot => $snap,
6608 archive => "$ds.img.fidx",
6609 };
88cabb62
SR
6610 $pbs_backing->{$confname}->{keyfile} = $keyfile if -e $keyfile;
6611
6612 my $drive = parse_drive($confname, $conf->{$confname});
6613 print "restoring '$ds' to '$drive->{file}'\n";
26731a3c
SR
6614 }
6615
fd70c843 6616 my $drives_streamed = 0;
26731a3c
SR
6617 eval {
6618 # make sure HA doesn't interrupt our restore by stopping the VM
6619 if (PVE::HA::Config::vm_is_ha_managed($vmid)) {
fd70c843 6620 run_command(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
26731a3c
SR
6621 }
6622
fd70c843
TL
6623 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6624 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
bfb12678 6625 vm_start_nolock($storecfg, $vmid, $conf, {paused => 1, 'pbs-backing' => $pbs_backing}, {});
26731a3c 6626
26697640
SR
6627 my $qmeventd_fd = register_qmeventd_handle($vmid);
6628
26731a3c
SR
6629 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6630 # this will effectively collapse the backing image chain consisting of
6631 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6632 # removes itself once all backing images vanish with 'auto-remove=on')
6633 my $jobs = {};
8986e36e 6634 for my $ds (sort keys %$restored_disks) {
26731a3c
SR
6635 my $job_id = "restore-$ds";
6636 mon_cmd($vmid, 'block-stream',
6637 'job-id' => $job_id,
6638 device => "$ds",
6639 );
6640 $jobs->{$job_id} = {};
6641 }
6642
6643 mon_cmd($vmid, 'cont');
6644 qemu_drive_mirror_monitor($vmid, undef, $jobs, 'auto', 0, 'stream');
6645
a09b39f1
TL
6646 print "restore-drive jobs finished successfully, removing all tracking block devices"
6647 ." to disconnect from Proxmox Backup Server\n";
6648
8986e36e 6649 for my $ds (sort keys %$restored_disks) {
26731a3c
SR
6650 mon_cmd($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6651 }
26697640
SR
6652
6653 close($qmeventd_fd);
26731a3c
SR
6654 };
6655
6656 my $err = $@;
6657
6658 if ($err) {
6659 warn "An error occured during live-restore: $err\n";
6660 _do_vm_stop($storecfg, $vmid, 1, 1, 10, 0, 1);
6661 die "live-restore failed\n";
6662 }
9f3d73bc
DM
6663}
6664
91bd6c90
DM
6665sub restore_vma_archive {
6666 my ($archive, $vmid, $user, $opts, $comp) = @_;
6667
91bd6c90
DM
6668 my $readfrom = $archive;
6669
7c536e11
WB
6670 my $cfg = PVE::Storage::config();
6671 my $commands = [];
6672 my $bwlimit = $opts->{bwlimit};
6673
6674 my $dbg_cmdstring = '';
6675 my $add_pipe = sub {
6676 my ($cmd) = @_;
6677 push @$commands, $cmd;
6678 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6679 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6680 $readfrom = '-';
7c536e11
WB
6681 };
6682
6683 my $input = undef;
6684 if ($archive eq '-') {
6685 $input = '<&STDIN';
6686 } else {
6687 # If we use a backup from a PVE defined storage we also consider that
6688 # storage's rate limit:
6689 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6690 if (defined($volid)) {
6691 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6692 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6693 if ($readlimit) {
6694 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6695 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6696 $add_pipe->($cstream);
6697 }
6698 }
6699 }
6700
6701 if ($comp) {
c6d51783
AA
6702 my $info = PVE::Storage::decompressor_info('vma', $comp);
6703 my $cmd = $info->{decompressor};
6704 push @$cmd, $readfrom;
7c536e11 6705 $add_pipe->($cmd);
91bd6c90
DM
6706 }
6707
6708 my $tmpdir = "/var/tmp/vzdumptmp$$";
6709 rmtree $tmpdir;
6710
6711 # disable interrupts (always do cleanups)
5b97ef24
TL
6712 local $SIG{INT} =
6713 local $SIG{TERM} =
6714 local $SIG{QUIT} =
6715 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6716
6717 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6718 POSIX::mkfifo($mapfifo, 0600);
6719 my $fifofh;
808a65b5 6720 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
91bd6c90 6721
7c536e11 6722 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6723
6724 my $oldtimeout;
6725 my $timeout = 5;
6726
6727 my $devinfo = {};
6728
6729 my $rpcenv = PVE::RPCEnvironment::get();
6730
ffda963f 6731 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90 6732
ae200950 6733 # Note: $oldconf is undef if VM does not exist
ffda963f
FG
6734 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6735 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
98a4b3fb 6736 my $new_conf_raw = '';
ed221350 6737
7c536e11
WB
6738 my %storage_limits;
6739
91bd6c90 6740 my $print_devmap = sub {
91bd6c90
DM
6741 my $cfgfn = "$tmpdir/qemu-server.conf";
6742
6743 # we can read the config - that is already extracted
6744 my $fh = IO::File->new($cfgfn, "r") ||
a1cbe55c 6745 die "unable to read qemu-server.conf - $!\n";
91bd6c90 6746
6738ab9c 6747 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6748 if (-f $fwcfgfn) {
6749 my $pve_firewall_dir = '/etc/pve/firewall';
6750 mkdir $pve_firewall_dir; # make sure the dir exists
6751 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6752 }
6738ab9c 6753
9f3d73bc 6754 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
91bd6c90 6755
c8964278
FE
6756 foreach my $info (values %{$virtdev_hash}) {
6757 my $storeid = $info->{storeid};
6758 next if defined($storage_limits{$storeid});
6759
6760 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$storeid], $bwlimit) // 0;
6761 print STDERR "rate limit for storage $storeid: $limit KiB/s\n" if $limit;
6762 $storage_limits{$storeid} = $limit * 1024;
7c536e11
WB
6763 }
6764
91bd6c90 6765 foreach my $devname (keys %$devinfo) {
be190583
DM
6766 die "found no device mapping information for device '$devname'\n"
6767 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6768 }
6769
ed221350 6770 # create empty/temp config
be190583 6771 if ($oldconf) {
ed221350 6772 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
d1e92cf6 6773 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
ed221350
DM
6774 }
6775
9f3d73bc
DM
6776 # allocate volumes
6777 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6778
6779 # print restore information to $fifofh
91bd6c90
DM
6780 foreach my $virtdev (sort keys %$virtdev_hash) {
6781 my $d = $virtdev_hash->{$virtdev};
9f3d73bc
DM
6782 next if $d->{is_cloudinit}; # no need to restore cloudinit
6783
7c536e11 6784 my $storeid = $d->{storeid};
9f3d73bc 6785 my $volid = $d->{volid};
7c536e11
WB
6786
6787 my $map_opts = '';
6788 if (my $limit = $storage_limits{$storeid}) {
6789 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6790 }
8fd57431 6791
91bd6c90 6792 my $write_zeros = 1;
88240a83 6793 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6794 $write_zeros = 0;
6795 }
6796
9f3d73bc 6797 my $path = PVE::Storage::path($cfg, $volid);
87056e18 6798
9f3d73bc 6799 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 6800
9f3d73bc 6801 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
91bd6c90
DM
6802 }
6803
6804 $fh->seek(0, 0) || die "seek failed - $!\n";
6805
91bd6c90
DM
6806 my $cookie = { netcount => 0 };
6807 while (defined(my $line = <$fh>)) {
c62d7cf5 6808 $new_conf_raw .= restore_update_config_line(
98a4b3fb 6809 $cookie,
98a4b3fb
FE
6810 $map,
6811 $line,
6812 $opts->{unique},
6813 );
91bd6c90
DM
6814 }
6815
6816 $fh->close();
91bd6c90
DM
6817 };
6818
6819 eval {
6820 # enable interrupts
6cb0144a
EK
6821 local $SIG{INT} =
6822 local $SIG{TERM} =
6823 local $SIG{QUIT} =
6824 local $SIG{HUP} =
6825 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6826 local $SIG{ALRM} = sub { die "got timeout\n"; };
6827
6828 $oldtimeout = alarm($timeout);
6829
6830 my $parser = sub {
6831 my $line = shift;
6832
6833 print "$line\n";
6834
6835 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6836 my ($dev_id, $size, $devname) = ($1, $2, $3);
6837 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6838 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6839 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6840 # the timeout now for disk allocation (set to 10 minutes, so
6841 # that we always timeout if something goes wrong)
6842 alarm(600);
91bd6c90
DM
6843 &$print_devmap();
6844 print $fifofh "done\n";
6845 my $tmp = $oldtimeout || 0;
6846 $oldtimeout = undef;
6847 alarm($tmp);
6848 close($fifofh);
808a65b5 6849 $fifofh = undef;
91bd6c90
DM
6850 }
6851 };
be190583 6852
7c536e11
WB
6853 print "restore vma archive: $dbg_cmdstring\n";
6854 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6855 };
6856 my $err = $@;
6857
6858 alarm($oldtimeout) if $oldtimeout;
6859
9f3d73bc 6860 $restore_deactivate_volumes->($cfg, $devinfo);
5f96f4df 6861
808a65b5 6862 close($fifofh) if $fifofh;
91bd6c90 6863 unlink $mapfifo;
9f3d73bc 6864 rmtree $tmpdir;
91bd6c90
DM
6865
6866 if ($err) {
9f3d73bc 6867 $restore_destroy_volumes->($cfg, $devinfo);
91bd6c90
DM
6868 die $err;
6869 }
6870
98a4b3fb 6871 PVE::Tools::file_set_contents($conffile, $new_conf_raw);
91bd6c90 6872
ed221350
DM
6873 PVE::Cluster::cfs_update(); # make sure we read new file
6874
91bd6c90
DM
6875 eval { rescan($vmid, 1); };
6876 warn $@ if $@;
26731a3c
SR
6877
6878 PVE::AccessControl::add_vm_to_pool($vmid, $opts->{pool}) if $opts->{pool};
91bd6c90
DM
6879}
6880
6881sub restore_tar_archive {
6882 my ($archive, $vmid, $user, $opts) = @_;
6883
9c502e26 6884 if ($archive ne '-') {
ed221350 6885 my $firstfile = tar_archive_read_firstfile($archive);
32e54050 6886 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
9c502e26
DM
6887 if $firstfile ne 'qemu-server.conf';
6888 }
3e16d5fc 6889
20519efc 6890 my $storecfg = PVE::Storage::config();
ebb55558 6891
4b026937
TL
6892 # avoid zombie disks when restoring over an existing VM -> cleanup first
6893 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6894 # skiplock=1 because qmrestore has set the 'create' lock itself already
ffda963f 6895 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
b04ea584 6896 destroy_vm($storecfg, $vmid, 1, { lock => 'restore' }) if -f $vmcfgfn;
ed221350 6897
3e16d5fc
DM
6898 my $tocmd = "/usr/lib/qemu-server/qmextract";
6899
2415a446 6900 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6901 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6902 $tocmd .= ' --prealloc' if $opts->{prealloc};
6903 $tocmd .= ' --info' if $opts->{info};
6904
a0d1b1a2 6905 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6906 # so we pipe to zcat
2415a446
DM
6907 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6908 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6909
6910 my $tmpdir = "/var/tmp/vzdumptmp$$";
6911 mkpath $tmpdir;
6912
6913 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6914 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6915 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6916
ffda963f 6917 my $conffile = PVE::QemuConfig->config_file($vmid);
98a4b3fb 6918 my $new_conf_raw = '';
3e16d5fc
DM
6919
6920 # disable interrupts (always do cleanups)
6cb0144a
EK
6921 local $SIG{INT} =
6922 local $SIG{TERM} =
6923 local $SIG{QUIT} =
6924 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6925
afdb31d5 6926 eval {
3e16d5fc 6927 # enable interrupts
6cb0144a
EK
6928 local $SIG{INT} =
6929 local $SIG{TERM} =
6930 local $SIG{QUIT} =
6931 local $SIG{HUP} =
6932 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6933
9c502e26
DM
6934 if ($archive eq '-') {
6935 print "extracting archive from STDIN\n";
6936 run_command($cmd, input => "<&STDIN");
6937 } else {
6938 print "extracting archive '$archive'\n";
6939 run_command($cmd);
6940 }
3e16d5fc
DM
6941
6942 return if $opts->{info};
6943
6944 # read new mapping
6945 my $map = {};
6946 my $statfile = "$tmpdir/qmrestore.stat";
6947 if (my $fd = IO::File->new($statfile, "r")) {
6948 while (defined (my $line = <$fd>)) {
6949 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6950 $map->{$1} = $2 if $1;
6951 } else {
6952 print STDERR "unable to parse line in statfile - $line\n";
6953 }
6954 }
6955 $fd->close();
6956 }
6957
6958 my $confsrc = "$tmpdir/qemu-server.conf";
6959
f7d1505b 6960 my $srcfd = IO::File->new($confsrc, "r") || die "unable to open file '$confsrc'\n";
3e16d5fc 6961
91bd6c90 6962 my $cookie = { netcount => 0 };
3e16d5fc 6963 while (defined (my $line = <$srcfd>)) {
c62d7cf5 6964 $new_conf_raw .= restore_update_config_line(
98a4b3fb 6965 $cookie,
98a4b3fb
FE
6966 $map,
6967 $line,
6968 $opts->{unique},
6969 );
3e16d5fc
DM
6970 }
6971
6972 $srcfd->close();
3e16d5fc 6973 };
7dc7f315 6974 if (my $err = $@) {
ed221350 6975 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
3e16d5fc 6976 die $err;
afdb31d5 6977 }
3e16d5fc
DM
6978
6979 rmtree $tmpdir;
6980
98a4b3fb 6981 PVE::Tools::file_set_contents($conffile, $new_conf_raw);
91bd6c90 6982
ed221350
DM
6983 PVE::Cluster::cfs_update(); # make sure we read new file
6984
91bd6c90
DM
6985 eval { rescan($vmid, 1); };
6986 warn $@ if $@;
3e16d5fc
DM
6987};
6988
65a5ce88 6989sub foreach_storage_used_by_vm {
18bfb361
DM
6990 my ($conf, $func) = @_;
6991
6992 my $sidhash = {};
6993
912792e2 6994 PVE::QemuConfig->foreach_volume($conf, sub {
8ddbcf8b
FG
6995 my ($ds, $drive) = @_;
6996 return if drive_is_cdrom($drive);
18bfb361
DM
6997
6998 my $volid = $drive->{file};
6999
7000 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 7001 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 7002 });
18bfb361
DM
7003
7004 foreach my $sid (sort keys %$sidhash) {
7005 &$func($sid);
7006 }
7007}
7008
6c9f59c1
TL
7009my $qemu_snap_storage = {
7010 rbd => 1,
7011};
e5eaa028
WL
7012sub do_snapshots_with_qemu {
7013 my ($storecfg, $volid) = @_;
7014
7015 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 7016 my $scfg = $storecfg->{ids}->{$storage_name};
f7d1505b 7017 die "could not find storage '$storage_name'\n" if !defined($scfg);
e5eaa028 7018
8aa2ed7c 7019 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
7020 return 1;
7021 }
7022
7023 if ($volid =~ m/\.(qcow2|qed)$/){
7024 return 1;
7025 }
7026
d1c1af4b 7027 return;
e5eaa028
WL
7028}
7029
4dcc780c 7030sub qga_check_running {
a4938c72 7031 my ($vmid, $nowarn) = @_;
4dcc780c 7032
0a13e08e 7033 eval { mon_cmd($vmid, "guest-ping", timeout => 3); };
4dcc780c 7034 if ($@) {
a4938c72 7035 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
7036 return 0;
7037 }
7038 return 1;
7039}
7040
04a69bb4
AD
7041sub template_create {
7042 my ($vmid, $conf, $disk) = @_;
7043
04a69bb4 7044 my $storecfg = PVE::Storage::config();
04a69bb4 7045
912792e2 7046 PVE::QemuConfig->foreach_volume($conf, sub {
9cd07842
DM
7047 my ($ds, $drive) = @_;
7048
7049 return if drive_is_cdrom($drive);
7050 return if $disk && $ds ne $disk;
7051
7052 my $volid = $drive->{file};
bbd56097 7053 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 7054
04a69bb4
AD
7055 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
7056 $drive->{file} = $voliddst;
71c58bb7 7057 $conf->{$ds} = print_drive($drive);
ffda963f 7058 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 7059 });
04a69bb4
AD
7060}
7061
92bdc3f0
DC
7062sub convert_iscsi_path {
7063 my ($path) = @_;
7064
7065 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
7066 my $portal = $1;
7067 my $target = $2;
7068 my $lun = $3;
7069
7070 my $initiator_name = get_initiator_name();
7071
7072 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7073 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7074 }
7075
7076 die "cannot convert iscsi path '$path', unkown format\n";
7077}
7078
5133de42 7079sub qemu_img_convert {
988e2714 7080 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
7081
7082 my $storecfg = PVE::Storage::config();
7083 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
7084 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
7085
af1f1ec0 7086 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 7087
af1f1ec0
DC
7088 my $cachemode;
7089 my $src_path;
7090 my $src_is_iscsi = 0;
bdd1feef 7091 my $src_format;
6bb91c17 7092
af1f1ec0
DC
7093 if ($src_storeid) {
7094 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 7095 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
7096 $src_format = qemu_img_format($src_scfg, $src_volname);
7097 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
7098 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
7099 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
7100 } elsif (-f $src_volid) {
7101 $src_path = $src_volid;
e0fd2b2f 7102 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
af1f1ec0
DC
7103 $src_format = $1;
7104 }
7105 }
5133de42 7106
af1f1ec0 7107 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 7108
af1f1ec0
DC
7109 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
7110 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
7111 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
7112 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 7113
af1f1ec0
DC
7114 my $cmd = [];
7115 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
bdd1feef
TL
7116 push @$cmd, '-l', "snapshot.name=$snapname"
7117 if $snapname && $src_format && $src_format eq "qcow2";
af1f1ec0
DC
7118 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
7119 push @$cmd, '-T', $cachemode if defined($cachemode);
7120
7121 if ($src_is_iscsi) {
7122 push @$cmd, '--image-opts';
7123 $src_path = convert_iscsi_path($src_path);
bdd1feef 7124 } elsif ($src_format) {
af1f1ec0
DC
7125 push @$cmd, '-f', $src_format;
7126 }
92bdc3f0 7127
af1f1ec0
DC
7128 if ($dst_is_iscsi) {
7129 push @$cmd, '--target-image-opts';
7130 $dst_path = convert_iscsi_path($dst_path);
7131 } else {
7132 push @$cmd, '-O', $dst_format;
7133 }
92bdc3f0 7134
af1f1ec0 7135 push @$cmd, $src_path;
92bdc3f0 7136
af1f1ec0
DC
7137 if (!$dst_is_iscsi && $is_zero_initialized) {
7138 push @$cmd, "zeroinit:$dst_path";
7139 } else {
7140 push @$cmd, $dst_path;
7141 }
92bdc3f0 7142
af1f1ec0
DC
7143 my $parser = sub {
7144 my $line = shift;
7145 if($line =~ m/\((\S+)\/100\%\)/){
7146 my $percent = $1;
7147 my $transferred = int($size * $percent / 100);
b5e9d97b
TL
7148 my $total_h = render_bytes($size, 1);
7149 my $transferred_h = render_bytes($transferred, 1);
92bdc3f0 7150
6629f976 7151 print "transferred $transferred_h of $total_h ($percent%)\n";
988e2714 7152 }
5133de42 7153
af1f1ec0 7154 };
5133de42 7155
af1f1ec0
DC
7156 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
7157 my $err = $@;
7158 die "copy failed: $err" if $err;
5133de42
AD
7159}
7160
7161sub qemu_img_format {
7162 my ($scfg, $volname) = @_;
7163
e0fd2b2f 7164 if ($scfg->{path} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
5133de42 7165 return $1;
be190583 7166 } else {
5133de42 7167 return "raw";
5133de42
AD
7168 }
7169}
7170
cfad42af 7171sub qemu_drive_mirror {
bc6c8231 7172 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
cfad42af 7173
5a345967
AD
7174 $jobs = {} if !$jobs;
7175
7176 my $qemu_target;
7177 my $format;
35e4ab04 7178 $jobs->{"drive-$drive"} = {};
152fe752 7179
1e5143de 7180 if ($dst_volid =~ /^nbd:/) {
87955688 7181 $qemu_target = $dst_volid;
5a345967 7182 $format = "nbd";
5a345967 7183 } else {
5a345967
AD
7184 my $storecfg = PVE::Storage::config();
7185 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
7186
7187 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 7188
5a345967 7189 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 7190
5a345967 7191 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 7192
5a345967
AD
7193 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
7194 }
988e2714
WB
7195
7196 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
7197 $opts->{format} = $format if $format;
7198
bc6c8231
FG
7199 if (defined($src_bitmap)) {
7200 $opts->{sync} = 'incremental';
7201 $opts->{bitmap} = $src_bitmap;
7202 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7203 }
7204
9fa05d31 7205 if (defined($bwlimit)) {
f6409f61
TL
7206 $opts->{speed} = $bwlimit * 1024;
7207 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
7208 } else {
7209 print "drive mirror is starting for drive-$drive\n";
7210 }
21ccdb50 7211
6dde5ea2 7212 # if a job already runs for this device we get an error, catch it for cleanup
0a13e08e 7213 eval { mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
7214 if (my $err = $@) {
7215 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
7216 warn "$@\n" if $@;
7217 die "mirroring error: $err\n";
5a345967
AD
7218 }
7219
e02fb126 7220 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
5a345967
AD
7221}
7222
db1f8b39
FG
7223# $completion can be either
7224# 'complete': wait until all jobs are ready, block-job-complete them (default)
7225# 'cancel': wait until all jobs are ready, block-job-cancel them
7226# 'skip': wait until all jobs are ready, return with block jobs in ready state
9e671722 7227# 'auto': wait until all jobs disappear, only use for jobs which complete automatically
5a345967 7228sub qemu_drive_mirror_monitor {
9e671722 7229 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
e02fb126 7230
db1f8b39 7231 $completion //= 'complete';
9e671722 7232 $op //= "mirror";
2e953867 7233
08ac653f 7234 eval {
5a345967
AD
7235 my $err_complete = 0;
7236
3b56383b 7237 my $starttime = time ();
08ac653f 7238 while (1) {
9e671722 7239 die "block job ('$op') timed out\n" if $err_complete > 300;
5a345967 7240
0a13e08e 7241 my $stats = mon_cmd($vmid, "query-block-jobs");
3b56383b 7242 my $ctime = time();
08ac653f 7243
9e671722 7244 my $running_jobs = {};
0ea24bf0 7245 for my $stat (@$stats) {
9e671722
SR
7246 next if $stat->{type} ne $op;
7247 $running_jobs->{$stat->{device}} = $stat;
5a345967 7248 }
08ac653f 7249
5a345967 7250 my $readycounter = 0;
67fb9de6 7251
0ea24bf0 7252 for my $job_id (sort keys %$jobs) {
1057fc74 7253 my $job = $running_jobs->{$job_id};
5a345967 7254
1057fc74 7255 my $vanished = !defined($job);
0ea24bf0 7256 my $complete = defined($jobs->{$job_id}->{complete}) && $vanished;
9e671722 7257 if($complete || ($vanished && $completion eq 'auto')) {
3b56383b 7258 print "$job_id: $op-job finished\n";
0ea24bf0 7259 delete $jobs->{$job_id};
5a345967
AD
7260 next;
7261 }
7262
1057fc74 7263 die "$job_id: '$op' has been cancelled\n" if !defined($job);
f34ebd52 7264
1057fc74
TL
7265 my $busy = $job->{busy};
7266 my $ready = $job->{ready};
7267 if (my $total = $job->{len}) {
7268 my $transferred = $job->{offset} || 0;
5a345967
AD
7269 my $remaining = $total - $transferred;
7270 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 7271
3b56383b
TL
7272 my $duration = $ctime - $starttime;
7273 my $total_h = render_bytes($total, 1);
7274 my $transferred_h = render_bytes($transferred, 1);
7275
7276 my $status = sprintf(
7277 "transferred $transferred_h of $total_h ($percent%%) in %s",
7278 render_duration($duration),
7279 );
7280
7281 if ($ready) {
7282 if ($busy) {
7283 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7284 } else {
7285 $status .= ", ready";
7286 }
7287 }
67daf692
TL
7288 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready};
7289 $jobs->{$job_id}->{ready} = $ready;
5a345967 7290 }
f34ebd52 7291
1057fc74 7292 $readycounter++ if $job->{ready};
5a345967 7293 }
b467f79a 7294
5a345967
AD
7295 last if scalar(keys %$jobs) == 0;
7296
7297 if ($readycounter == scalar(keys %$jobs)) {
9e671722
SR
7298 print "all '$op' jobs are ready\n";
7299
7300 # do the complete later (or has already been done)
7301 last if $completion eq 'skip' || $completion eq 'auto';
5a345967
AD
7302
7303 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
7304 my $agent_running = $qga && qga_check_running($vmid);
7305 if ($agent_running) {
5619e74a 7306 print "freeze filesystem\n";
0a13e08e 7307 eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); };
5619e74a
AD
7308 } else {
7309 print "suspend vm\n";
7310 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
7311 }
7312
5a345967
AD
7313 # if we clone a disk for a new target vm, we don't switch the disk
7314 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 7315
1a988fd2 7316 if ($agent_running) {
5619e74a 7317 print "unfreeze filesystem\n";
0a13e08e 7318 eval { mon_cmd($vmid, "guest-fsfreeze-thaw"); };
5619e74a
AD
7319 } else {
7320 print "resume vm\n";
7321 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
7322 }
7323
2e953867 7324 last;
5a345967
AD
7325 } else {
7326
0ea24bf0 7327 for my $job_id (sort keys %$jobs) {
5a345967 7328 # try to switch the disk if source and destination are on the same guest
0ea24bf0 7329 print "$job_id: Completing block job_id...\n";
5a345967 7330
e02fb126 7331 my $op;
db1f8b39 7332 if ($completion eq 'complete') {
e02fb126 7333 $op = 'block-job-complete';
db1f8b39 7334 } elsif ($completion eq 'cancel') {
e02fb126
ML
7335 $op = 'block-job-cancel';
7336 } else {
7337 die "invalid completion value: $completion\n";
7338 }
0ea24bf0 7339 eval { mon_cmd($vmid, $op, device => $job_id) };
5a345967 7340 if ($@ =~ m/cannot be completed/) {
3b56383b 7341 print "$job_id: block job cannot be completed, trying again.\n";
5a345967
AD
7342 $err_complete++;
7343 }else {
0ea24bf0
TL
7344 print "$job_id: Completed successfully.\n";
7345 $jobs->{$job_id}->{complete} = 1;
5a345967
AD
7346 }
7347 }
2e953867 7348 }
08ac653f 7349 }
08ac653f 7350 sleep 1;
cfad42af 7351 }
08ac653f 7352 };
88383920 7353 my $err = $@;
08ac653f 7354
88383920 7355 if ($err) {
5a345967 7356 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
3b56383b 7357 die "block job ($op) error: $err";
88383920 7358 }
5a345967
AD
7359}
7360
7361sub qemu_blockjobs_cancel {
7362 my ($vmid, $jobs) = @_;
7363
7364 foreach my $job (keys %$jobs) {
bd2d5fe6 7365 print "$job: Cancelling block job\n";
0a13e08e 7366 eval { mon_cmd($vmid, "block-job-cancel", device => $job); };
5a345967
AD
7367 $jobs->{$job}->{cancel} = 1;
7368 }
7369
7370 while (1) {
0a13e08e 7371 my $stats = mon_cmd($vmid, "query-block-jobs");
5a345967
AD
7372
7373 my $running_jobs = {};
7374 foreach my $stat (@$stats) {
7375 $running_jobs->{$stat->{device}} = $stat;
7376 }
7377
7378 foreach my $job (keys %$jobs) {
7379
bd2d5fe6
WB
7380 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
7381 print "$job: Done.\n";
5a345967
AD
7382 delete $jobs->{$job};
7383 }
7384 }
7385
7386 last if scalar(keys %$jobs) == 0;
7387
7388 sleep 1;
cfad42af
AD
7389 }
7390}
7391
152fe752 7392sub clone_disk {
be190583 7393 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
818ce80e 7394 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
152fe752
DM
7395
7396 my $newvolid;
7397
7398 if (!$full) {
7399 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 7400 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
7401 push @$newvollist, $newvolid;
7402 } else {
5a345967 7403
152fe752
DM
7404 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
7405 $storeid = $storage if $storage;
7406
44549149 7407 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
7408
7409 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd 7410 my $name = undef;
d0abc774 7411 my $size = undef;
7fe8b44c
TL
7412 if (drive_is_cloudinit($drive)) {
7413 $name = "vm-$newvmid-cloudinit";
c997e24a
ML
7414 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7415 if ($scfg->{path}) {
7416 $name .= ".$dst_format";
7417 }
7fe8b44c
TL
7418 $snapname = undef;
7419 $size = PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE;
818ce80e
DC
7420 } elsif ($drivename eq 'efidisk0') {
7421 $size = get_efivars_size($conf);
f9dde219
SR
7422 } elsif ($drivename eq 'tpmstate0') {
7423 $size = PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE;
d0abc774 7424 } else {
3bae384f 7425 ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 10);
7fe8b44c 7426 }
b5688f69
FE
7427 $newvolid = PVE::Storage::vdisk_alloc(
7428 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7429 );
152fe752
DM
7430 push @$newvollist, $newvolid;
7431
3999f370 7432 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 7433
7fe8b44c 7434 if (drive_is_cloudinit($drive)) {
1b485263
ML
7435 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7436 # if this is the case, we have to complete any block-jobs still there from
7437 # previous drive-mirrors
7438 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7439 qemu_drive_mirror_monitor($vmid, $newvmid, $jobs, $completion, $qga);
7440 }
7fe8b44c
TL
7441 goto no_data_clone;
7442 }
7443
988e2714 7444 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 7445 if (!$running || $snapname) {
d189e590 7446 # TODO: handle bwlimits
818ce80e
DC
7447 if ($drivename eq 'efidisk0') {
7448 # the relevant data on the efidisk may be smaller than the source
7449 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7450 # that is given by the OVMF_VARS.fd
7451 my $src_path = PVE::Storage::path($storecfg, $drive->{file});
7452 my $dst_path = PVE::Storage::path($storecfg, $newvolid);
fdfdc80e
FE
7453
7454 # better for Ceph if block size is not too small, see bug #3324
7455 my $bs = 1024*1024;
7456
7457 run_command(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=$bs", "osize=$size",
4df98f2f 7458 "if=$src_path", "of=$dst_path"]);
818ce80e
DC
7459 } else {
7460 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
7461 }
152fe752 7462 } else {
2e541679 7463
f9dde219
SR
7464 die "cannot move TPM state while VM is running\n" if $drivename eq 'tpmstate0';
7465
2e541679 7466 my $kvmver = get_running_qemu_version ($vmid);
2ea5fb7e 7467 if (!min_version($kvmver, 2, 7)) {
961af8a3
WB
7468 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7469 if $drive->{iothread};
2e541679 7470 }
2af848a2 7471
4df98f2f
TL
7472 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7473 $completion, $qga, $bwlimit);
be190583 7474 }
152fe752
DM
7475 }
7476
7fe8b44c 7477no_data_clone:
3bae384f 7478 my ($size) = eval { PVE::Storage::volume_size_info($storecfg, $newvolid, 10) };
152fe752
DM
7479
7480 my $disk = $drive;
7481 $disk->{format} = undef;
7482 $disk->{file} = $newvolid;
3bae384f 7483 $disk->{size} = $size if defined($size);
152fe752
DM
7484
7485 return $disk;
7486}
7487
98cfd8b6
AD
7488sub get_running_qemu_version {
7489 my ($vmid) = @_;
0a13e08e 7490 my $res = mon_cmd($vmid, "query-version");
98cfd8b6
AD
7491 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7492}
7493
249c4a6c
AD
7494sub qemu_use_old_bios_files {
7495 my ($machine_type) = @_;
7496
7497 return if !$machine_type;
7498
7499 my $use_old_bios_files = undef;
7500
7501 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7502 $machine_type = $1;
7503 $use_old_bios_files = 1;
7504 } else {
4df98f2f 7505 my $version = extract_version($machine_type, kvm_user_version());
249c4a6c
AD
7506 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7507 # load new efi bios files on migration. So this hack is required to allow
7508 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7509 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
2ea5fb7e 7510 $use_old_bios_files = !min_version($version, 2, 4);
249c4a6c
AD
7511 }
7512
7513 return ($use_old_bios_files, $machine_type);
7514}
7515
818ce80e
DC
7516sub get_efivars_size {
7517 my ($conf) = @_;
7518 my $arch = get_vm_arch($conf);
7519 my (undef, $ovmf_vars) = get_ovmf_files($arch);
7520 die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
7521 return -s $ovmf_vars;
7522}
7523
7524sub update_efidisk_size {
7525 my ($conf) = @_;
7526
7527 return if !defined($conf->{efidisk0});
7528
7529 my $disk = PVE::QemuServer::parse_drive('efidisk0', $conf->{efidisk0});
7530 $disk->{size} = get_efivars_size($conf);
7531 $conf->{efidisk0} = print_drive($disk);
7532
7533 return;
7534}
7535
f9dde219
SR
7536sub update_tpmstate_size {
7537 my ($conf) = @_;
7538
7539 my $disk = PVE::QemuServer::parse_drive('tpmstate0', $conf->{tpmstate0});
7540 $disk->{size} = PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE;
7541 $conf->{tpmstate0} = print_drive($disk);
7542}
7543
96ed3574
WB
7544sub create_efidisk($$$$$) {
7545 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 7546
96ed3574
WB
7547 my (undef, $ovmf_vars) = get_ovmf_files($arch);
7548 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 7549
af1f1ec0
DC
7550 my $vars_size_b = -s $ovmf_vars;
7551 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
7552 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7553 PVE::Storage::activate_volumes($storecfg, [$volid]);
7554
af1f1ec0 7555 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
340dbcf7 7556 my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 3);
3e1f1122 7557
340dbcf7 7558 return ($volid, $size/1024);
3e1f1122
TL
7559}
7560
22de899a
AD
7561sub vm_iothreads_list {
7562 my ($vmid) = @_;
7563
0a13e08e 7564 my $res = mon_cmd($vmid, 'query-iothreads');
22de899a
AD
7565
7566 my $iothreads = {};
7567 foreach my $iothread (@$res) {
7568 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
7569 }
7570
7571 return $iothreads;
7572}
7573
ee034f5c
AD
7574sub scsihw_infos {
7575 my ($conf, $drive) = @_;
7576
7577 my $maxdev = 0;
7578
7fe1b688 7579 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 7580 $maxdev = 7;
a1511b3c 7581 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
7582 $maxdev = 1;
7583 } else {
7584 $maxdev = 256;
7585 }
7586
7587 my $controller = int($drive->{index} / $maxdev);
4df98f2f
TL
7588 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single')
7589 ? "virtioscsi"
7590 : "scsihw";
ee034f5c
AD
7591
7592 return ($maxdev, $controller, $controller_prefix);
7593}
a1511b3c 7594
4317f69f
AD
7595sub windows_version {
7596 my ($ostype) = @_;
7597
7598 return 0 if !$ostype;
7599
7600 my $winversion = 0;
7601
7602 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7603 $winversion = 5;
7604 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7605 $winversion = 6;
7606 } elsif ($ostype =~ m/^win(\d+)$/) {
7607 $winversion = $1;
7608 }
7609
7610 return $winversion;
7611}
7612
44549149
EK
7613sub resolve_dst_disk_format {
7614 my ($storecfg, $storeid, $src_volname, $format) = @_;
7615 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7616
7617 if (!$format) {
7618 # if no target format is specified, use the source disk format as hint
7619 if ($src_volname) {
7620 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7621 $format = qemu_img_format($scfg, $src_volname);
7622 } else {
7623 return $defFormat;
7624 }
7625 }
7626
7627 # test if requested format is supported - else use default
7628 my $supported = grep { $_ eq $format } @$validFormats;
7629 $format = $defFormat if !$supported;
7630 return $format;
7631}
7632
66cebc46
DC
7633# NOTE: if this logic changes, please update docs & possibly gui logic
7634sub find_vmstate_storage {
7635 my ($conf, $storecfg) = @_;
7636
7637 # first, return storage from conf if set
7638 return $conf->{vmstatestorage} if $conf->{vmstatestorage};
7639
7640 my ($target, $shared, $local);
7641
7642 foreach_storage_used_by_vm($conf, sub {
7643 my ($sid) = @_;
7644 my $scfg = PVE::Storage::storage_config($storecfg, $sid);
7645 my $dst = $scfg->{shared} ? \$shared : \$local;
7646 $$dst = $sid if !$$dst || $scfg->{path}; # prefer file based storage
7647 });
7648
7649 # second, use shared storage where VM has at least one disk
7650 # third, use local storage where VM has at least one disk
7651 # fall back to local storage
7652 $target = $shared // $local // 'local';
7653
7654 return $target;
7655}
7656
6ee499ff 7657sub generate_uuid {
ae2fcb3b
EK
7658 my ($uuid, $uuid_str);
7659 UUID::generate($uuid);
7660 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7661 return $uuid_str;
7662}
7663
7664sub generate_smbios1_uuid {
7665 return "uuid=".generate_uuid();
ae2fcb3b
EK
7666}
7667
9c152e87
TL
7668sub nbd_stop {
7669 my ($vmid) = @_;
7670
0a13e08e 7671 mon_cmd($vmid, 'nbd-server-stop');
9c152e87
TL
7672}
7673
dae98db9
DC
7674sub create_reboot_request {
7675 my ($vmid) = @_;
7676 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7677 or die "failed to create reboot trigger file: $!\n";
7678 close($fh);
7679}
7680
7681sub clear_reboot_request {
7682 my ($vmid) = @_;
7683 my $path = "/run/qemu-server/$vmid.reboot";
7684 my $res = 0;
7685
7686 $res = unlink($path);
7687 die "could not remove reboot request for $vmid: $!"
7688 if !$res && $! != POSIX::ENOENT;
7689
7690 return $res;
7691}
7692
5cfa9f5f
SR
7693sub bootorder_from_legacy {
7694 my ($conf, $bootcfg) = @_;
7695
7696 my $boot = $bootcfg->{legacy} || $boot_fmt->{legacy}->{default};
7697 my $bootindex_hash = {};
7698 my $i = 1;
7699 foreach my $o (split(//, $boot)) {
7700 $bootindex_hash->{$o} = $i*100;
7701 $i++;
7702 }
7703
7704 my $bootorder = {};
7705
7706 PVE::QemuConfig->foreach_volume($conf, sub {
7707 my ($ds, $drive) = @_;
7708
7709 if (drive_is_cdrom ($drive, 1)) {
7710 if ($bootindex_hash->{d}) {
7711 $bootorder->{$ds} = $bootindex_hash->{d};
7712 $bootindex_hash->{d} += 1;
7713 }
7714 } elsif ($bootindex_hash->{c}) {
7715 $bootorder->{$ds} = $bootindex_hash->{c}
7716 if $conf->{bootdisk} && $conf->{bootdisk} eq $ds;
7717 $bootindex_hash->{c} += 1;
7718 }
7719 });
7720
7721 if ($bootindex_hash->{n}) {
7722 for (my $i = 0; $i < $MAX_NETS; $i++) {
7723 my $netname = "net$i";
7724 next if !$conf->{$netname};
7725 $bootorder->{$netname} = $bootindex_hash->{n};
7726 $bootindex_hash->{n} += 1;
7727 }
7728 }
7729
7730 return $bootorder;
7731}
7732
7733# Generate default device list for 'boot: order=' property. Matches legacy
7734# default boot order, but with explicit device names. This is important, since
7735# the fallback for when neither 'order' nor the old format is specified relies
7736# on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
7737sub get_default_bootdevices {
7738 my ($conf) = @_;
7739
7740 my @ret = ();
7741
7742 # harddisk
7743 my $first = PVE::QemuServer::Drive::resolve_first_disk($conf, 0);
7744 push @ret, $first if $first;
7745
7746 # cdrom
7747 $first = PVE::QemuServer::Drive::resolve_first_disk($conf, 1);
7748 push @ret, $first if $first;
7749
7750 # network
7751 for (my $i = 0; $i < $MAX_NETS; $i++) {
7752 my $netname = "net$i";
7753 next if !$conf->{$netname};
7754 push @ret, $netname;
7755 last;
7756 }
7757
7758 return \@ret;
7759}
7760
e5d611c3
TL
7761sub device_bootorder {
7762 my ($conf) = @_;
7763
7764 return bootorder_from_legacy($conf) if !defined($conf->{boot});
7765
7766 my $boot = parse_property_string($boot_fmt, $conf->{boot});
7767
7768 my $bootorder = {};
7769 if (!defined($boot) || $boot->{legacy}) {
7770 $bootorder = bootorder_from_legacy($conf, $boot);
7771 } elsif ($boot->{order}) {
7772 my $i = 100; # start at 100 to allow user to insert devices before us with -args
7773 for my $dev (PVE::Tools::split_list($boot->{order})) {
7774 $bootorder->{$dev} = $i++;
7775 }
7776 }
7777
7778 return $bootorder;
7779}
7780
65911545
SR
7781sub register_qmeventd_handle {
7782 my ($vmid) = @_;
7783
7784 my $fh;
7785 my $peer = "/var/run/qmeventd.sock";
7786 my $count = 0;
7787
7788 for (;;) {
7789 $count++;
7790 $fh = IO::Socket::UNIX->new(Peer => $peer, Blocking => 0, Timeout => 1);
7791 last if $fh;
7792 if ($! != EINTR && $! != EAGAIN) {
7793 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
7794 }
7795 if ($count > 4) {
7796 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
7797 . "after $count retries\n";
7798 }
7799 usleep(25000);
7800 }
7801
7802 # send handshake to mark VM as backing up
7803 print $fh to_json({vzdump => {vmid => "$vmid"}});
7804
7805 # return handle to be closed later when inhibit is no longer required
7806 return $fh;
7807}
7808
65e866e5
DM
7809# bash completion helper
7810
7811sub complete_backup_archives {
7812 my ($cmdname, $pname, $cvalue) = @_;
7813
7814 my $cfg = PVE::Storage::config();
7815
7816 my $storeid;
7817
7818 if ($cvalue =~ m/^([^:]+):/) {
7819 $storeid = $1;
7820 }
7821
7822 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7823
7824 my $res = [];
7825 foreach my $id (keys %$data) {
7826 foreach my $item (@{$data->{$id}}) {
f43a4f12 7827 next if $item->{format} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
65e866e5
DM
7828 push @$res, $item->{volid} if defined($item->{volid});
7829 }
7830 }
7831
7832 return $res;
7833}
7834
7835my $complete_vmid_full = sub {
7836 my ($running) = @_;
7837
7838 my $idlist = vmstatus();
7839
7840 my $res = [];
7841
7842 foreach my $id (keys %$idlist) {
7843 my $d = $idlist->{$id};
7844 if (defined($running)) {
7845 next if $d->{template};
7846 next if $running && $d->{status} ne 'running';
7847 next if !$running && $d->{status} eq 'running';
7848 }
7849 push @$res, $id;
7850
7851 }
7852 return $res;
7853};
7854
7855sub complete_vmid {
7856 return &$complete_vmid_full();
7857}
7858
7859sub complete_vmid_stopped {
7860 return &$complete_vmid_full(0);
7861}
7862
7863sub complete_vmid_running {
7864 return &$complete_vmid_full(1);
7865}
7866
335af808
DM
7867sub complete_storage {
7868
7869 my $cfg = PVE::Storage::config();
7870 my $ids = $cfg->{ids};
7871
7872 my $res = [];
7873 foreach my $sid (keys %$ids) {
7874 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7875 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7876 push @$res, $sid;
7877 }
7878
7879 return $res;
7880}
7881
255e9c54
AL
7882sub complete_migration_storage {
7883 my ($cmd, $param, $current_value, $all_args) = @_;
7884
7885 my $targetnode = @$all_args[1];
7886
7887 my $cfg = PVE::Storage::config();
7888 my $ids = $cfg->{ids};
7889
7890 my $res = [];
7891 foreach my $sid (keys %$ids) {
7892 next if !PVE::Storage::storage_check_enabled($cfg, $sid, $targetnode, 1);
7893 next if !$ids->{$sid}->{content}->{images};
7894 push @$res, $sid;
7895 }
7896
7897 return $res;
7898}
7899
b08c37c3
DC
7900sub vm_is_paused {
7901 my ($vmid) = @_;
7902 my $qmpstatus = eval {
7903 PVE::QemuConfig::assert_config_exists_on_node($vmid);
7904 mon_cmd($vmid, "query-status");
7905 };
7906 warn "$@\n" if $@;
7907 return $qmpstatus && $qmpstatus->{status} eq "paused";
7908}
7909
3f11f0d7
LS
7910sub check_volume_storage_type {
7911 my ($storecfg, $vol) = @_;
7912
7913 my ($storeid, $volname) = PVE::Storage::parse_volume_id($vol);
7914 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7915 my ($vtype) = PVE::Storage::parse_volname($storecfg, $vol);
7916
7917 die "storage '$storeid' does not support content-type '$vtype'\n"
7918 if !$scfg->{content}->{$vtype};
7919
7920 return 1;
7921}
7922
1e3baf05 79231;