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