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