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