1 package PVE
::QemuServer
;
22 use Storable
qw(dclone);
23 use PVE
::Exception
qw(raise raise_param_exc);
25 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
26 use PVE
::JSONSchema
qw(get_standard_option);
27 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
32 use PVE
::RPCEnvironment
;
33 use PVE
::GuestHelpers
;
34 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
35 use PVE
::QemuServer
::Memory
;
36 use PVE
::QemuServer
::USB
qw(parse_usb_device);
37 use PVE
::QemuServer
::Cloudinit
;
40 use Time
::HiRes
qw(gettimeofday);
41 use File
::Copy
qw(copy);
44 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
47 "$EDK2_FW_BASE/OVMF_CODE.fd",
48 "$EDK2_FW_BASE/OVMF_VARS.fd"
51 "$EDK2_FW_BASE/AAVMF_CODE.fd",
52 "$EDK2_FW_BASE/AAVMF_VARS.fd"
56 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
58 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
60 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
62 # Note about locking: we use flock on the config file protect
63 # against concurent actions.
64 # Aditionaly, we have a 'lock' setting in the config file. This
65 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
66 # allowed when such lock is set. But you can ignore this kind of
67 # lock with the --skiplock flag.
69 cfs_register_file
('/qemu-server/',
73 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
74 description
=> "Some command save/restore state from this location.",
80 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
81 description
=> "The name of the snapshot.",
82 type
=> 'string', format
=> 'pve-configid',
86 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
88 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
89 description
=> "The drive's backing file's data format.",
93 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
94 description
=> "Specifies the Qemu machine type.",
96 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
101 #no warnings 'redefine';
104 my ($controller, $vmid, $option, $value) = @_;
106 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
107 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
111 my $nodename = PVE
::INotify
::nodename
();
113 mkdir "/etc/pve/nodes/$nodename";
114 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
117 my $var_run_tmpdir = "/var/run/qemu-server";
118 mkdir $var_run_tmpdir;
120 my $lock_dir = "/var/lock/qemu-server";
123 my $cpu_vendor_list = {
125 486 => 'GenuineIntel',
126 pentium
=> 'GenuineIntel',
127 pentium2
=> 'GenuineIntel',
128 pentium3
=> 'GenuineIntel',
129 coreduo
=> 'GenuineIntel',
130 core2duo
=> 'GenuineIntel',
131 Conroe
=> 'GenuineIntel',
132 Penryn
=> 'GenuineIntel',
133 Nehalem
=> 'GenuineIntel',
134 'Nehalem-IBRS' => 'GenuineIntel',
135 Westmere
=> 'GenuineIntel',
136 'Westmere-IBRS' => 'GenuineIntel',
137 SandyBridge
=> 'GenuineIntel',
138 'SandyBridge-IBRS' => 'GenuineIntel',
139 IvyBridge
=> 'GenuineIntel',
140 'IvyBridge-IBRS' => 'GenuineIntel',
141 Haswell
=> 'GenuineIntel',
142 'Haswell-IBRS' => 'GenuineIntel',
143 'Haswell-noTSX' => 'GenuineIntel',
144 'Haswell-noTSX-IBRS' => 'GenuineIntel',
145 Broadwell
=> 'GenuineIntel',
146 'Broadwell-IBRS' => 'GenuineIntel',
147 'Broadwell-noTSX' => 'GenuineIntel',
148 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
149 'Skylake-Client' => 'GenuineIntel',
150 'Skylake-Client-IBRS' => 'GenuineIntel',
151 'Skylake-Server' => 'GenuineIntel',
152 'Skylake-Server-IBRS' => 'GenuineIntel',
155 athlon
=> 'AuthenticAMD',
156 phenom
=> 'AuthenticAMD',
157 Opteron_G1
=> 'AuthenticAMD',
158 Opteron_G2
=> 'AuthenticAMD',
159 Opteron_G3
=> 'AuthenticAMD',
160 Opteron_G4
=> 'AuthenticAMD',
161 Opteron_G5
=> 'AuthenticAMD',
162 EPYC
=> 'AuthenticAMD',
163 'EPYC-IBPB' => 'AuthenticAMD',
165 # generic types, use vendor from host node
174 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
178 description
=> "Emulated CPU type.",
180 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
185 description
=> "Do not identify as a KVM virtual machine.",
192 pattern
=> qr/[a-zA-Z0-9]{1,12}/,
193 format_description
=> 'vendor-id',
194 description
=> 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
198 description
=> "List of additional CPU flags separated by ';'."
199 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
200 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
201 format_description
=> '+FLAG[;-FLAG...]',
203 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
212 enum
=> [qw(i6300esb ib700)],
213 description
=> "Watchdog type to emulate.",
214 default => 'i6300esb',
219 enum
=> [qw(reset shutdown poweroff pause debug none)],
220 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
224 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
228 description
=> "Enable/disable Qemu GuestAgent.",
233 fstrim_cloned_disks
=> {
234 description
=> "Run fstrim after cloning/moving a disk.",
243 description
=> "Select the VGA type.",
248 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
251 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
263 description
=> "The size of the file in MB.",
267 pattern
=> '[a-zA-Z0-9\-]+',
269 format_description
=> 'string',
270 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
278 description
=> "Specifies whether a VM will be started during system bootup.",
284 description
=> "Automatic restart after crash (currently ignored).",
289 type
=> 'string', format
=> 'pve-hotplug-features',
290 description
=> "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
291 default => 'network,disk,usb',
296 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
302 description
=> "Lock/unlock the VM.",
303 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete)],
308 description
=> "Limit of CPU usage.",
309 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
317 description
=> "CPU weight for a VM.",
318 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
326 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
333 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
339 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
347 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
348 "It should not be necessary to set it.",
349 enum
=> PVE
::Tools
::kvmkeymaplist
(),
354 type
=> 'string', format
=> 'dns-name',
355 description
=> "Set a name for the VM. Only used on the configuration web interface.",
360 description
=> "SCSI controller model",
361 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
367 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
372 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
373 description
=> "Specify guest operating system.",
374 verbose_description
=> <<EODESC,
375 Specify guest operating system. This is used to enable special
376 optimization/features for specific operating systems:
379 other;; unspecified OS
380 wxp;; Microsoft Windows XP
381 w2k;; Microsoft Windows 2000
382 w2k3;; Microsoft Windows 2003
383 w2k8;; Microsoft Windows 2008
384 wvista;; Microsoft Windows Vista
385 win7;; Microsoft Windows 7
386 win8;; Microsoft Windows 8/2012/2012r2
387 win10;; Microsoft Windows 10/2016
388 l24;; Linux 2.4 Kernel
389 l26;; Linux 2.6/3.X Kernel
390 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
396 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
397 pattern
=> '[acdn]{1,4}',
402 type
=> 'string', format
=> 'pve-qm-bootdisk',
403 description
=> "Enable booting from specified disk.",
404 pattern
=> '(ide|sata|scsi|virtio)\d+',
409 description
=> "The number of CPUs. Please use option -sockets instead.",
416 description
=> "The number of CPU sockets.",
423 description
=> "The number of cores per socket.",
430 description
=> "Enable/disable NUMA.",
436 description
=> "Enable/disable hugepages memory.",
437 enum
=> [qw(any 2 1024)],
442 description
=> "Number of hotplugged vcpus.",
449 description
=> "Enable/disable ACPI.",
454 description
=> "Enable/disable Qemu GuestAgent and its properties.",
456 format
=> $agent_fmt,
461 description
=> "Enable/disable KVM hardware virtualization.",
467 description
=> "Enable/disable time drift fix.",
473 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
478 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
482 type
=> 'string', format
=> $vga_fmt,
483 description
=> "Configure the VGA hardware.",
484 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
485 "high resolution modes (>= 1280x1024x16) you may need to increase " .
486 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
487 "is 'std' for all OS types besides some Windows versions (XP and " .
488 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
489 "display server. For win* OS you can select how many independent " .
490 "displays you want, Linux guests can add displays them self.\n".
491 "You can also run without any graphic card, using a serial device as terminal.",
495 type
=> 'string', format
=> 'pve-qm-watchdog',
496 description
=> "Create a virtual hardware watchdog device.",
497 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
498 " (by a guest action), the watchdog must be periodically polled " .
499 "by an agent inside the guest or else the watchdog will reset " .
500 "the guest (or execute the respective action specified)",
505 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
506 description
=> "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
507 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
510 startup
=> get_standard_option
('pve-startup-order'),
514 description
=> "Enable/disable Template.",
520 description
=> "Arbitrary arguments passed to kvm.",
521 verbose_description
=> <<EODESCR,
522 Arbitrary arguments passed to kvm, for example:
524 args: -no-reboot -no-hpet
526 NOTE: this option is for experts only.
533 description
=> "Enable/disable the USB tablet device.",
534 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
535 "usually needed to allow absolute mouse positioning with VNC. " .
536 "Else the mouse runs out of sync with normal VNC clients. " .
537 "If you're running lots of console-only guests on one host, " .
538 "you may consider disabling this to save some context switches. " .
539 "This is turned off by default if you use spice (-vga=qxl).",
544 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
548 migrate_downtime
=> {
551 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
557 type
=> 'string', format
=> 'pve-qm-ide',
558 typetext
=> '<volume>',
559 description
=> "This is an alias for option -ide2",
563 description
=> "Emulated CPU type.",
567 parent
=> get_standard_option
('pve-snapshot-name', {
569 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
573 description
=> "Timestamp for snapshots.",
579 type
=> 'string', format
=> 'pve-volume-id',
580 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
582 vmstatestorage
=> get_standard_option
('pve-storage-id', {
583 description
=> "Default storage for VM state volumes/files.",
586 runningmachine
=> get_standard_option
('pve-qemu-machine', {
587 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
589 machine
=> get_standard_option
('pve-qemu-machine'),
591 description
=> "Virtual processor architecture. Defaults to the host.",
594 enum
=> [qw(x86_64 aarch64)],
597 description
=> "Specify SMBIOS type 1 fields.",
598 type
=> 'string', format
=> 'pve-qm-smbios1',
605 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
611 enum
=> [ qw(seabios ovmf) ],
612 description
=> "Select BIOS implementation.",
613 default => 'seabios',
617 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
618 format_description
=> 'UUID',
619 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
620 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
621 " 128-bit integer value identifier to the guest OS. This allows to".
622 " notify the guest operating system when the virtual machine is".
623 " executed with a different configuration (e.g. snapshot execution".
624 " or creation from a template). The guest operating system notices".
625 " the change, and is then able to react as appropriate by marking".
626 " its copies of distributed databases as dirty, re-initializing its".
627 " random number generator, etc.\n".
628 "Note that auto-creation only works when done throug API/CLI create".
629 " or update methods, but not when manually editing the config file.",
630 default => "1 (autogenerated)",
635 format
=> 'pve-volume-id',
637 description
=> "Script that will be executed during various steps in the vms lifetime.",
641 format
=> $ivshmem_fmt,
642 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
651 description
=> 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
652 format
=> 'pve-volume-id',
653 format_description
=> 'volume',
658 description
=> 'Specify a custom file containing all network data passed to the VM via cloud-init.',
659 format
=> 'pve-volume-id',
660 format_description
=> 'volume',
665 description
=> 'Specify a custom file containing all user data passed to the VM via cloud-init.',
666 format
=> 'pve-volume-id',
667 format_description
=> 'volume',
670 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
672 my $confdesc_cloudinit = {
676 description
=> 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
677 enum
=> ['configdrive2', 'nocloud'],
682 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
687 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
692 description
=> 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
693 format
=> 'pve-qm-cicustom',
698 description
=> "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
702 type
=> 'string', format
=> 'address-list',
703 description
=> "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
708 format
=> 'urlencoded',
709 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
713 # what about other qemu settings ?
715 #machine => 'string',
728 ##soundhw => 'string',
730 while (my ($k, $v) = each %$confdesc) {
731 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
734 my $MAX_IDE_DISKS = 4;
735 my $MAX_SCSI_DISKS = 14;
736 my $MAX_VIRTIO_DISKS = 16;
737 my $MAX_SATA_DISKS = 6;
738 my $MAX_USB_DEVICES = 5;
740 my $MAX_UNUSED_DISKS = 256;
741 my $MAX_HOSTPCI_DEVICES = 4;
742 my $MAX_SERIAL_PORTS = 4;
743 my $MAX_PARALLEL_PORTS = 3;
749 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
750 description
=> "CPUs accessing this NUMA node.",
751 format_description
=> "id[-id];...",
755 description
=> "Amount of memory this NUMA node provides.",
760 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
761 description
=> "Host NUMA nodes to use.",
762 format_description
=> "id[-id];...",
767 enum
=> [qw(preferred bind interleave)],
768 description
=> "NUMA allocation policy.",
772 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
775 type
=> 'string', format
=> $numa_fmt,
776 description
=> "NUMA topology.",
778 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
780 for (my $i = 0; $i < $MAX_NUMA; $i++) {
781 $confdesc->{"numa$i"} = $numadesc;
784 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
785 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
786 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
787 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
789 my $net_fmt_bridge_descr = <<__EOD__;
790 Bridge to attach the network device to. The Proxmox VE standard bridge
793 If you do not specify a bridge, we create a kvm user (NATed) network
794 device, which provides DHCP and DNS services. The following addresses
801 The DHCP server assign addresses to the guest starting from 10.0.2.15.
807 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
808 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
809 format_description
=> "XX:XX:XX:XX:XX:XX",
814 description
=> "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
815 enum
=> $nic_model_list,
818 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
821 description
=> $net_fmt_bridge_descr,
822 format_description
=> 'bridge',
827 minimum
=> 0, maximum
=> 16,
828 description
=> 'Number of packet queues to be used on the device.',
834 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
839 minimum
=> 1, maximum
=> 4094,
840 description
=> 'VLAN tag to apply to packets on this interface.',
845 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
846 description
=> 'VLAN trunks to pass through this interface.',
847 format_description
=> 'vlanid[;vlanid...]',
852 description
=> 'Whether this interface should be protected by the firewall.',
857 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
864 type
=> 'string', format
=> $net_fmt,
865 description
=> "Specify network devices.",
868 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
873 format
=> 'pve-ipv4-config',
874 format_description
=> 'IPv4Format/CIDR',
875 description
=> 'IPv4 address in CIDR format.',
882 format_description
=> 'GatewayIPv4',
883 description
=> 'Default gateway for IPv4 traffic.',
889 format
=> 'pve-ipv6-config',
890 format_description
=> 'IPv6Format/CIDR',
891 description
=> 'IPv6 address in CIDR format.',
898 format_description
=> 'GatewayIPv6',
899 description
=> 'Default gateway for IPv6 traffic.',
904 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
907 type
=> 'string', format
=> 'pve-qm-ipconfig',
908 description
=> <<'EODESCR',
909 cloud-init: Specify IP addresses and gateways for the corresponding interface.
911 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
913 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
914 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
916 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
919 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
921 for (my $i = 0; $i < $MAX_NETS; $i++) {
922 $confdesc->{"net$i"} = $netdesc;
923 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
926 foreach my $key (keys %$confdesc_cloudinit) {
927 $confdesc->{$key} = $confdesc_cloudinit->{$key};
930 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
931 sub verify_volume_id_or_qm_path
{
932 my ($volid, $noerr) = @_;
934 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
938 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
939 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
941 return undef if $noerr;
949 my %drivedesc_base = (
950 volume
=> { alias
=> 'file' },
953 format
=> 'pve-volume-id-or-qm-path',
955 format_description
=> 'volume',
956 description
=> "The drive's backing volume.",
960 enum
=> [qw(cdrom disk)],
961 description
=> "The drive's media type.",
967 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
972 description
=> "Force the drive's physical geometry to have a specific head count.",
977 description
=> "Force the drive's physical geometry to have a specific sector count.",
982 enum
=> [qw(none lba auto)],
983 description
=> "Force disk geometry bios translation mode.",
988 description
=> "Controls qemu's snapshot mode feature."
989 . " If activated, changes made to the disk are temporary and will"
990 . " be discarded when the VM is shutdown.",
995 enum
=> [qw(none writethrough writeback unsafe directsync)],
996 description
=> "The drive's cache mode",
999 format
=> get_standard_option
('pve-qm-image-format'),
1002 format
=> 'disk-size',
1003 format_description
=> 'DiskSize',
1004 description
=> "Disk size. This is purely informational and has no effect.",
1009 description
=> "Whether the drive should be included when making backups.",
1014 description
=> 'Whether the drive should considered for replication jobs.',
1020 enum
=> [qw(ignore report stop)],
1021 description
=> 'Read error action.',
1026 enum
=> [qw(enospc ignore report stop)],
1027 description
=> 'Write error action.',
1032 enum
=> [qw(native threads)],
1033 description
=> 'AIO type to use.',
1038 enum
=> [qw(ignore on)],
1039 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
1044 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
1049 format
=> 'urlencoded',
1050 format_description
=> 'serial',
1051 maxLength
=> 20*3, # *3 since it's %xx url enoded
1052 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
1057 description
=> 'Mark this locally-managed volume as available on all nodes',
1058 verbose_description
=> "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
1064 my %iothread_fmt = ( iothread
=> {
1066 description
=> "Whether to use iothreads for this drive",
1073 format
=> 'urlencoded',
1074 format_description
=> 'model',
1075 maxLength
=> 40*3, # *3 since it's %xx url enoded
1076 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1084 description
=> "Number of queues.",
1090 my %scsiblock_fmt = (
1093 description
=> "whether to use scsi-block for full passthrough of host block device\n\nWARNING: can lead to I/O errors in combination with low memory or high memory fragmentation on host",
1102 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1110 pattern
=> qr/^(0x)[0-9a-fA-F]{16}/,
1111 format_description
=> 'wwn',
1112 description
=> "The drive's worldwide name, encoded as 16 bytes hex string, prefixed by '0x'.",
1117 my $add_throttle_desc = sub {
1118 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1121 format_description
=> $unit,
1122 description
=> "Maximum $what in $longunit.",
1125 $d->{minimum
} = $minimum if defined($minimum);
1126 $drivedesc_base{$key} = $d;
1128 # throughput: (leaky bucket)
1129 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1130 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1131 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1132 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1133 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1134 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1135 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1136 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1137 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1139 # pools: (pool of IO before throttling starts taking effect)
1140 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1141 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1142 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1143 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1144 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1145 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1148 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1149 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1150 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1151 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1152 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1153 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1156 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1157 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1158 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1159 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1167 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1171 type
=> 'string', format
=> $ide_fmt,
1172 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1174 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1186 type
=> 'string', format
=> $scsi_fmt,
1187 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1189 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1198 type
=> 'string', format
=> $sata_fmt,
1199 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1201 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1209 type
=> 'string', format
=> $virtio_fmt,
1210 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1212 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1214 my $alldrive_fmt = {
1225 volume
=> { alias
=> 'file' },
1228 format
=> 'pve-volume-id-or-qm-path',
1230 format_description
=> 'volume',
1231 description
=> "The drive's backing volume.",
1233 format
=> get_standard_option
('pve-qm-image-format'),
1236 format
=> 'disk-size',
1237 format_description
=> 'DiskSize',
1238 description
=> "Disk size. This is purely informational and has no effect.",
1243 my $efidisk_desc = {
1245 type
=> 'string', format
=> $efidisk_fmt,
1246 description
=> "Configure a Disk for storing EFI vars",
1249 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1254 type
=> 'string', format
=> 'pve-qm-usb-device',
1255 format_description
=> 'HOSTUSBDEVICE|spice',
1256 description
=> <<EODESCR,
1257 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1259 'bus-port(.port)*' (decimal numbers) or
1260 'vendor_id:product_id' (hexadeciaml numbers) or
1263 You can use the 'lsusb -t' command to list existing usb devices.
1265 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1267 The value 'spice' can be used to add a usb redirection devices for spice.
1273 description
=> "Specifies whether if given host option is a USB3 device or port (this does currently not work reliably with spice redirection and is then ignored).",
1280 type
=> 'string', format
=> $usb_fmt,
1281 description
=> "Configure an USB device (n is 0 to 4).",
1283 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1285 my $PCIRE = qr/[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1290 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1291 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1292 description
=> <<EODESCR,
1293 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1294 of PCI virtual functions of the host. HOSTPCIID syntax is:
1296 'bus:dev.func' (hexadecimal numbers)
1298 You can us the 'lspci' command to list existing PCI devices.
1303 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1309 pattern
=> '[^,;]+',
1310 format_description
=> 'string',
1311 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1316 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1322 description
=> "Enable vfio-vga device support.",
1328 format_description
=> 'string',
1329 pattern
=> '[^/\.:]+',
1331 description
=> <<EODESCR
1332 The type of mediated device to use.
1333 An instance of this type will be created on startup of the VM and
1334 will be cleaned up when the VM stops.
1338 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1342 type
=> 'string', format
=> 'pve-qm-hostpci',
1343 description
=> "Map host PCI devices into guest.",
1344 verbose_description
=> <<EODESCR,
1345 Map host PCI devices into guest.
1347 NOTE: This option allows direct access to host hardware. So it is no longer
1348 possible to migrate such machines - use with special care.
1350 CAUTION: Experimental! User reported problems with this option.
1353 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1358 pattern
=> '(/dev/.+|socket)',
1359 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1360 verbose_description
=> <<EODESCR,
1361 Create a serial device inside the VM (n is 0 to 3), and pass through a
1362 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1363 host side (use 'qm terminal' to open a terminal connection).
1365 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1367 CAUTION: Experimental! User reported problems with this option.
1374 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1375 description
=> "Map host parallel devices (n is 0 to 2).",
1376 verbose_description
=> <<EODESCR,
1377 Map host parallel devices (n is 0 to 2).
1379 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1381 CAUTION: Experimental! User reported problems with this option.
1385 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1386 $confdesc->{"parallel$i"} = $paralleldesc;
1389 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1390 $confdesc->{"serial$i"} = $serialdesc;
1393 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1394 $confdesc->{"hostpci$i"} = $hostpcidesc;
1397 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1398 $drivename_hash->{"ide$i"} = 1;
1399 $confdesc->{"ide$i"} = $idedesc;
1402 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1403 $drivename_hash->{"sata$i"} = 1;
1404 $confdesc->{"sata$i"} = $satadesc;
1407 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1408 $drivename_hash->{"scsi$i"} = 1;
1409 $confdesc->{"scsi$i"} = $scsidesc ;
1412 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1413 $drivename_hash->{"virtio$i"} = 1;
1414 $confdesc->{"virtio$i"} = $virtiodesc;
1417 $drivename_hash->{efidisk0
} = 1;
1418 $confdesc->{efidisk0
} = $efidisk_desc;
1420 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1421 $confdesc->{"usb$i"} = $usbdesc;
1426 type
=> 'string', format
=> 'pve-volume-id',
1427 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1430 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1431 $confdesc->{"unused$i"} = $unuseddesc;
1434 my $kvm_api_version = 0;
1437 return $kvm_api_version if $kvm_api_version;
1439 open my $fh, '<', '/dev/kvm'
1442 # 0xae00 => KVM_GET_API_VERSION
1443 $kvm_api_version = ioctl($fh, 0xae00, 0);
1445 return $kvm_api_version;
1448 my $kvm_user_version;
1450 sub kvm_user_version
{
1452 return $kvm_user_version if $kvm_user_version;
1454 $kvm_user_version = 'unknown';
1458 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1459 $kvm_user_version = $2;
1463 eval { run_command
("kvm -version", outfunc
=> $code); };
1466 return $kvm_user_version;
1470 sub kernel_has_vhost_net
{
1471 return -c
'/dev/vhost-net';
1474 sub valid_drive_names
{
1475 # order is important - used to autoselect boot disk
1476 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1477 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1478 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1479 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1483 sub is_valid_drivename
{
1486 return defined($drivename_hash->{$dev});
1491 return defined($confdesc->{$key});
1495 return $nic_model_list;
1498 sub os_list_description
{
1502 wxp
=> 'Windows XP',
1503 w2k
=> 'Windows 2000',
1504 w2k3
=>, 'Windows 2003',
1505 w2k8
=> 'Windows 2008',
1506 wvista
=> 'Windows Vista',
1507 win7
=> 'Windows 7',
1508 win8
=> 'Windows 8/2012',
1509 win10
=> 'Windows 10/2016',
1517 sub get_cdrom_path
{
1519 return $cdrom_path if $cdrom_path;
1521 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1522 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1523 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1527 my ($storecfg, $vmid, $cdrom) = @_;
1529 if ($cdrom eq 'cdrom') {
1530 return get_cdrom_path
();
1531 } elsif ($cdrom eq 'none') {
1533 } elsif ($cdrom =~ m
|^/|) {
1536 return PVE
::Storage
::path
($storecfg, $cdrom);
1540 # try to convert old style file names to volume IDs
1541 sub filename_to_volume_id
{
1542 my ($vmid, $file, $media) = @_;
1544 if (!($file eq 'none' || $file eq 'cdrom' ||
1545 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1547 return undef if $file =~ m
|/|;
1549 if ($media && $media eq 'cdrom') {
1550 $file = "local:iso/$file";
1552 $file = "local:$vmid/$file";
1559 sub verify_media_type
{
1560 my ($opt, $vtype, $media) = @_;
1565 if ($media eq 'disk') {
1567 } elsif ($media eq 'cdrom') {
1570 die "internal error";
1573 return if ($vtype eq $etype);
1575 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1578 sub cleanup_drive_path
{
1579 my ($opt, $storecfg, $drive) = @_;
1581 # try to convert filesystem paths to volume IDs
1583 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1584 ($drive->{file
} !~ m
|^/dev/.+|) &&
1585 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1586 ($drive->{file
} !~ m/^\d+$/)) {
1587 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1588 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1589 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1590 verify_media_type
($opt, $vtype, $drive->{media
});
1591 $drive->{file
} = $volid;
1594 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1597 sub parse_hotplug_features
{
1602 return $res if $data eq '0';
1604 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1606 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1607 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1610 die "invalid hotplug feature '$feature'\n";
1616 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1617 sub pve_verify_hotplug_features
{
1618 my ($value, $noerr) = @_;
1620 return $value if parse_hotplug_features
($value);
1622 return undef if $noerr;
1624 die "unable to parse hotplug option\n";
1627 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1628 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1629 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1630 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1631 # [,iothread=on][,serial=serial][,model=model]
1634 my ($key, $data) = @_;
1636 my ($interface, $index);
1638 if ($key =~ m/^([^\d]+)(\d+)$/) {
1645 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1646 : $confdesc->{$key}->{format
};
1648 warn "invalid drive key: $key\n";
1651 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1652 return undef if !$res;
1653 $res->{interface
} = $interface;
1654 $res->{index} = $index;
1657 foreach my $opt (qw(bps bps_rd bps_wr)) {
1658 if (my $bps = defined(delete $res->{$opt})) {
1659 if (defined($res->{"m$opt"})) {
1660 warn "both $opt and m$opt specified\n";
1664 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1668 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1669 for my $requirement (
1670 [mbps_max
=> 'mbps'],
1671 [mbps_rd_max
=> 'mbps_rd'],
1672 [mbps_wr_max
=> 'mbps_wr'],
1673 [miops_max
=> 'miops'],
1674 [miops_rd_max
=> 'miops_rd'],
1675 [miops_wr_max
=> 'miops_wr'],
1676 [bps_max_length
=> 'mbps_max'],
1677 [bps_rd_max_length
=> 'mbps_rd_max'],
1678 [bps_wr_max_length
=> 'mbps_wr_max'],
1679 [iops_max_length
=> 'iops_max'],
1680 [iops_rd_max_length
=> 'iops_rd_max'],
1681 [iops_wr_max_length
=> 'iops_wr_max']) {
1682 my ($option, $requires) = @$requirement;
1683 if ($res->{$option} && !$res->{$requires}) {
1684 warn "$option requires $requires\n";
1689 return undef if $error;
1691 return undef if $res->{mbps_rd
} && $res->{mbps
};
1692 return undef if $res->{mbps_wr
} && $res->{mbps
};
1693 return undef if $res->{iops_rd
} && $res->{iops
};
1694 return undef if $res->{iops_wr
} && $res->{iops
};
1696 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1697 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1698 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1699 return undef if $res->{interface
} eq 'virtio';
1702 if (my $size = $res->{size
}) {
1703 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1710 my ($vmid, $drive) = @_;
1711 my $data = { %$drive };
1712 delete $data->{$_} for qw(index interface);
1713 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1717 my($fh, $noerr) = @_;
1720 my $SG_GET_VERSION_NUM = 0x2282;
1722 my $versionbuf = "\x00" x
8;
1723 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1725 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1728 my $version = unpack("I", $versionbuf);
1729 if ($version < 30000) {
1730 die "scsi generic interface too old\n" if !$noerr;
1734 my $buf = "\x00" x
36;
1735 my $sensebuf = "\x00" x
8;
1736 my $cmd = pack("C x3 C x1", 0x12, 36);
1738 # see /usr/include/scsi/sg.h
1739 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1741 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1742 length($sensebuf), 0, length($buf), $buf,
1743 $cmd, $sensebuf, 6000);
1745 $ret = ioctl($fh, $SG_IO, $packet);
1747 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1751 my @res = unpack($sg_io_hdr_t, $packet);
1752 if ($res[17] || $res[18]) {
1753 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1758 (my $byte0, my $byte1, $res->{vendor
},
1759 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1761 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1762 $res->{type
} = $byte0 & 31;
1770 my $fh = IO
::File-
>new("+<$path") || return undef;
1771 my $res = scsi_inquiry
($fh, 1);
1777 sub machine_type_is_q35
{
1780 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1783 sub print_tabletdevice_full
{
1784 my ($conf, $arch) = @_;
1786 my $q35 = machine_type_is_q35
($conf);
1788 # we use uhci for old VMs because tablet driver was buggy in older qemu
1790 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1796 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1799 sub print_keyboarddevice_full
{
1800 my ($conf, $arch, $machine) = @_;
1802 return undef if $arch ne 'aarch64';
1804 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1807 sub print_drivedevice_full
{
1808 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1813 if ($drive->{interface
} eq 'virtio') {
1814 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1815 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1816 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1817 } elsif ($drive->{interface
} eq 'scsi') {
1819 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1820 my $unit = $drive->{index} % $maxdev;
1821 my $devicetype = 'hd';
1823 if (drive_is_cdrom
($drive)) {
1826 if ($drive->{file
} =~ m
|^/|) {
1827 $path = $drive->{file
};
1828 if (my $info = path_is_scsi
($path)) {
1829 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1830 $devicetype = 'block';
1831 } elsif ($info->{type
} == 1) { # tape
1832 $devicetype = 'generic';
1836 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1839 if($path =~ m/^iscsi\:\/\
//){
1840 $devicetype = 'generic';
1844 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1845 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1847 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1850 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1851 $device .= ",rotation_rate=1";
1853 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1855 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1856 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1857 my $controller = int($drive->{index} / $maxdev);
1858 my $unit = $drive->{index} % $maxdev;
1859 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1861 $device = "ide-$devicetype";
1862 if ($drive->{interface
} eq 'ide') {
1863 $device .= ",bus=ide.$controller,unit=$unit";
1865 $device .= ",bus=ahci$controller.$unit";
1867 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1869 if ($devicetype eq 'hd') {
1870 if (my $model = $drive->{model
}) {
1871 $model = URI
::Escape
::uri_unescape
($model);
1872 $device .= ",model=$model";
1874 if ($drive->{ssd
}) {
1875 $device .= ",rotation_rate=1";
1878 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1879 } elsif ($drive->{interface
} eq 'usb') {
1881 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1883 die "unsupported interface type";
1886 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1888 if (my $serial = $drive->{serial
}) {
1889 $serial = URI
::Escape
::uri_unescape
($serial);
1890 $device .= ",serial=$serial";
1897 sub get_initiator_name
{
1900 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1901 while (defined(my $line = <$fh>)) {
1902 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1911 sub print_drive_full
{
1912 my ($storecfg, $vmid, $drive) = @_;
1915 my $volid = $drive->{file
};
1918 if (drive_is_cdrom
($drive)) {
1919 $path = get_iso_path
($storecfg, $vmid, $volid);
1921 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1923 $path = PVE
::Storage
::path
($storecfg, $volid);
1924 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1925 $format = qemu_img_format
($scfg, $volname);
1933 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1934 foreach my $o (@qemu_drive_options) {
1935 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1938 # snapshot only accepts on|off
1939 if (defined($drive->{snapshot
})) {
1940 my $v = $drive->{snapshot
} ?
'on' : 'off';
1941 $opts .= ",snapshot=$v";
1944 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1945 my ($dir, $qmpname) = @$type;
1946 if (my $v = $drive->{"mbps$dir"}) {
1947 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1949 if (my $v = $drive->{"mbps${dir}_max"}) {
1950 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1952 if (my $v = $drive->{"bps${dir}_max_length"}) {
1953 $opts .= ",throttling.bps$qmpname-max-length=$v";
1955 if (my $v = $drive->{"iops${dir}"}) {
1956 $opts .= ",throttling.iops$qmpname=$v";
1958 if (my $v = $drive->{"iops${dir}_max"}) {
1959 $opts .= ",throttling.iops$qmpname-max=$v";
1961 if (my $v = $drive->{"iops${dir}_max_length"}) {
1962 $opts .= ",throttling.iops$qmpname-max-length=$v";
1966 $opts .= ",format=$format" if $format && !$drive->{format
};
1968 my $cache_direct = 0;
1970 if (my $cache = $drive->{cache
}) {
1971 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1972 } elsif (!drive_is_cdrom
($drive)) {
1973 $opts .= ",cache=none";
1977 # aio native works only with O_DIRECT
1978 if (!$drive->{aio
}) {
1980 $opts .= ",aio=native";
1982 $opts .= ",aio=threads";
1986 if (!drive_is_cdrom
($drive)) {
1988 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1989 $detectzeroes = 'off';
1990 } elsif ($drive->{discard
}) {
1991 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1993 # This used to be our default with discard not being specified:
1994 $detectzeroes = 'on';
1996 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1999 my $pathinfo = $path ?
"file=$path," : '';
2001 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
2004 sub print_netdevice_full
{
2005 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
2007 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
2009 my $device = $net->{model
};
2010 if ($net->{model
} eq 'virtio') {
2011 $device = 'virtio-net-pci';
2014 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
2015 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
2016 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
2017 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
2018 my $vectors = $net->{queues
} * 2 + 2;
2019 $tmpstr .= ",vectors=$vectors,mq=on";
2021 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
2023 if ($use_old_bios_files) {
2025 if ($device eq 'virtio-net-pci') {
2026 $romfile = 'pxe-virtio.rom';
2027 } elsif ($device eq 'e1000') {
2028 $romfile = 'pxe-e1000.rom';
2029 } elsif ($device eq 'ne2k') {
2030 $romfile = 'pxe-ne2k_pci.rom';
2031 } elsif ($device eq 'pcnet') {
2032 $romfile = 'pxe-pcnet.rom';
2033 } elsif ($device eq 'rtl8139') {
2034 $romfile = 'pxe-rtl8139.rom';
2036 $tmpstr .= ",romfile=$romfile" if $romfile;
2042 sub print_netdev_full
{
2043 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
2046 if ($netid =~ m/^net(\d+)$/) {
2050 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
2052 my $ifname = "tap${vmid}i$i";
2054 # kvm uses TUNSETIFF ioctl, and that limits ifname length
2055 die "interface name '$ifname' is too long (max 15 character)\n"
2056 if length($ifname) >= 16;
2058 my $vhostparam = '';
2059 if (is_native
($arch)) {
2060 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
2063 my $vmname = $conf->{name
} || "vm$vmid";
2066 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
2068 if ($net->{bridge
}) {
2069 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
2071 $netdev = "type=user,id=$netid,hostname=$vmname";
2074 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
2080 sub print_cpu_device
{
2081 my ($conf, $id) = @_;
2083 my $kvm = $conf->{kvm
} // 1;
2084 my $cpu = $kvm ?
"kvm64" : "qemu64";
2085 if (my $cputype = $conf->{cpu
}) {
2086 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
2087 or die "Cannot parse cpu description: $cputype\n";
2088 $cpu = $cpuconf->{cputype
};
2091 my $cores = $conf->{cores
} || 1;
2093 my $current_core = ($id - 1) % $cores;
2094 my $current_socket = int(($id - 1 - $current_core)/$cores);
2096 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2100 'cirrus' => 'cirrus-vga',
2102 'vmware' => 'vmware-svga',
2103 'virtio' => 'virtio-vga',
2106 sub print_vga_device
{
2107 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2109 my $type = $vga_map->{$vga->{type
}};
2110 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
2111 $type = 'virtio-gpu';
2113 my $vgamem_mb = $vga->{memory
};
2115 $type = $id ?
'qxl' : 'qxl-vga';
2117 die "no devicetype for $vga->{type}\n" if !$type;
2121 if ($vga->{type
} eq 'virtio') {
2122 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2123 $memory = ",max_hostmem=$bytes";
2125 # from https://www.spice-space.org/multiple-monitors.html
2126 $memory = ",vgamem_mb=$vga->{memory}";
2127 my $ram = $vgamem_mb * 4;
2128 my $vram = $vgamem_mb * 2;
2129 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2131 $memory = ",vgamem_mb=$vga->{memory}";
2133 } elsif ($qxlnum && $id) {
2134 $memory = ",ram_size=67108864,vram_size=33554432";
2137 my $q35 = machine_type_is_q35
($conf);
2138 my $vgaid = "vga" . ($id // '');
2141 if ($q35 && $vgaid eq 'vga') {
2142 # the first display uses pcie.0 bus on q35 machines
2143 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2145 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2148 return "$type,id=${vgaid}${memory}${pciaddr}";
2151 sub drive_is_cloudinit
{
2153 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2156 sub drive_is_cdrom
{
2157 my ($drive, $exclude_cloudinit) = @_;
2159 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2161 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2165 sub parse_number_sets
{
2168 foreach my $part (split(/;/, $set)) {
2169 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2170 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2171 push @$res, [ $1, $2 ];
2173 die "invalid range: $part\n";
2182 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2183 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2184 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2191 return undef if !$value;
2193 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2195 my @idlist = split(/;/, $res->{host
});
2196 delete $res->{host
};
2197 foreach my $id (@idlist) {
2198 if ($id =~ m/\./) { # full id 00:00.1
2199 push @{$res->{pciid
}}, {
2202 } else { # partial id 00:00
2203 $res->{pciid
} = PVE
::SysFSTools
::lspci
($id);
2209 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2213 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2218 if (!defined($res->{macaddr
})) {
2219 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2220 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2225 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2226 sub parse_ipconfig
{
2229 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2235 if ($res->{gw
} && !$res->{ip
}) {
2236 warn 'gateway specified without specifying an IP address';
2239 if ($res->{gw6
} && !$res->{ip6
}) {
2240 warn 'IPv6 gateway specified without specifying an IPv6 address';
2243 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2244 warn 'gateway specified together with DHCP';
2247 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2249 warn "IPv6 gateway specified together with $res->{ip6} address";
2253 if (!$res->{ip
} && !$res->{ip6
}) {
2254 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2263 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2266 sub add_random_macs
{
2267 my ($settings) = @_;
2269 foreach my $opt (keys %$settings) {
2270 next if $opt !~ m/^net(\d+)$/;
2271 my $net = parse_net
($settings->{$opt});
2273 $settings->{$opt} = print_net
($net);
2277 sub vm_is_volid_owner
{
2278 my ($storecfg, $vmid, $volid) = @_;
2280 if ($volid !~ m
|^/|) {
2282 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2283 if ($owner && ($owner == $vmid)) {
2291 sub split_flagged_list
{
2292 my $text = shift || '';
2293 $text =~ s/[,;]/ /g;
2295 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2298 sub join_flagged_list
{
2299 my ($how, $lst) = @_;
2300 join $how, map { $lst->{$_} . $_ } keys %$lst;
2303 sub vmconfig_delete_pending_option
{
2304 my ($conf, $key, $force) = @_;
2306 delete $conf->{pending
}->{$key};
2307 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2308 $pending_delete_hash->{$key} = $force ?
'!' : '';
2309 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2312 sub vmconfig_undelete_pending_option
{
2313 my ($conf, $key) = @_;
2315 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2316 delete $pending_delete_hash->{$key};
2318 if (%$pending_delete_hash) {
2319 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2321 delete $conf->{pending
}->{delete};
2325 sub vmconfig_register_unused_drive
{
2326 my ($storecfg, $vmid, $conf, $drive) = @_;
2328 if (drive_is_cloudinit
($drive)) {
2329 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2331 } elsif (!drive_is_cdrom
($drive)) {
2332 my $volid = $drive->{file
};
2333 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2334 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2339 sub vmconfig_cleanup_pending
{
2342 # remove pending changes when nothing changed
2344 foreach my $opt (keys %{$conf->{pending
}}) {
2345 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2347 delete $conf->{pending
}->{$opt};
2351 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2352 my $pending_delete_hash = {};
2353 while (my ($opt, $force) = each %$current_delete_hash) {
2354 if (defined($conf->{$opt})) {
2355 $pending_delete_hash->{$opt} = $force;
2361 if (%$pending_delete_hash) {
2362 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2364 delete $conf->{pending
}->{delete};
2370 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2374 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2375 format_description
=> 'UUID',
2376 description
=> "Set SMBIOS1 UUID.",
2382 format_description
=> 'string',
2383 description
=> "Set SMBIOS1 version.",
2389 format_description
=> 'string',
2390 description
=> "Set SMBIOS1 serial number.",
2396 format_description
=> 'string',
2397 description
=> "Set SMBIOS1 manufacturer.",
2403 format_description
=> 'string',
2404 description
=> "Set SMBIOS1 product ID.",
2410 format_description
=> 'string',
2411 description
=> "Set SMBIOS1 SKU string.",
2417 format_description
=> 'string',
2418 description
=> "Set SMBIOS1 family string.",
2426 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2433 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2436 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2438 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2439 sub verify_bootdisk
{
2440 my ($value, $noerr) = @_;
2442 return $value if is_valid_drivename
($value);
2444 return undef if $noerr;
2446 die "invalid boot disk '$value'\n";
2449 sub parse_watchdog
{
2452 return undef if !$value;
2454 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2459 sub parse_guest_agent
{
2462 return {} if !defined($value->{agent
});
2464 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2467 # if the agent is disabled ignore the other potentially set properties
2468 return {} if !$res->{enabled
};
2475 return {} if !$value;
2476 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2481 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2482 sub verify_usb_device
{
2483 my ($value, $noerr) = @_;
2485 return $value if parse_usb_device
($value);
2487 return undef if $noerr;
2489 die "unable to parse usb device\n";
2492 # add JSON properties for create and set function
2493 sub json_config_properties
{
2496 foreach my $opt (keys %$confdesc) {
2497 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2498 $prop->{$opt} = $confdesc->{$opt};
2504 # return copy of $confdesc_cloudinit to generate documentation
2505 sub cloudinit_config_properties
{
2507 return dclone
($confdesc_cloudinit);
2511 my ($key, $value) = @_;
2513 die "unknown setting '$key'\n" if !$confdesc->{$key};
2515 my $type = $confdesc->{$key}->{type
};
2517 if (!defined($value)) {
2518 die "got undefined value\n";
2521 if ($value =~ m/[\n\r]/) {
2522 die "property contains a line feed\n";
2525 if ($type eq 'boolean') {
2526 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2527 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2528 die "type check ('boolean') failed - got '$value'\n";
2529 } elsif ($type eq 'integer') {
2530 return int($1) if $value =~ m/^(\d+)$/;
2531 die "type check ('integer') failed - got '$value'\n";
2532 } elsif ($type eq 'number') {
2533 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2534 die "type check ('number') failed - got '$value'\n";
2535 } elsif ($type eq 'string') {
2536 if (my $fmt = $confdesc->{$key}->{format
}) {
2537 PVE
::JSONSchema
::check_format
($fmt, $value);
2540 $value =~ s/^\"(.*)\"$/$1/;
2543 die "internal error"
2550 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2551 utime undef, undef, $conf;
2555 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2557 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2559 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2561 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2563 if ($conf->{template
}) {
2564 # check if any base image is still used by a linked clone
2565 foreach_drive
($conf, sub {
2566 my ($ds, $drive) = @_;
2568 return if drive_is_cdrom
($drive);
2570 my $volid = $drive->{file
};
2572 return if !$volid || $volid =~ m
|^/|;
2574 die "base volume '$volid' is still in use by linked cloned\n"
2575 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2580 # only remove disks owned by this VM
2581 foreach_drive
($conf, sub {
2582 my ($ds, $drive) = @_;
2584 return if drive_is_cdrom
($drive, 1);
2586 my $volid = $drive->{file
};
2588 return if !$volid || $volid =~ m
|^/|;
2590 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2591 return if !$path || !$owner || ($owner != $vmid);
2594 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2596 warn "Could not remove disk '$volid', check manually: $@" if $@;
2600 if ($keep_empty_config) {
2601 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2606 # also remove unused disk
2608 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2611 PVE
::Storage
::foreach_volid
($dl, sub {
2612 my ($volid, $sid, $volname, $d) = @_;
2613 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2622 sub parse_vm_config
{
2623 my ($filename, $raw) = @_;
2625 return undef if !defined($raw);
2628 digest
=> Digest
::SHA
::sha1_hex
($raw),
2633 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2634 || die "got strange filename '$filename'";
2642 my @lines = split(/\n/, $raw);
2643 foreach my $line (@lines) {
2644 next if $line =~ m/^\s*$/;
2646 if ($line =~ m/^\[PENDING\]\s*$/i) {
2647 $section = 'pending';
2648 if (defined($descr)) {
2650 $conf->{description
} = $descr;
2653 $conf = $res->{$section} = {};
2656 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2658 if (defined($descr)) {
2660 $conf->{description
} = $descr;
2663 $conf = $res->{snapshots
}->{$section} = {};
2667 if ($line =~ m/^\#(.*)\s*$/) {
2668 $descr = '' if !defined($descr);
2669 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2673 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2674 $descr = '' if !defined($descr);
2675 $descr .= PVE
::Tools
::decode_text
($2);
2676 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2677 $conf->{snapstate
} = $1;
2678 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2681 $conf->{$key} = $value;
2682 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2684 if ($section eq 'pending') {
2685 $conf->{delete} = $value; # we parse this later
2687 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2689 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2692 eval { $value = check_type
($key, $value); };
2694 warn "vm $vmid - unable to parse value of '$key' - $@";
2696 $key = 'ide2' if $key eq 'cdrom';
2697 my $fmt = $confdesc->{$key}->{format
};
2698 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2699 my $v = parse_drive
($key, $value);
2700 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2701 $v->{file
} = $volid;
2702 $value = print_drive
($vmid, $v);
2704 warn "vm $vmid - unable to parse value of '$key'\n";
2709 $conf->{$key} = $value;
2714 if (defined($descr)) {
2716 $conf->{description
} = $descr;
2718 delete $res->{snapstate
}; # just to be sure
2723 sub write_vm_config
{
2724 my ($filename, $conf) = @_;
2726 delete $conf->{snapstate
}; # just to be sure
2728 if ($conf->{cdrom
}) {
2729 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2730 $conf->{ide2
} = $conf->{cdrom
};
2731 delete $conf->{cdrom
};
2734 # we do not use 'smp' any longer
2735 if ($conf->{sockets
}) {
2736 delete $conf->{smp
};
2737 } elsif ($conf->{smp
}) {
2738 $conf->{sockets
} = $conf->{smp
};
2739 delete $conf->{cores
};
2740 delete $conf->{smp
};
2743 my $used_volids = {};
2745 my $cleanup_config = sub {
2746 my ($cref, $pending, $snapname) = @_;
2748 foreach my $key (keys %$cref) {
2749 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2750 $key eq 'snapstate' || $key eq 'pending';
2751 my $value = $cref->{$key};
2752 if ($key eq 'delete') {
2753 die "propertry 'delete' is only allowed in [PENDING]\n"
2755 # fixme: check syntax?
2758 eval { $value = check_type
($key, $value); };
2759 die "unable to parse value of '$key' - $@" if $@;
2761 $cref->{$key} = $value;
2763 if (!$snapname && is_valid_drivename
($key)) {
2764 my $drive = parse_drive
($key, $value);
2765 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2770 &$cleanup_config($conf);
2772 &$cleanup_config($conf->{pending
}, 1);
2774 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2775 die "internal error" if $snapname eq 'pending';
2776 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2779 # remove 'unusedX' settings if we re-add a volume
2780 foreach my $key (keys %$conf) {
2781 my $value = $conf->{$key};
2782 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2783 delete $conf->{$key};
2787 my $generate_raw_config = sub {
2788 my ($conf, $pending) = @_;
2792 # add description as comment to top of file
2793 if (defined(my $descr = $conf->{description
})) {
2795 foreach my $cl (split(/\n/, $descr)) {
2796 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2799 $raw .= "#\n" if $pending;
2803 foreach my $key (sort keys %$conf) {
2804 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2805 $raw .= "$key: $conf->{$key}\n";
2810 my $raw = &$generate_raw_config($conf);
2812 if (scalar(keys %{$conf->{pending
}})){
2813 $raw .= "\n[PENDING]\n";
2814 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2817 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2818 $raw .= "\n[$snapname]\n";
2819 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2829 # we use static defaults from our JSON schema configuration
2830 foreach my $key (keys %$confdesc) {
2831 if (defined(my $default = $confdesc->{$key}->{default})) {
2832 $res->{$key} = $default;
2840 my $vmlist = PVE
::Cluster
::get_vmlist
();
2842 return $res if !$vmlist || !$vmlist->{ids
};
2843 my $ids = $vmlist->{ids
};
2845 foreach my $vmid (keys %$ids) {
2846 my $d = $ids->{$vmid};
2847 next if !$d->{node
} || $d->{node
} ne $nodename;
2848 next if !$d->{type
} || $d->{type
} ne 'qemu';
2849 $res->{$vmid}->{exists} = 1;
2854 # test if VM uses local resources (to prevent migration)
2855 sub check_local_resources
{
2856 my ($conf, $noerr) = @_;
2860 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2861 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2863 $loc_res = 1 if $conf->{ivshmem
};
2865 foreach my $k (keys %$conf) {
2866 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2867 # sockets are safe: they will recreated be on the target side post-migrate
2868 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2869 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2872 die "VM uses local resources\n" if $loc_res && !$noerr;
2877 # check if used storages are available on all nodes (use by migrate)
2878 sub check_storage_availability
{
2879 my ($storecfg, $conf, $node) = @_;
2881 foreach_drive
($conf, sub {
2882 my ($ds, $drive) = @_;
2884 my $volid = $drive->{file
};
2887 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2890 # check if storage is available on both nodes
2891 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2892 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2896 # list nodes where all VM images are available (used by has_feature API)
2898 my ($conf, $storecfg) = @_;
2900 my $nodelist = PVE
::Cluster
::get_nodelist
();
2901 my $nodehash = { map { $_ => 1 } @$nodelist };
2902 my $nodename = PVE
::INotify
::nodename
();
2904 foreach_drive
($conf, sub {
2905 my ($ds, $drive) = @_;
2907 my $volid = $drive->{file
};
2910 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2912 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2913 if ($scfg->{disable
}) {
2915 } elsif (my $avail = $scfg->{nodes
}) {
2916 foreach my $node (keys %$nodehash) {
2917 delete $nodehash->{$node} if !$avail->{$node};
2919 } elsif (!$scfg->{shared
}) {
2920 foreach my $node (keys %$nodehash) {
2921 delete $nodehash->{$node} if $node ne $nodename
2931 my ($pidfile, $pid) = @_;
2933 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2937 return undef if !$line;
2938 my @param = split(/\0/, $line);
2940 my $cmd = $param[0];
2941 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2943 for (my $i = 0; $i < scalar (@param); $i++) {
2946 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2947 my $p = $param[$i+1];
2948 return 1 if $p && ($p eq $pidfile);
2957 my ($vmid, $nocheck, $node) = @_;
2959 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2961 die "unable to find configuration file for VM $vmid - no such machine\n"
2962 if !$nocheck && ! -f
$filename;
2964 my $pidfile = pidfile_name
($vmid);
2966 if (my $fd = IO
::File-
>new("<$pidfile")) {
2971 my $mtime = $st->mtime;
2972 if ($mtime > time()) {
2973 warn "file '$filename' modified in future\n";
2976 if ($line =~ m/^(\d+)$/) {
2978 if (check_cmdline
($pidfile, $pid)) {
2979 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2991 my $vzlist = config_list
();
2993 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2995 while (defined(my $de = $fd->read)) {
2996 next if $de !~ m/^(\d+)\.pid$/;
2998 next if !defined($vzlist->{$vmid});
2999 if (my $pid = check_running
($vmid)) {
3000 $vzlist->{$vmid}->{pid
} = $pid;
3008 my ($storecfg, $conf) = @_;
3010 my $bootdisk = $conf->{bootdisk
};
3011 return undef if !$bootdisk;
3012 return undef if !is_valid_drivename
($bootdisk);
3014 return undef if !$conf->{$bootdisk};
3016 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
3017 return undef if !defined($drive);
3019 return undef if drive_is_cdrom
($drive);
3021 my $volid = $drive->{file
};
3022 return undef if !$volid;
3024 return $drive->{size
};
3027 our $vmstatus_return_properties = {
3028 vmid
=> get_standard_option
('pve-vmid'),
3030 description
=> "Qemu process status.",
3032 enum
=> ['stopped', 'running'],
3035 description
=> "Maximum memory in bytes.",
3038 renderer
=> 'bytes',
3041 description
=> "Root disk size in bytes.",
3044 renderer
=> 'bytes',
3047 description
=> "VM name.",
3052 description
=> "Qemu QMP agent status.",
3057 description
=> "PID of running qemu process.",
3062 description
=> "Uptime.",
3065 renderer
=> 'duration',
3068 description
=> "Maximum usable CPUs.",
3074 my $last_proc_pid_stat;
3076 # get VM status information
3077 # This must be fast and should not block ($full == false)
3078 # We only query KVM using QMP if $full == true (this can be slow)
3080 my ($opt_vmid, $full) = @_;
3084 my $storecfg = PVE
::Storage
::config
();
3086 my $list = vzlist
();
3087 my $defaults = load_defaults
();
3089 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3091 my $cpucount = $cpuinfo->{cpus
} || 1;
3093 foreach my $vmid (keys %$list) {
3094 next if $opt_vmid && ($vmid ne $opt_vmid);
3096 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3097 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3099 my $d = { vmid
=> $vmid };
3100 $d->{pid
} = $list->{$vmid}->{pid
};
3102 # fixme: better status?
3103 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3105 my $size = disksize
($storecfg, $conf);
3106 if (defined($size)) {
3107 $d->{disk
} = 0; # no info available
3108 $d->{maxdisk
} = $size;
3114 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3115 * ($conf->{cores
} || $defaults->{cores
});
3116 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3117 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3119 $d->{name
} = $conf->{name
} || "VM $vmid";
3120 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3121 : $defaults->{memory
}*(1024*1024);
3123 if ($conf->{balloon
}) {
3124 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3125 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3126 : $defaults->{shares
};
3137 $d->{diskwrite
} = 0;
3139 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3141 $d->{serial
} = 1 if conf_has_serial
($conf);
3146 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3147 foreach my $dev (keys %$netdev) {
3148 next if $dev !~ m/^tap([1-9]\d*)i/;
3150 my $d = $res->{$vmid};
3153 $d->{netout
} += $netdev->{$dev}->{receive
};
3154 $d->{netin
} += $netdev->{$dev}->{transmit
};
3157 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3158 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3163 my $ctime = gettimeofday
;
3165 foreach my $vmid (keys %$list) {
3167 my $d = $res->{$vmid};
3168 my $pid = $d->{pid
};
3171 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3172 next if !$pstat; # not running
3174 my $used = $pstat->{utime} + $pstat->{stime
};
3176 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3178 if ($pstat->{vsize
}) {
3179 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3182 my $old = $last_proc_pid_stat->{$pid};
3184 $last_proc_pid_stat->{$pid} = {
3192 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3194 if ($dtime > 1000) {
3195 my $dutime = $used - $old->{used
};
3197 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3198 $last_proc_pid_stat->{$pid} = {
3204 $d->{cpu
} = $old->{cpu
};
3208 return $res if !$full;
3210 my $qmpclient = PVE
::QMPClient-
>new();
3212 my $ballooncb = sub {
3213 my ($vmid, $resp) = @_;
3215 my $info = $resp->{'return'};
3216 return if !$info->{max_mem
};
3218 my $d = $res->{$vmid};
3220 # use memory assigned to VM
3221 $d->{maxmem
} = $info->{max_mem
};
3222 $d->{balloon
} = $info->{actual
};
3224 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3225 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3226 $d->{freemem
} = $info->{free_mem
};
3229 $d->{ballooninfo
} = $info;
3232 my $blockstatscb = sub {
3233 my ($vmid, $resp) = @_;
3234 my $data = $resp->{'return'} || [];
3235 my $totalrdbytes = 0;
3236 my $totalwrbytes = 0;
3238 for my $blockstat (@$data) {
3239 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3240 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3242 $blockstat->{device
} =~ s/drive-//;
3243 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3245 $res->{$vmid}->{diskread
} = $totalrdbytes;
3246 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3249 my $statuscb = sub {
3250 my ($vmid, $resp) = @_;
3252 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3253 # this fails if ballon driver is not loaded, so this must be
3254 # the last commnand (following command are aborted if this fails).
3255 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3257 my $status = 'unknown';
3258 if (!defined($status = $resp->{'return'}->{status
})) {
3259 warn "unable to get VM status\n";
3263 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3266 foreach my $vmid (keys %$list) {
3267 next if $opt_vmid && ($vmid ne $opt_vmid);
3268 next if !$res->{$vmid}->{pid
}; # not running
3269 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3272 $qmpclient->queue_execute(undef, 2);
3274 foreach my $vmid (keys %$list) {
3275 next if $opt_vmid && ($vmid ne $opt_vmid);
3276 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3283 my ($conf, $func, @param) = @_;
3285 foreach my $ds (valid_drive_names
()) {
3286 next if !defined($conf->{$ds});
3288 my $drive = parse_drive
($ds, $conf->{$ds});
3291 &$func($ds, $drive, @param);
3296 my ($conf, $func, @param) = @_;
3300 my $test_volid = sub {
3301 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3305 $volhash->{$volid}->{cdrom
} //= 1;
3306 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3308 $volhash->{$volid}->{replicate
} //= 0;
3309 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3311 $volhash->{$volid}->{shared
} //= 0;
3312 $volhash->{$volid}->{shared
} = 1 if $shared;
3314 $volhash->{$volid}->{referenced_in_config
} //= 0;
3315 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3317 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3318 if defined($snapname);
3321 foreach_drive
($conf, sub {
3322 my ($ds, $drive) = @_;
3323 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3326 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3327 my $snap = $conf->{snapshots
}->{$snapname};
3328 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3329 foreach_drive
($snap, sub {
3330 my ($ds, $drive) = @_;
3331 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3335 foreach my $volid (keys %$volhash) {
3336 &$func($volid, $volhash->{$volid}, @param);
3340 sub conf_has_serial
{
3343 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3344 if ($conf->{"serial$i"}) {
3352 sub vga_conf_has_spice
{
3355 my $vgaconf = parse_vga
($vga);
3356 my $vgatype = $vgaconf->{type
};
3357 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3362 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3363 sub get_host_arch
() {
3364 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3370 return get_host_arch
() eq $arch;
3373 my $default_machines = {
3378 sub get_basic_machine_info
{
3379 my ($conf, $forcemachine) = @_;
3381 my $arch = $conf->{arch
} // get_host_arch
();
3382 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3383 return ($arch, $machine);
3386 sub get_ovmf_files
($) {
3389 my $ovmf = $OVMF->{$arch}
3390 or die "no OVMF images known for architecture '$arch'\n";
3396 aarch64
=> '/usr/bin/qemu-system-aarch64',
3397 x86_64
=> '/usr/bin/qemu-system-x86_64',
3399 sub get_command_for_arch
($) {
3401 return '/usr/bin/kvm' if is_native
($arch);
3403 my $cmd = $Arch2Qemu->{$arch}
3404 or die "don't know how to emulate architecture '$arch'\n";
3408 sub get_cpu_options
{
3409 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3412 my $ostype = $conf->{ostype
};
3414 my $cpu = $kvm ?
"kvm64" : "qemu64";
3415 if ($arch eq 'aarch64') {
3416 $cpu = 'cortex-a57';
3419 if (my $cputype = $conf->{cpu
}) {
3420 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3421 or die "Cannot parse cpu description: $cputype\n";
3422 $cpu = $cpuconf->{cputype
};
3423 $kvm_off = 1 if $cpuconf->{hidden
};
3424 $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
3426 if (defined(my $flags = $cpuconf->{flags
})) {
3427 push @$cpuFlags, split(";", $flags);
3431 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3433 push @$cpuFlags , '-x2apic'
3434 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3436 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3438 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3440 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3442 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3443 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3446 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough, $hv_vendor_id) if $kvm;
3448 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3450 push @$cpuFlags, 'kvm=off' if $kvm_off;
3452 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3453 push @$cpuFlags, "vendor=${cpu_vendor}"
3454 if $cpu_vendor ne 'default';
3455 } elsif ($arch ne 'aarch64') {
3456 die "internal error"; # should not happen
3459 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3461 return ('-cpu', $cpu);
3464 sub config_to_command
{
3465 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3468 my $globalFlags = [];
3469 my $machineFlags = [];
3474 my $kvmver = kvm_user_version
();
3475 my $vernum = 0; # unknown
3476 my $ostype = $conf->{ostype
};
3477 my $winversion = windows_version
($ostype);
3478 my $kvm = $conf->{kvm
};
3480 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3481 $kvm //= 1 if is_native
($arch);
3484 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3485 if !defined kvm_version
();
3488 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3489 $vernum = $1*1000000+$2*1000;
3490 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3491 $vernum = $1*1000000+$2*1000+$3;
3494 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3496 my $have_ovz = -f
'/proc/vz/vestat';
3498 my $q35 = machine_type_is_q35
($conf);
3499 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3500 my $use_old_bios_files = undef;
3501 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3503 my $cpuunits = defined($conf->{cpuunits
}) ?
3504 $conf->{cpuunits
} : $defaults->{cpuunits
};
3506 push @$cmd, get_command_for_arch
($arch);
3508 push @$cmd, '-id', $vmid;
3510 my $vmname = $conf->{name
} || "vm$vmid";
3512 push @$cmd, '-name', $vmname;
3516 my $qmpsocket = qmp_socket
($vmid);
3517 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3518 push @$cmd, '-mon', "chardev=qmp,mode=control";
3520 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3521 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3522 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3525 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3527 push @$cmd, '-daemonize';
3529 if ($conf->{smbios1
}) {
3530 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3533 if ($conf->{vmgenid
}) {
3534 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3537 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3538 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3539 die "uefi base image not found\n" if ! -f
$ovmf_code;
3543 if (my $efidisk = $conf->{efidisk0
}) {
3544 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3545 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3546 $format = $d->{format
};
3548 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3549 if (!defined($format)) {
3550 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3551 $format = qemu_img_format
($scfg, $volname);
3555 die "efidisk format must be specified\n"
3556 if !defined($format);
3559 warn "no efidisk configured! Using temporary efivars disk.\n";
3560 $path = "/tmp/$vmid-ovmf.fd";
3561 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3565 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3566 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3570 # add usb controllers
3571 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3572 push @$devices, @usbcontrollers if @usbcontrollers;
3573 my $vga = parse_vga
($conf->{vga
});
3575 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3576 $vga->{type
} = 'qxl' if $qxlnum;
3578 if (!$vga->{type
}) {
3579 if ($arch eq 'aarch64') {
3580 $vga->{type
} = 'virtio';
3581 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3582 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3584 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3588 # enable absolute mouse coordinates (needed by vnc)
3590 if (defined($conf->{tablet
})) {
3591 $tablet = $conf->{tablet
};
3593 $tablet = $defaults->{tablet
};
3594 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3595 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3599 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3600 my $kbd = print_keyboarddevice_full
($conf, $arch);
3601 push @$devices, '-device', $kbd if defined($kbd);
3605 my $gpu_passthrough;
3608 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3609 my $d = parse_hostpci
($conf->{"hostpci$i"});
3612 my $pcie = $d->{pcie
};
3614 die "q35 machine model is not enabled" if !$q35;
3615 # win7 wants to have the pcie devices directly on the pcie bus
3616 # instead of in the root port
3617 if ($winversion == 7) {
3618 $pciaddr = print_pcie_addr
("hostpci${i}bus0");
3620 $pciaddr = print_pcie_addr
("hostpci$i");
3623 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3626 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3627 my $romfile = $d->{romfile
};
3630 if ($d->{'x-vga'}) {
3631 $xvga = ',x-vga=on';
3633 $vga->{type
} = 'none' if !defined($conf->{vga
});
3634 $gpu_passthrough = 1;
3636 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3640 my $pcidevices = $d->{pciid
};
3641 my $multifunction = 1 if @$pcidevices > 1;
3643 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3644 my $id = $pcidevices->[0]->{id
};
3645 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3646 $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3647 } elsif ($d->{mdev
}) {
3648 warn "ignoring mediated device with multifunction device\n";
3652 foreach my $pcidevice (@$pcidevices) {
3654 my $id = "hostpci$i";
3655 $id .= ".$j" if $multifunction;
3656 my $addr = $pciaddr;
3657 $addr .= ".$j" if $multifunction;
3658 my $devicestr = "vfio-pci";
3660 $devicestr .= ",sysfsdev=$sysfspath";
3662 $devicestr .= ",host=$pcidevice->{id}";
3664 $devicestr .= ",id=$id$addr";
3667 $devicestr .= "$rombar$xvga";
3668 $devicestr .= ",multifunction=on" if $multifunction;
3669 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3672 push @$devices, '-device', $devicestr;
3678 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3679 push @$devices, @usbdevices if @usbdevices;
3681 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3682 if (my $path = $conf->{"serial$i"}) {
3683 if ($path eq 'socket') {
3684 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3685 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3686 # On aarch64, serial0 is the UART device. Qemu only allows
3687 # connecting UART devices via the '-serial' command line, as
3688 # the device has a fixed slot on the hardware...
3689 if ($arch eq 'aarch64' && $i == 0) {
3690 push @$devices, '-serial', "chardev:serial$i";
3692 push @$devices, '-device', "isa-serial,chardev=serial$i";
3695 die "no such serial device\n" if ! -c
$path;
3696 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3697 push @$devices, '-device', "isa-serial,chardev=serial$i";
3703 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3704 if (my $path = $conf->{"parallel$i"}) {
3705 die "no such parallel device\n" if ! -c
$path;
3706 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3707 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3708 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3714 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3715 $sockets = $conf->{sockets
} if $conf->{sockets
};
3717 my $cores = $conf->{cores
} || 1;
3719 my $maxcpus = $sockets * $cores;
3721 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3723 my $allowed_vcpus = $cpuinfo->{cpus
};
3725 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3726 if ($allowed_vcpus < $maxcpus);
3728 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3730 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3731 for (my $i = 2; $i <= $vcpus; $i++) {
3732 my $cpustr = print_cpu_device
($conf,$i);
3733 push @$cmd, '-device', $cpustr;
3738 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3740 push @$cmd, '-nodefaults';
3742 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3744 my $bootindex_hash = {};
3746 foreach my $o (split(//, $bootorder)) {
3747 $bootindex_hash->{$o} = $i*100;
3751 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3753 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3755 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3757 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3758 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3759 my $socket = vnc_socket
($vmid);
3760 push @$cmd, '-vnc', "unix:$socket,x509,password";
3762 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3763 push @$cmd, '-nographic';
3767 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3769 my $useLocaltime = $conf->{localtime};
3771 if ($winversion >= 5) { # windows
3772 $useLocaltime = 1 if !defined($conf->{localtime});
3774 # use time drift fix when acpi is enabled
3775 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3776 $tdf = 1 if !defined($conf->{tdf
});
3780 if ($winversion >= 6) {
3781 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3782 push @$cmd, '-no-hpet';
3785 push @$rtcFlags, 'driftfix=slew' if $tdf;
3788 push @$machineFlags, 'accel=tcg';
3791 if ($machine_type) {
3792 push @$machineFlags, "type=${machine_type}";
3795 if ($conf->{startdate
}) {
3796 push @$rtcFlags, "base=$conf->{startdate}";
3797 } elsif ($useLocaltime) {
3798 push @$rtcFlags, 'base=localtime';
3801 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3803 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3805 push @$cmd, '-S' if $conf->{freeze
};
3807 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3810 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3811 #push @$cmd, '-soundhw', 'es1370';
3812 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3814 if (parse_guest_agent
($conf)->{enabled
}) {
3815 my $qgasocket = qmp_socket
($vmid, 1);
3816 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3817 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3818 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3819 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3827 for(my $i = 1; $i < $qxlnum; $i++){
3828 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3831 # assume other OS works like Linux
3832 my ($ram, $vram) = ("134217728", "67108864");
3833 if ($vga->{memory
}) {
3834 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3835 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3837 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3838 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3842 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3844 my $nodename = PVE
::INotify
::nodename
();
3845 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3846 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3847 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3848 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3849 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3851 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3853 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3854 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3855 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3858 # enable balloon by default, unless explicitly disabled
3859 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3860 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3861 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3864 if ($conf->{watchdog
}) {
3865 my $wdopts = parse_watchdog
($conf->{watchdog
});
3866 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3867 my $watchdog = $wdopts->{model
} || 'i6300esb';
3868 push @$devices, '-device', "$watchdog$pciaddr";
3869 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3873 my $scsicontroller = {};
3874 my $ahcicontroller = {};
3875 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3877 # Add iscsi initiator name if available
3878 if (my $initiator = get_initiator_name
()) {
3879 push @$devices, '-iscsi', "initiator-name=$initiator";
3882 foreach_drive
($conf, sub {
3883 my ($ds, $drive) = @_;
3885 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3886 push @$vollist, $drive->{file
};
3889 # ignore efidisk here, already added in bios/fw handling code above
3890 return if $drive->{interface
} eq 'efidisk';
3892 $use_virtio = 1 if $ds =~ m/^virtio/;
3894 if (drive_is_cdrom
($drive)) {
3895 if ($bootindex_hash->{d
}) {
3896 $drive->{bootindex
} = $bootindex_hash->{d
};
3897 $bootindex_hash->{d
} += 1;
3900 if ($bootindex_hash->{c
}) {
3901 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3902 $bootindex_hash->{c
} += 1;
3906 if($drive->{interface
} eq 'virtio'){
3907 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3910 if ($drive->{interface
} eq 'scsi') {
3912 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3914 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3915 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3918 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3919 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3920 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3921 } elsif ($drive->{iothread
}) {
3922 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3926 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3927 $queues = ",num_queues=$drive->{queues}";
3930 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3931 $scsicontroller->{$controller}=1;
3934 if ($drive->{interface
} eq 'sata') {
3935 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3936 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3937 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3938 $ahcicontroller->{$controller}=1;
3941 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3942 push @$devices, '-drive',$drive_cmd;
3943 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3946 for (my $i = 0; $i < $MAX_NETS; $i++) {
3947 next if !$conf->{"net$i"};
3948 my $d = parse_net
($conf->{"net$i"});
3951 $use_virtio = 1 if $d->{model
} eq 'virtio';
3953 if ($bootindex_hash->{n
}) {
3954 $d->{bootindex
} = $bootindex_hash->{n
};
3955 $bootindex_hash->{n
} += 1;
3958 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3959 push @$devices, '-netdev', $netdevfull;
3961 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3962 push @$devices, '-device', $netdevicefull;
3965 if ($conf->{ivshmem
}) {
3966 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3970 $bus = print_pcie_addr
("ivshmem");
3972 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3975 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3976 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3978 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3979 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3984 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3989 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3991 while (my ($k, $v) = each %$bridges) {
3992 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3993 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3997 push @$cmd, @$devices;
3998 push @$cmd, '-rtc', join(',', @$rtcFlags)
3999 if scalar(@$rtcFlags);
4000 push @$cmd, '-machine', join(',', @$machineFlags)
4001 if scalar(@$machineFlags);
4002 push @$cmd, '-global', join(',', @$globalFlags)
4003 if scalar(@$globalFlags);
4006 if ($conf->{args
}) {
4007 my $aa = PVE
::Tools
::split_args
($conf->{args
});
4011 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
4016 return "${var_run_tmpdir}/$vmid.vnc";
4022 my $res = vm_mon_cmd
($vmid, 'query-spice');
4024 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
4028 my ($vmid, $qga, $name) = @_;
4029 my $sockettype = $qga ?
'qga' : 'qmp';
4030 my $ext = $name ?
'-'.$name : '';
4031 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
4036 return "${var_run_tmpdir}/$vmid.pid";
4039 sub vm_devices_list
{
4042 my $res = vm_mon_cmd
($vmid, 'query-pci');
4043 my $devices_to_check = [];
4045 foreach my $pcibus (@$res) {
4046 push @$devices_to_check, @{$pcibus->{devices
}},
4049 while (@$devices_to_check) {
4051 for my $d (@$devices_to_check) {
4052 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4053 next if !$d->{'pci_bridge'};
4055 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
4056 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
4058 $devices_to_check = $to_check;
4061 my $resblock = vm_mon_cmd
($vmid, 'query-block');
4062 foreach my $block (@$resblock) {
4063 if($block->{device
} =~ m/^drive-(\S+)/){
4068 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
4069 foreach my $mice (@$resmice) {
4070 if ($mice->{name
} eq 'QEMU HID Tablet') {
4071 $devices->{tablet
} = 1;
4076 # for usb devices there is no query-usb
4077 # but we can iterate over the entries in
4078 # qom-list path=/machine/peripheral
4079 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4080 foreach my $per (@$resperipheral) {
4081 if ($per->{name
} =~ m/^usb\d+$/) {
4082 $devices->{$per->{name
}} = 1;
4090 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4092 my $q35 = machine_type_is_q35
($conf);
4094 my $devices_list = vm_devices_list
($vmid);
4095 return 1 if defined($devices_list->{$deviceid});
4097 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
4099 if ($deviceid eq 'tablet') {
4101 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4103 } elsif ($deviceid eq 'keyboard') {
4105 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4107 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4109 die "usb hotplug currently not reliable\n";
4110 # since we can't reliably hot unplug all added usb devices
4111 # and usb passthrough disables live migration
4112 # we disable usb hotplugging for now
4113 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
4115 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4117 qemu_iothread_add
($vmid, $deviceid, $device);
4119 qemu_driveadd
($storecfg, $vmid, $device);
4120 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4122 qemu_deviceadd
($vmid, $devicefull);
4123 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4125 eval { qemu_drivedel
($vmid, $deviceid); };
4130 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4133 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4134 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4135 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4137 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4139 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4140 qemu_iothread_add
($vmid, $deviceid, $device);
4141 $devicefull .= ",iothread=iothread-$deviceid";
4144 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4145 $devicefull .= ",num_queues=$device->{queues}";
4148 qemu_deviceadd
($vmid, $devicefull);
4149 qemu_deviceaddverify
($vmid, $deviceid);
4151 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4153 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4154 qemu_driveadd
($storecfg, $vmid, $device);
4156 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4157 eval { qemu_deviceadd
($vmid, $devicefull); };
4159 eval { qemu_drivedel
($vmid, $deviceid); };
4164 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4166 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4168 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4169 my $use_old_bios_files = undef;
4170 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4172 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4173 qemu_deviceadd
($vmid, $netdevicefull);
4175 qemu_deviceaddverify
($vmid, $deviceid);
4176 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4179 eval { qemu_netdevdel
($vmid, $deviceid); };
4184 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4187 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4188 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4190 qemu_deviceadd
($vmid, $devicefull);
4191 qemu_deviceaddverify
($vmid, $deviceid);
4194 die "can't hotplug device '$deviceid'\n";
4200 # fixme: this should raise exceptions on error!
4201 sub vm_deviceunplug
{
4202 my ($vmid, $conf, $deviceid) = @_;
4204 my $devices_list = vm_devices_list
($vmid);
4205 return 1 if !defined($devices_list->{$deviceid});
4207 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4209 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4211 qemu_devicedel
($vmid, $deviceid);
4213 } elsif ($deviceid =~ m/^usb\d+$/) {
4215 die "usb hotplug currently not reliable\n";
4216 # when unplugging usb devices this way,
4217 # there may be remaining usb controllers/hubs
4218 # so we disable it for now
4219 qemu_devicedel
($vmid, $deviceid);
4220 qemu_devicedelverify
($vmid, $deviceid);
4222 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4224 qemu_devicedel
($vmid, $deviceid);
4225 qemu_devicedelverify
($vmid, $deviceid);
4226 qemu_drivedel
($vmid, $deviceid);
4227 qemu_iothread_del
($conf, $vmid, $deviceid);
4229 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4231 qemu_devicedel
($vmid, $deviceid);
4232 qemu_devicedelverify
($vmid, $deviceid);
4233 qemu_iothread_del
($conf, $vmid, $deviceid);
4235 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4237 qemu_devicedel
($vmid, $deviceid);
4238 qemu_drivedel
($vmid, $deviceid);
4239 qemu_deletescsihw
($conf, $vmid, $deviceid);
4241 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4243 qemu_devicedel
($vmid, $deviceid);
4244 qemu_devicedelverify
($vmid, $deviceid);
4245 qemu_netdevdel
($vmid, $deviceid);
4248 die "can't unplug device '$deviceid'\n";
4254 sub qemu_deviceadd
{
4255 my ($vmid, $devicefull) = @_;
4257 $devicefull = "driver=".$devicefull;
4258 my %options = split(/[=,]/, $devicefull);
4260 vm_mon_cmd
($vmid, "device_add" , %options);
4263 sub qemu_devicedel
{
4264 my ($vmid, $deviceid) = @_;
4266 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4269 sub qemu_iothread_add
{
4270 my($vmid, $deviceid, $device) = @_;
4272 if ($device->{iothread
}) {
4273 my $iothreads = vm_iothreads_list
($vmid);
4274 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4278 sub qemu_iothread_del
{
4279 my($conf, $vmid, $deviceid) = @_;
4281 my $confid = $deviceid;
4282 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
4283 $confid = 'scsi' . $1;
4285 my $device = parse_drive
($confid, $conf->{$confid});
4286 if ($device->{iothread
}) {
4287 my $iothreads = vm_iothreads_list
($vmid);
4288 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4292 sub qemu_objectadd
{
4293 my($vmid, $objectid, $qomtype) = @_;
4295 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4300 sub qemu_objectdel
{
4301 my($vmid, $objectid) = @_;
4303 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4309 my ($storecfg, $vmid, $device) = @_;
4311 my $drive = print_drive_full
($storecfg, $vmid, $device);
4312 $drive =~ s/\\/\\\\/g;
4313 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4315 # If the command succeeds qemu prints: "OK
"
4316 return 1 if $ret =~ m/OK/s;
4318 die "adding drive failed
: $ret\n";
4322 my($vmid, $deviceid) = @_;
4324 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4327 return 1 if $ret eq "";
4329 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4330 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4332 die "deleting drive
$deviceid failed
: $ret\n";
4335 sub qemu_deviceaddverify {
4336 my ($vmid, $deviceid) = @_;
4338 for (my $i = 0; $i <= 5; $i++) {
4339 my $devices_list = vm_devices_list($vmid);
4340 return 1 if defined($devices_list->{$deviceid});
4344 die "error on hotplug device
'$deviceid'\n";
4348 sub qemu_devicedelverify {
4349 my ($vmid, $deviceid) = @_;
4351 # need to verify that the device is correctly removed as device_del
4352 # is async and empty return is not reliable
4354 for (my $i = 0; $i <= 5; $i++) {
4355 my $devices_list = vm_devices_list($vmid);
4356 return 1 if !defined($devices_list->{$deviceid});
4360 die "error on hot-unplugging device
'$deviceid'\n";
4363 sub qemu_findorcreatescsihw {
4364 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4366 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4368 my $scsihwid="$controller_prefix$controller";
4369 my $devices_list = vm_devices_list($vmid);
4371 if(!defined($devices_list->{$scsihwid})) {
4372 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4378 sub qemu_deletescsihw {
4379 my ($conf, $vmid, $opt) = @_;
4381 my $device = parse_drive($opt, $conf->{$opt});
4383 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4384 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4388 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4390 my $devices_list = vm_devices_list($vmid);
4391 foreach my $opt (keys %{$devices_list}) {
4392 if (PVE::QemuServer::is_valid_drivename($opt)) {
4393 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4394 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4400 my $scsihwid="scsihw
$controller";
4402 vm_deviceunplug($vmid, $conf, $scsihwid);
4407 sub qemu_add_pci_bridge {
4408 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4414 print_pci_addr($device, $bridges, $arch, $machine_type);
4416 while (my ($k, $v) = each %$bridges) {
4419 return 1 if !defined($bridgeid) || $bridgeid < 1;
4421 my $bridge = "pci
.$bridgeid";
4422 my $devices_list = vm_devices_list($vmid);
4424 if (!defined($devices_list->{$bridge})) {
4425 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4431 sub qemu_set_link_status {
4432 my ($vmid, $device, $up) = @_;
4434 vm_mon_cmd($vmid, "set_link
", name => $device,
4435 up => $up ? JSON::true : JSON::false);
4438 sub qemu_netdevadd {
4439 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4441 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4442 my %options = split(/[=,]/, $netdev);
4444 vm_mon_cmd($vmid, "netdev_add
", %options);
4448 sub qemu_netdevdel {
4449 my ($vmid, $deviceid) = @_;
4451 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4454 sub qemu_usb_hotplug {
4455 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4459 # remove the old one first
4460 vm_deviceunplug($vmid, $conf, $deviceid);
4462 # check if xhci controller is necessary and available
4463 if ($device->{usb3}) {
4465 my $devicelist = vm_devices_list($vmid);
4467 if (!$devicelist->{xhci}) {
4468 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4469 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4472 my $d = parse_usb_device($device->{host});
4473 $d->{usb3} = $device->{usb3};
4476 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4479 sub qemu_cpu_hotplug {
4480 my ($vmid, $conf, $vcpus) = @_;
4482 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4485 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4486 $sockets = $conf->{sockets} if $conf->{sockets};
4487 my $cores = $conf->{cores} || 1;
4488 my $maxcpus = $sockets * $cores;
4490 $vcpus = $maxcpus if !$vcpus;
4492 die "you can
't add more vcpus than maxcpus\n"
4493 if $vcpus > $maxcpus;
4495 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4497 if ($vcpus < $currentvcpus) {
4499 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4501 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4502 qemu_devicedel($vmid, "cpu$i");
4504 my $currentrunningvcpus = undef;
4506 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4507 last if scalar(@{$currentrunningvcpus}) == $i-1;
4508 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4512 #update conf after each succesfull cpu unplug
4513 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4514 PVE::QemuConfig->write_config($vmid, $conf);
4517 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4523 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4524 die "vcpus in running vm does not match its configuration\n"
4525 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4527 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4529 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4530 my $cpustr = print_cpu_device($conf, $i);
4531 qemu_deviceadd($vmid, $cpustr);
4534 my $currentrunningvcpus = undef;
4536 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4537 last if scalar(@{$currentrunningvcpus}) == $i;
4538 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4542 #update conf after each succesfull cpu hotplug
4543 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4544 PVE::QemuConfig->write_config($vmid, $conf);
4548 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4549 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4554 sub qemu_block_set_io_throttle {
4555 my ($vmid, $deviceid,
4556 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4557 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4558 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4559 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4561 return if !check_running($vmid) ;
4563 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4565 bps_rd => int($bps_rd),
4566 bps_wr => int($bps_wr),
4568 iops_rd => int($iops_rd),
4569 iops_wr => int($iops_wr),
4570 bps_max => int($bps_max),
4571 bps_rd_max => int($bps_rd_max),
4572 bps_wr_max => int($bps_wr_max),
4573 iops_max => int($iops_max),
4574 iops_rd_max => int($iops_rd_max),
4575 iops_wr_max => int($iops_wr_max),
4576 bps_max_length => int($bps_max_length),
4577 bps_rd_max_length => int($bps_rd_max_length),
4578 bps_wr_max_length => int($bps_wr_max_length),
4579 iops_max_length => int($iops_max_length),
4580 iops_rd_max_length => int($iops_rd_max_length),
4581 iops_wr_max_length => int($iops_wr_max_length),
4586 # old code, only used to shutdown old VM after update
4588 my ($fh, $timeout) = @_;
4590 my $sel = new IO::Select;
4597 while (scalar (@ready = $sel->can_read($timeout))) {
4599 if ($count = $fh->sysread($buf, 8192)) {
4600 if ($buf =~ /^(.*)\(qemu\) $/s) {
4607 if (!defined($count)) {
4614 die "monitor read timeout\n" if !scalar(@ready);
4619 sub qemu_block_resize {
4620 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4622 my $running = check_running($vmid);
4624 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4626 return if !$running;
4628 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4632 sub qemu_volume_snapshot {
4633 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4635 my $running = check_running($vmid);
4637 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4638 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4640 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4644 sub qemu_volume_snapshot_delete {
4645 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4647 my $running = check_running($vmid);
4652 my $conf = PVE::QemuConfig->load_config($vmid);
4653 foreach_drive($conf, sub {
4654 my ($ds, $drive) = @_;
4655 $running = 1 if $drive->{file} eq $volid;
4659 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4660 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4662 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4666 sub set_migration_caps {
4672 "auto-converge" => 1,
4674 "x-rdma-pin-all" => 0,
4679 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4681 for my $supported_capability (@$supported_capabilities) {
4683 capability => $supported_capability->{capability},
4684 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4688 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4691 my $fast_plug_option = {
4699 'vmstatestorage
' => 1,
4703 # hotplug changes in [PENDING]
4704 # $selection hash can be used to only apply specified options, for
4705 # example: { cores => 1 } (only apply changed 'cores
')
4706 # $errors ref is used to return error messages
4707 sub vmconfig_hotplug_pending {
4708 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4710 my $defaults = load_defaults();
4711 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4713 # commit values which do not have any impact on running VM first
4714 # Note: those option cannot raise errors, we we do not care about
4715 # $selection and always apply them.
4717 my $add_error = sub {
4718 my ($opt, $msg) = @_;
4719 $errors->{$opt} = "hotplug problem - $msg";
4723 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4724 if ($fast_plug_option->{$opt}) {
4725 $conf->{$opt} = $conf->{pending}->{$opt};
4726 delete $conf->{pending}->{$opt};
4732 PVE::QemuConfig->write_config($vmid, $conf);
4733 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4736 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4738 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4739 while (my ($opt, $force) = each %$pending_delete_hash) {
4740 next if $selection && !$selection->{$opt};
4742 if ($opt eq 'hotplug
') {
4743 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4744 } elsif ($opt eq 'tablet
') {
4745 die "skip\n" if !$hotplug_features->{usb};
4746 if ($defaults->{tablet}) {
4747 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4748 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4749 if $arch eq 'aarch64
';
4751 vm_deviceunplug($vmid, $conf, 'tablet
');
4752 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4754 } elsif ($opt =~ m/^usb\d+/) {
4756 # since we cannot reliably hot unplug usb devices
4757 # we are disabling it
4758 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4759 vm_deviceunplug($vmid, $conf, $opt);
4760 } elsif ($opt eq 'vcpus
') {
4761 die "skip\n" if !$hotplug_features->{cpu};
4762 qemu_cpu_hotplug($vmid, $conf, undef);
4763 } elsif ($opt eq 'balloon
') {
4764 # enable balloon device is not hotpluggable
4765 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4766 # here we reset the ballooning value to memory
4767 my $balloon = $conf->{memory} || $defaults->{memory};
4768 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4769 } elsif ($fast_plug_option->{$opt}) {
4771 } elsif ($opt =~ m/^net(\d+)$/) {
4772 die "skip\n" if !$hotplug_features->{network};
4773 vm_deviceunplug($vmid, $conf, $opt);
4774 } elsif (is_valid_drivename($opt)) {
4775 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4776 vm_deviceunplug($vmid, $conf, $opt);
4777 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4778 } elsif ($opt =~ m/^memory$/) {
4779 die "skip\n" if !$hotplug_features->{memory};
4780 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4781 } elsif ($opt eq 'cpuunits
') {
4782 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4783 } elsif ($opt eq 'cpulimit
') {
4784 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4790 &$add_error($opt, $err) if $err ne "skip\n";
4792 # save new config if hotplug was successful
4793 delete $conf->{$opt};
4794 vmconfig_undelete_pending_option($conf, $opt);
4795 PVE::QemuConfig->write_config($vmid, $conf);
4796 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4800 my $apply_pending_cloudinit;
4801 $apply_pending_cloudinit = sub {
4802 my ($key, $value) = @_;
4803 $apply_pending_cloudinit = sub {}; # once is enough
4805 my @cloudinit_opts = keys %$confdesc_cloudinit;
4806 foreach my $opt (keys %{$conf->{pending}}) {
4807 next if !grep { $_ eq $opt } @cloudinit_opts;
4808 $conf->{$opt} = delete $conf->{pending}->{$opt};
4811 my $new_conf = { %$conf };
4812 $new_conf->{$key} = $value;
4813 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4816 foreach my $opt (keys %{$conf->{pending}}) {
4817 next if $selection && !$selection->{$opt};
4818 my $value = $conf->{pending}->{$opt};
4820 if ($opt eq 'hotplug
') {
4821 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4822 } elsif ($opt eq 'tablet
') {
4823 die "skip\n" if !$hotplug_features->{usb};
4825 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4826 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4827 if $arch eq 'aarch64
';
4828 } elsif ($value == 0) {
4829 vm_deviceunplug($vmid, $conf, 'tablet
');
4830 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4832 } elsif ($opt =~ m/^usb\d+$/) {
4834 # since we cannot reliably hot unplug usb devices
4835 # we are disabling it
4836 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4837 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4838 die "skip\n" if !$d;
4839 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4840 } elsif ($opt eq 'vcpus
') {
4841 die "skip\n" if !$hotplug_features->{cpu};
4842 qemu_cpu_hotplug($vmid, $conf, $value);
4843 } elsif ($opt eq 'balloon
') {
4844 # enable/disable balloning device is not hotpluggable
4845 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4846 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4847 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4849 # allow manual ballooning if shares is set to zero
4850 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4851 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4852 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4854 } elsif ($opt =~ m/^net(\d+)$/) {
4855 # some changes can be done without hotplug
4856 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4857 $vmid, $opt, $value, $arch, $machine_type);
4858 } elsif (is_valid_drivename($opt)) {
4859 # some changes can be done without hotplug
4860 my $drive = parse_drive($opt, $value);
4861 if (drive_is_cloudinit($drive)) {
4862 &$apply_pending_cloudinit($opt, $value);
4864 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4865 $vmid, $opt, $value, 1, $arch, $machine_type);
4866 } elsif ($opt =~ m/^memory$/) { #dimms
4867 die "skip\n" if !$hotplug_features->{memory};
4868 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4869 } elsif ($opt eq 'cpuunits
') {
4870 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4871 } elsif ($opt eq 'cpulimit
') {
4872 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4873 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4875 die "skip\n"; # skip non-hot-pluggable options
4879 &$add_error($opt, $err) if $err ne "skip\n";
4881 # save new config if hotplug was successful
4882 $conf->{$opt} = $value;
4883 delete $conf->{pending}->{$opt};
4884 PVE::QemuConfig->write_config($vmid, $conf);
4885 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4890 sub try_deallocate_drive {
4891 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4893 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4894 my $volid = $drive->{file};
4895 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4896 my $sid = PVE::Storage::parse_volume_id($volid);
4897 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4899 # check if the disk is really unused
4900 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4901 if is_volume_in_use($storecfg, $conf, $key, $volid);
4902 PVE::Storage::vdisk_free($storecfg, $volid);
4905 # If vm is not owner of this disk remove from config
4913 sub vmconfig_delete_or_detach_drive {
4914 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4916 my $drive = parse_drive($opt, $conf->{$opt});
4918 my $rpcenv = PVE::RPCEnvironment::get();
4919 my $authuser = $rpcenv->get_user();
4922 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4923 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4925 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4929 sub vmconfig_apply_pending {
4930 my ($vmid, $conf, $storecfg) = @_;
4934 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4935 while (my ($opt, $force) = each %$pending_delete_hash) {
4936 die "internal error" if $opt =~ m/^unused/;
4937 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4938 if (!defined($conf->{$opt})) {
4939 vmconfig_undelete_pending_option($conf, $opt);
4940 PVE::QemuConfig->write_config($vmid, $conf);
4941 } elsif (is_valid_drivename($opt)) {
4942 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4943 vmconfig_undelete_pending_option($conf, $opt);
4944 delete $conf->{$opt};
4945 PVE::QemuConfig->write_config($vmid, $conf);
4947 vmconfig_undelete_pending_option($conf, $opt);
4948 delete $conf->{$opt};
4949 PVE::QemuConfig->write_config($vmid, $conf);
4953 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4955 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4956 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4958 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4959 # skip if nothing changed
4960 } elsif (is_valid_drivename($opt)) {
4961 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4962 if defined($conf->{$opt});
4963 $conf->{$opt} = $conf->{pending}->{$opt};
4965 $conf->{$opt} = $conf->{pending}->{$opt};
4968 delete $conf->{pending}->{$opt};
4969 PVE::QemuConfig->write_config($vmid, $conf);
4973 my $safe_num_ne = sub {
4976 return 0 if !defined($a) && !defined($b);
4977 return 1 if !defined($a);
4978 return 1 if !defined($b);
4983 my $safe_string_ne = sub {
4986 return 0 if !defined($a) && !defined($b);
4987 return 1 if !defined($a);
4988 return 1 if !defined($b);
4993 sub vmconfig_update_net {
4994 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4996 my $newnet = parse_net($value);
4998 if ($conf->{$opt}) {
4999 my $oldnet = parse_net($conf->{$opt});
5001 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5002 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5003 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
5004 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5006 # for non online change, we try to hot-unplug
5007 die "skip\n" if !$hotplug;
5008 vm_deviceunplug($vmid, $conf, $opt);
5011 die "internal error" if $opt !~ m/net(\d+)/;
5012 my $iface = "tap${vmid}i$1";
5014 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5015 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
5016 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
5017 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
5018 PVE::Network::tap_unplug($iface);
5019 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5020 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
5021 # Rate can be applied on its own but any change above needs to
5022 # include the rate in tap_plug since OVS resets everything.
5023 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
5026 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5027 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5035 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5041 sub vmconfig_update_disk {
5042 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
5044 # fixme: do we need force?
5046 my $drive = parse_drive($opt, $value);
5048 if ($conf->{$opt}) {
5050 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5052 my $media = $drive->{media} || 'disk
';
5053 my $oldmedia = $old_drive->{media} || 'disk
';
5054 die "unable to change media type\n" if $media ne $oldmedia;
5056 if (!drive_is_cdrom($old_drive)) {
5058 if ($drive->{file} ne $old_drive->{file}) {
5060 die "skip\n" if !$hotplug;
5062 # unplug and register as unused
5063 vm_deviceunplug($vmid, $conf, $opt);
5064 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5067 # update existing disk
5069 # skip non hotpluggable value
5070 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5071 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5072 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5073 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5078 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5079 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5080 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5081 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5082 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5083 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5084 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5085 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5086 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5087 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5088 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5089 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5090 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5091 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5092 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5093 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5094 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5095 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5097 qemu_block_set_io_throttle($vmid,"drive-$opt",
5098 ($drive->{mbps} || 0)*1024*1024,
5099 ($drive->{mbps_rd} || 0)*1024*1024,
5100 ($drive->{mbps_wr} || 0)*1024*1024,
5101 $drive->{iops} || 0,
5102 $drive->{iops_rd} || 0,
5103 $drive->{iops_wr} || 0,
5104 ($drive->{mbps_max} || 0)*1024*1024,
5105 ($drive->{mbps_rd_max} || 0)*1024*1024,
5106 ($drive->{mbps_wr_max} || 0)*1024*1024,
5107 $drive->{iops_max} || 0,
5108 $drive->{iops_rd_max} || 0,
5109 $drive->{iops_wr_max} || 0,
5110 $drive->{bps_max_length} || 1,
5111 $drive->{bps_rd_max_length} || 1,
5112 $drive->{bps_wr_max_length} || 1,
5113 $drive->{iops_max_length} || 1,
5114 $drive->{iops_rd_max_length} || 1,
5115 $drive->{iops_wr_max_length} || 1);
5124 if ($drive->{file} eq 'none
') {
5125 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5126 if (drive_is_cloudinit($old_drive)) {
5127 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5130 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5131 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5132 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5140 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5142 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5143 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5147 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5148 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5150 PVE::QemuConfig->lock_config($vmid, sub {
5151 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5153 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5155 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5157 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5159 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5160 vmconfig_apply_pending($vmid, $conf, $storecfg);
5161 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5164 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5166 my $defaults = load_defaults();
5168 # set environment variable useful inside network script
5169 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5171 my $local_volumes = {};
5173 if ($targetstorage) {
5174 foreach_drive($conf, sub {
5175 my ($ds, $drive) = @_;
5177 return if drive_is_cdrom($drive);
5179 my $volid = $drive->{file};
5183 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5185 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5186 return if $scfg->{shared};
5187 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5192 foreach my $opt (sort keys %$local_volumes) {
5194 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5195 my $drive = parse_drive($opt, $conf->{$opt});
5197 #if remote storage is specified, use default format
5198 if ($targetstorage && $targetstorage ne "1") {
5199 $storeid = $targetstorage;
5200 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5201 $format = $defFormat;
5203 #else we use same format than original
5204 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5205 $format = qemu_img_format($scfg, $volid);
5208 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5209 my $newdrive = $drive;
5210 $newdrive->{format} = $format;
5211 $newdrive->{file} = $newvolid;
5212 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5213 $local_volumes->{$opt} = $drivestr;
5214 #pass drive to conf for command line
5215 $conf->{$opt} = $drivestr;
5219 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
5221 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5223 my $migrate_port = 0;
5226 if ($statefile eq 'tcp
') {
5227 my $localip = "localhost";
5228 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5229 my $nodename = PVE::INotify::nodename();
5231 if (!defined($migration_type)) {
5232 if (defined($datacenterconf->{migration}->{type})) {
5233 $migration_type = $datacenterconf->{migration}->{type};
5235 $migration_type = 'secure
';
5239 if ($migration_type eq 'insecure
') {
5240 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5241 if ($migrate_network_addr) {
5242 $localip = $migrate_network_addr;
5244 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5247 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5250 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5251 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5252 $migrate_uri = "tcp:${localip}:${migrate_port}";
5253 push @$cmd, '-incoming
', $migrate_uri;
5256 } elsif ($statefile eq 'unix
') {
5257 # should be default for secure migrations as a ssh TCP forward
5258 # tunnel is not deterministic reliable ready and fails regurarly
5259 # to set up in time, so use UNIX socket forwards
5260 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5261 unlink $socket_addr;
5263 $migrate_uri = "unix:$socket_addr";
5265 push @$cmd, '-incoming
', $migrate_uri;
5269 push @$cmd, '-loadstate
', $statefile;
5276 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5277 my $d = parse_hostpci($conf->{"hostpci$i"});
5279 my $pcidevices = $d->{pciid};
5280 foreach my $pcidevice (@$pcidevices) {
5281 my $pciid = $pcidevice->{id};
5283 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5284 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5285 die "no pci device info for device '$pciid'\n" if !$info;
5288 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5289 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5291 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5292 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5293 die "can
't reset pci device '$pciid'\n"
5294 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5299 PVE::Storage::activate_volumes($storecfg, $vollist);
5301 if (-d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
5303 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5304 outfunc => sub {}, errfunc => sub {});
5308 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5309 : $defaults->{cpuunits};
5311 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5312 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5315 Slice => 'qemu
.slice
',
5317 CPUShares => $cpuunits
5320 if (my $cpulimit = $conf->{cpulimit}) {
5321 $properties{CPUQuota} = int($cpulimit * 100);
5323 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5325 my $run_qemu = sub {
5326 PVE::Tools::run_fork sub {
5327 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5328 run_command($cmd, %run_params);
5332 if ($conf->{hugepages}) {
5335 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5336 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5338 PVE::QemuServer::Memory::hugepages_mount();
5339 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5341 eval { $run_qemu->() };
5343 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5347 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5349 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5352 eval { $run_qemu->() };
5356 # deactivate volumes if start fails
5357 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5358 die "start failed: $err";
5361 print "migration listens on $migrate_uri\n" if $migrate_uri;
5363 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5364 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5368 #start nbd server for storage migration
5369 if ($targetstorage) {
5370 my $nodename = PVE::INotify::nodename();
5371 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5372 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5373 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5374 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5376 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5378 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5380 foreach my $opt (sort keys %$local_volumes) {
5381 my $volid = $local_volumes->{$opt};
5382 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5383 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5384 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5388 if ($migratedfrom) {
5390 set_migration_caps($vmid);
5395 print "spice listens on port $spice_port\n";
5396 if ($spice_ticket) {
5397 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5398 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5403 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5404 if !$statefile && $conf->{balloon};
5406 foreach my $opt (keys %$conf) {
5407 next if $opt !~ m/^net\d+$/;
5408 my $nicconf = parse_net($conf->{$opt});
5409 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5413 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5414 path => "machine/peripheral/balloon0",
5415 property => "guest-stats-polling-interval",
5416 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5418 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start
');
5423 my ($vmid, $execute, %params) = @_;
5425 my $cmd = { execute => $execute, arguments => \%params };
5426 vm_qmp_command($vmid, $cmd);
5429 sub vm_mon_cmd_nocheck {
5430 my ($vmid, $execute, %params) = @_;
5432 my $cmd = { execute => $execute, arguments => \%params };
5433 vm_qmp_command($vmid, $cmd, 1);
5436 sub vm_qmp_command {
5437 my ($vmid, $cmd, $nocheck) = @_;
5442 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5443 $timeout = $cmd->{arguments}->{timeout};
5444 delete $cmd->{arguments}->{timeout};
5448 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5449 my $sname = qmp_socket($vmid);
5450 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5451 my $qmpclient = PVE::QMPClient->new();
5453 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5455 die "unable to open monitor socket\n";
5459 syslog("err", "VM $vmid qmp command failed - $err");
5466 sub vm_human_monitor_command {
5467 my ($vmid, $cmdline) = @_;
5472 execute => 'human-monitor-command
',
5473 arguments => { 'command-line
' => $cmdline},
5476 return vm_qmp_command($vmid, $cmd);
5479 sub vm_commandline {
5480 my ($storecfg, $vmid, $snapname) = @_;
5482 my $conf = PVE::QemuConfig->load_config($vmid);
5485 my $snapshot = $conf->{snapshots}->{$snapname};
5486 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5488 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
5493 my $defaults = load_defaults();
5495 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5497 return PVE::Tools::cmd2string($cmd);
5501 my ($vmid, $skiplock) = @_;
5503 PVE::QemuConfig->lock_config($vmid, sub {
5505 my $conf = PVE::QemuConfig->load_config($vmid);
5507 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5509 vm_mon_cmd($vmid, "system_reset");
5513 sub get_vm_volumes {
5517 foreach_volid($conf, sub {
5518 my ($volid, $attr) = @_;
5520 return if $volid =~ m|^/|;
5522 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5525 push @$vollist, $volid;
5531 sub vm_stop_cleanup {
5532 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5537 my $vollist = get_vm_volumes($conf);
5538 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5541 foreach my $ext (qw(mon qmp pid vnc qga)) {
5542 unlink "/var/run/qemu-server/${vmid}.$ext";
5545 if ($conf->{ivshmem
}) {
5546 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5547 # just delete it for now, VMs which have this already open do not
5548 # are affected, but new VMs will get a separated one. If this
5549 # becomes an issue we either add some sort of ref-counting or just
5550 # add a "don't delete on stop" flag to the ivshmem format.
5551 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5554 foreach my $key (keys %$conf) {
5555 next if $key !~ m/^hostpci(\d+)$/;
5556 my $hostpciindex = $1;
5557 my $d = parse_hostpci
($conf->{$key});
5558 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5560 foreach my $pci (@{$d->{pciid
}}) {
5561 my $pciid = $pci->{id
};
5562 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5566 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5568 warn $@ if $@; # avoid errors - just warn
5571 # Note: use $nockeck to skip tests if VM configuration file exists.
5572 # We need that when migration VMs to other nodes (files already moved)
5573 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5575 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5577 $force = 1 if !defined($force) && !$shutdown;
5580 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5581 kill 15, $pid if $pid;
5582 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5583 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5587 PVE
::QemuConfig-
>lock_config($vmid, sub {
5589 my $pid = check_running
($vmid, $nocheck);
5594 $conf = PVE
::QemuConfig-
>load_config($vmid);
5595 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5596 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5597 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5598 $timeout = $opts->{down
} if $opts->{down
};
5600 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5603 $timeout = 60 if !defined($timeout);
5607 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5608 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5610 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5613 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5620 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5625 if ($count >= $timeout) {
5627 warn "VM still running - terminating now with SIGTERM\n";
5630 die "VM quit/powerdown failed - got timeout\n";
5633 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5638 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5641 die "VM quit/powerdown failed\n";
5649 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5654 if ($count >= $timeout) {
5655 warn "VM still running - terminating now with SIGKILL\n";
5660 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5665 my ($vmid, $skiplock) = @_;
5667 PVE
::QemuConfig-
>lock_config($vmid, sub {
5669 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5671 PVE
::QemuConfig-
>check_lock($conf)
5672 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5674 vm_mon_cmd
($vmid, "stop");
5679 my ($vmid, $skiplock, $nocheck) = @_;
5681 PVE
::QemuConfig-
>lock_config($vmid, sub {
5683 my $res = vm_mon_cmd
($vmid, 'query-status');
5684 my $resume_cmd = 'cont';
5686 if ($res->{status
} && $res->{status
} eq 'suspended') {
5687 $resume_cmd = 'system_wakeup';
5692 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5694 PVE
::QemuConfig-
>check_lock($conf)
5695 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5697 vm_mon_cmd
($vmid, $resume_cmd);
5700 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5706 my ($vmid, $skiplock, $key) = @_;
5708 PVE
::QemuConfig-
>lock_config($vmid, sub {
5710 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5712 # there is no qmp command, so we use the human monitor command
5713 vm_human_monitor_command
($vmid, "sendkey $key");
5718 my ($storecfg, $vmid, $skiplock) = @_;
5720 PVE
::QemuConfig-
>lock_config($vmid, sub {
5722 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5724 if (!check_running
($vmid)) {
5725 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5727 die "VM $vmid is running - destroy failed\n";
5732 # vzdump restore implementaion
5734 sub tar_archive_read_firstfile
{
5735 my $archive = shift;
5737 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5739 # try to detect archive type first
5740 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5741 die "unable to open file '$archive'\n";
5742 my $firstfile = <$fh>;
5746 die "ERROR: archive contaions no data\n" if !$firstfile;
5752 sub tar_restore_cleanup
{
5753 my ($storecfg, $statfile) = @_;
5755 print STDERR
"starting cleanup\n";
5757 if (my $fd = IO
::File-
>new($statfile, "r")) {
5758 while (defined(my $line = <$fd>)) {
5759 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5762 if ($volid =~ m
|^/|) {
5763 unlink $volid || die 'unlink failed\n';
5765 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5767 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5769 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5771 print STDERR
"unable to parse line in statfile - $line";
5778 sub restore_archive
{
5779 my ($archive, $vmid, $user, $opts) = @_;
5781 my $format = $opts->{format
};
5784 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5785 $format = 'tar' if !$format;
5787 } elsif ($archive =~ m/\.tar$/) {
5788 $format = 'tar' if !$format;
5789 } elsif ($archive =~ m/.tar.lzo$/) {
5790 $format = 'tar' if !$format;
5792 } elsif ($archive =~ m/\.vma$/) {
5793 $format = 'vma' if !$format;
5794 } elsif ($archive =~ m/\.vma\.gz$/) {
5795 $format = 'vma' if !$format;
5797 } elsif ($archive =~ m/\.vma\.lzo$/) {
5798 $format = 'vma' if !$format;
5801 $format = 'vma' if !$format; # default
5804 # try to detect archive format
5805 if ($format eq 'tar') {
5806 return restore_tar_archive
($archive, $vmid, $user, $opts);
5808 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5812 sub restore_update_config_line
{
5813 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5815 return if $line =~ m/^\#qmdump\#/;
5816 return if $line =~ m/^\#vzdump\#/;
5817 return if $line =~ m/^lock:/;
5818 return if $line =~ m/^unused\d+:/;
5819 return if $line =~ m/^parent:/;
5820 return if $line =~ m/^template:/; # restored VM is never a template
5822 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5823 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5824 # try to convert old 1.X settings
5825 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5826 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5827 my ($model, $macaddr) = split(/\=/, $devconfig);
5828 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5831 bridge
=> "vmbr$ind",
5832 macaddr
=> $macaddr,
5834 my $netstr = print_net
($net);
5836 print $outfd "net$cookie->{netcount}: $netstr\n";
5837 $cookie->{netcount
}++;
5839 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5840 my ($id, $netstr) = ($1, $2);
5841 my $net = parse_net
($netstr);
5842 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5843 $netstr = print_net
($net);
5844 print $outfd "$id: $netstr\n";
5845 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5848 my $di = parse_drive
($virtdev, $value);
5849 if (defined($di->{backup
}) && !$di->{backup
}) {
5850 print $outfd "#$line";
5851 } elsif ($map->{$virtdev}) {
5852 delete $di->{format
}; # format can change on restore
5853 $di->{file
} = $map->{$virtdev};
5854 $value = print_drive
($vmid, $di);
5855 print $outfd "$virtdev: $value\n";
5859 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5861 if ($vmgenid ne '0') {
5862 # always generate a new vmgenid if there was a valid one setup
5863 $vmgenid = generate_uuid
();
5865 print $outfd "vmgenid: $vmgenid\n";
5866 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5867 my ($uuid, $uuid_str);
5868 UUID
::generate
($uuid);
5869 UUID
::unparse
($uuid, $uuid_str);
5870 my $smbios1 = parse_smbios1
($2);
5871 $smbios1->{uuid
} = $uuid_str;
5872 print $outfd $1.print_smbios1
($smbios1)."\n";
5879 my ($cfg, $vmid) = @_;
5881 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5883 my $volid_hash = {};
5884 foreach my $storeid (keys %$info) {
5885 foreach my $item (@{$info->{$storeid}}) {
5886 next if !($item->{volid
} && $item->{size
});
5887 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5888 $volid_hash->{$item->{volid
}} = $item;
5895 sub is_volume_in_use
{
5896 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5898 my $path = PVE
::Storage
::path
($storecfg, $volid);
5900 my $scan_config = sub {
5901 my ($cref, $snapname) = @_;
5903 foreach my $key (keys %$cref) {
5904 my $value = $cref->{$key};
5905 if (is_valid_drivename
($key)) {
5906 next if $skip_drive && $key eq $skip_drive;
5907 my $drive = parse_drive
($key, $value);
5908 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5909 return 1 if $volid eq $drive->{file
};
5910 if ($drive->{file
} =~ m!^/!) {
5911 return 1 if $drive->{file
} eq $path;
5913 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5915 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5917 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5925 return 1 if &$scan_config($conf);
5929 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5930 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5936 sub update_disksize
{
5937 my ($vmid, $conf, $volid_hash) = @_;
5940 my $prefix = "VM $vmid:";
5942 # used and unused disks
5943 my $referenced = {};
5945 # Note: it is allowed to define multiple storages with same path (alias), so
5946 # we need to check both 'volid' and real 'path' (two different volid can point
5947 # to the same path).
5949 my $referencedpath = {};
5952 foreach my $opt (keys %$conf) {
5953 if (is_valid_drivename
($opt)) {
5954 my $drive = parse_drive
($opt, $conf->{$opt});
5955 my $volid = $drive->{file
};
5958 $referenced->{$volid} = 1;
5959 if ($volid_hash->{$volid} &&
5960 (my $path = $volid_hash->{$volid}->{path
})) {
5961 $referencedpath->{$path} = 1;
5964 next if drive_is_cdrom
($drive);
5965 next if !$volid_hash->{$volid};
5967 $drive->{size
} = $volid_hash->{$volid}->{size
};
5968 my $new = print_drive
($vmid, $drive);
5969 if ($new ne $conf->{$opt}) {
5971 $conf->{$opt} = $new;
5972 print "$prefix update disk '$opt' information.\n";
5977 # remove 'unusedX' entry if volume is used
5978 foreach my $opt (keys %$conf) {
5979 next if $opt !~ m/^unused\d+$/;
5980 my $volid = $conf->{$opt};
5981 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5982 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5983 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5985 delete $conf->{$opt};
5988 $referenced->{$volid} = 1;
5989 $referencedpath->{$path} = 1 if $path;
5992 foreach my $volid (sort keys %$volid_hash) {
5993 next if $volid =~ m/vm-$vmid-state-/;
5994 next if $referenced->{$volid};
5995 my $path = $volid_hash->{$volid}->{path
};
5996 next if !$path; # just to be sure
5997 next if $referencedpath->{$path};
5999 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6000 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
6001 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6008 my ($vmid, $nolock, $dryrun) = @_;
6010 my $cfg = PVE
::Storage
::config
();
6012 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
6013 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
6014 foreach my $stor (keys %{$cfg->{ids
}}) {
6015 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
6018 print "rescan volumes...\n";
6019 my $volid_hash = scan_volids
($cfg, $vmid);
6021 my $updatefn = sub {
6024 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6026 PVE
::QemuConfig-
>check_lock($conf);
6029 foreach my $volid (keys %$volid_hash) {
6030 my $info = $volid_hash->{$volid};
6031 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6034 my $changes = update_disksize
($vmid, $conf, $vm_volids);
6036 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6039 if (defined($vmid)) {
6043 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6046 my $vmlist = config_list
();
6047 foreach my $vmid (keys %$vmlist) {
6051 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6057 sub restore_vma_archive
{
6058 my ($archive, $vmid, $user, $opts, $comp) = @_;
6060 my $readfrom = $archive;
6062 my $cfg = PVE
::Storage
::config
();
6064 my $bwlimit = $opts->{bwlimit
};
6066 my $dbg_cmdstring = '';
6067 my $add_pipe = sub {
6069 push @$commands, $cmd;
6070 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6071 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6076 if ($archive eq '-') {
6079 # If we use a backup from a PVE defined storage we also consider that
6080 # storage's rate limit:
6081 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6082 if (defined($volid)) {
6083 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6084 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6086 print STDERR
"applying read rate limit: $readlimit\n";
6087 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6088 $add_pipe->($cstream);
6095 if ($comp eq 'gzip') {
6096 $cmd = ['zcat', $readfrom];
6097 } elsif ($comp eq 'lzop') {
6098 $cmd = ['lzop', '-d', '-c', $readfrom];
6100 die "unknown compression method '$comp'\n";
6105 my $tmpdir = "/var/tmp/vzdumptmp$$";
6108 # disable interrupts (always do cleanups)
6112 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6114 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6115 POSIX
::mkfifo
($mapfifo, 0600);
6118 my $openfifo = sub {
6119 open($fifofh, '>', $mapfifo) || die $!;
6122 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6129 my $rpcenv = PVE
::RPCEnvironment
::get
();
6131 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6132 my $tmpfn = "$conffile.$$.tmp";
6134 # Note: $oldconf is undef if VM does not exists
6135 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6136 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6140 my $print_devmap = sub {
6141 my $virtdev_hash = {};
6143 my $cfgfn = "$tmpdir/qemu-server.conf";
6145 # we can read the config - that is already extracted
6146 my $fh = IO
::File-
>new($cfgfn, "r") ||
6147 "unable to read qemu-server.conf - $!\n";
6149 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6151 my $pve_firewall_dir = '/etc/pve/firewall';
6152 mkdir $pve_firewall_dir; # make sure the dir exists
6153 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6156 while (defined(my $line = <$fh>)) {
6157 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6158 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6159 die "archive does not contain data for drive '$virtdev'\n"
6160 if !$devinfo->{$devname};
6161 if (defined($opts->{storage
})) {
6162 $storeid = $opts->{storage
} || 'local';
6163 } elsif (!$storeid) {
6166 $format = 'raw' if !$format;
6167 $devinfo->{$devname}->{devname
} = $devname;
6168 $devinfo->{$devname}->{virtdev
} = $virtdev;
6169 $devinfo->{$devname}->{format
} = $format;
6170 $devinfo->{$devname}->{storeid
} = $storeid;
6172 # check permission on storage
6173 my $pool = $opts->{pool
}; # todo: do we need that?
6174 if ($user ne 'root@pam') {
6175 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6178 $storage_limits{$storeid} = $bwlimit;
6180 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6184 foreach my $key (keys %storage_limits) {
6185 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6187 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6188 $storage_limits{$key} = $limit * 1024;
6191 foreach my $devname (keys %$devinfo) {
6192 die "found no device mapping information for device '$devname'\n"
6193 if !$devinfo->{$devname}->{virtdev
};
6196 # create empty/temp config
6198 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6199 foreach_drive
($oldconf, sub {
6200 my ($ds, $drive) = @_;
6202 return if drive_is_cdrom
($drive);
6204 my $volid = $drive->{file
};
6206 return if !$volid || $volid =~ m
|^/|;
6208 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6209 return if !$path || !$owner || ($owner != $vmid);
6211 # Note: only delete disk we want to restore
6212 # other volumes will become unused
6213 if ($virtdev_hash->{$ds}) {
6214 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6221 # delete vmstate files
6222 # since after the restore we have no snapshots anymore
6223 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6224 my $snap = $oldconf->{snapshots
}->{$snapname};
6225 if ($snap->{vmstate
}) {
6226 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6235 foreach my $virtdev (sort keys %$virtdev_hash) {
6236 my $d = $virtdev_hash->{$virtdev};
6237 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6238 my $storeid = $d->{storeid
};
6239 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6242 if (my $limit = $storage_limits{$storeid}) {
6243 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6246 # test if requested format is supported
6247 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6248 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6249 $d->{format
} = $defFormat if !$supported;
6251 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6252 $d->{format
}, undef, $alloc_size);
6253 print STDERR
"new volume ID is '$volid'\n";
6254 $d->{volid
} = $volid;
6255 my $path = PVE
::Storage
::path
($cfg, $volid);
6257 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6259 my $write_zeros = 1;
6260 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6264 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6266 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6267 $map->{$virtdev} = $volid;
6270 $fh->seek(0, 0) || die "seek failed - $!\n";
6272 my $outfd = new IO
::File
($tmpfn, "w") ||
6273 die "unable to write config for VM $vmid\n";
6275 my $cookie = { netcount
=> 0 };
6276 while (defined(my $line = <$fh>)) {
6277 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6290 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6291 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6293 $oldtimeout = alarm($timeout);
6300 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6301 my ($dev_id, $size, $devname) = ($1, $2, $3);
6302 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6303 } elsif ($line =~ m/^CTIME: /) {
6304 # we correctly received the vma config, so we can disable
6305 # the timeout now for disk allocation (set to 10 minutes, so
6306 # that we always timeout if something goes wrong)
6309 print $fifofh "done\n";
6310 my $tmp = $oldtimeout || 0;
6311 $oldtimeout = undef;
6317 print "restore vma archive: $dbg_cmdstring\n";
6318 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6322 alarm($oldtimeout) if $oldtimeout;
6325 foreach my $devname (keys %$devinfo) {
6326 my $volid = $devinfo->{$devname}->{volid
};
6327 push @$vollist, $volid if $volid;
6330 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6338 foreach my $devname (keys %$devinfo) {
6339 my $volid = $devinfo->{$devname}->{volid
};
6342 if ($volid =~ m
|^/|) {
6343 unlink $volid || die 'unlink failed\n';
6345 PVE
::Storage
::vdisk_free
($cfg, $volid);
6347 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6349 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6356 rename($tmpfn, $conffile) ||
6357 die "unable to commit configuration file '$conffile'\n";
6359 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6361 eval { rescan
($vmid, 1); };
6365 sub restore_tar_archive
{
6366 my ($archive, $vmid, $user, $opts) = @_;
6368 if ($archive ne '-') {
6369 my $firstfile = tar_archive_read_firstfile
($archive);
6370 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6371 if $firstfile ne 'qemu-server.conf';
6374 my $storecfg = PVE
::Storage
::config
();
6376 # destroy existing data - keep empty config
6377 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6378 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6380 my $tocmd = "/usr/lib/qemu-server/qmextract";
6382 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6383 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6384 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6385 $tocmd .= ' --info' if $opts->{info
};
6387 # tar option "xf" does not autodetect compression when read from STDIN,
6388 # so we pipe to zcat
6389 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6390 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6392 my $tmpdir = "/var/tmp/vzdumptmp$$";
6395 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6396 local $ENV{VZDUMP_VMID
} = $vmid;
6397 local $ENV{VZDUMP_USER
} = $user;
6399 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6400 my $tmpfn = "$conffile.$$.tmp";
6402 # disable interrupts (always do cleanups)
6406 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6414 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6416 if ($archive eq '-') {
6417 print "extracting archive from STDIN\n";
6418 run_command
($cmd, input
=> "<&STDIN");
6420 print "extracting archive '$archive'\n";
6424 return if $opts->{info
};
6428 my $statfile = "$tmpdir/qmrestore.stat";
6429 if (my $fd = IO
::File-
>new($statfile, "r")) {
6430 while (defined (my $line = <$fd>)) {
6431 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6432 $map->{$1} = $2 if $1;
6434 print STDERR
"unable to parse line in statfile - $line\n";
6440 my $confsrc = "$tmpdir/qemu-server.conf";
6442 my $srcfd = new IO
::File
($confsrc, "r") ||
6443 die "unable to open file '$confsrc'\n";
6445 my $outfd = new IO
::File
($tmpfn, "w") ||
6446 die "unable to write config for VM $vmid\n";
6448 my $cookie = { netcount
=> 0 };
6449 while (defined (my $line = <$srcfd>)) {
6450 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6462 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6469 rename $tmpfn, $conffile ||
6470 die "unable to commit configuration file '$conffile'\n";
6472 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6474 eval { rescan
($vmid, 1); };
6478 sub foreach_storage_used_by_vm
{
6479 my ($conf, $func) = @_;
6483 foreach_drive
($conf, sub {
6484 my ($ds, $drive) = @_;
6485 return if drive_is_cdrom
($drive);
6487 my $volid = $drive->{file
};
6489 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6490 $sidhash->{$sid} = $sid if $sid;
6493 foreach my $sid (sort keys %$sidhash) {
6498 sub do_snapshots_with_qemu
{
6499 my ($storecfg, $volid) = @_;
6501 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6503 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6504 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6508 if ($volid =~ m/\.(qcow2|qed)$/){
6515 sub qga_check_running
{
6516 my ($vmid, $nowarn) = @_;
6518 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6520 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6526 sub template_create
{
6527 my ($vmid, $conf, $disk) = @_;
6529 my $storecfg = PVE
::Storage
::config
();
6531 foreach_drive
($conf, sub {
6532 my ($ds, $drive) = @_;
6534 return if drive_is_cdrom
($drive);
6535 return if $disk && $ds ne $disk;
6537 my $volid = $drive->{file
};
6538 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6540 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6541 $drive->{file
} = $voliddst;
6542 $conf->{$ds} = print_drive
($vmid, $drive);
6543 PVE
::QemuConfig-
>write_config($vmid, $conf);
6547 sub convert_iscsi_path
{
6550 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6555 my $initiator_name = get_initiator_name
();
6557 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6558 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6561 die "cannot convert iscsi path '$path', unkown format\n";
6564 sub qemu_img_convert
{
6565 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6567 my $storecfg = PVE
::Storage
::config
();
6568 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6569 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6571 if ($src_storeid && $dst_storeid) {
6573 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6575 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6576 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6578 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6579 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6581 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6582 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6584 my $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6585 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6588 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6589 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6590 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6591 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6593 if ($src_is_iscsi) {
6594 push @$cmd, '--image-opts';
6595 $src_path = convert_iscsi_path
($src_path);
6597 push @$cmd, '-f', $src_format;
6600 if ($dst_is_iscsi) {
6601 push @$cmd, '--target-image-opts';
6602 $dst_path = convert_iscsi_path
($dst_path);
6604 push @$cmd, '-O', $dst_format;
6607 push @$cmd, $src_path;
6609 if (!$dst_is_iscsi && $is_zero_initialized) {
6610 push @$cmd, "zeroinit:$dst_path";
6612 push @$cmd, $dst_path;
6617 if($line =~ m/\((\S+)\/100\
%\)/){
6619 my $transferred = int($size * $percent / 100);
6620 my $remaining = $size - $transferred;
6622 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6627 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6629 die "copy failed: $err" if $err;
6633 sub qemu_img_format
{
6634 my ($scfg, $volname) = @_;
6636 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6643 sub qemu_drive_mirror
{
6644 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6646 $jobs = {} if !$jobs;
6650 $jobs->{"drive-$drive"} = {};
6652 if ($dst_volid =~ /^nbd:/) {
6653 $qemu_target = $dst_volid;
6656 my $storecfg = PVE
::Storage
::config
();
6657 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6659 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6661 $format = qemu_img_format
($dst_scfg, $dst_volname);
6663 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6665 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6668 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6669 $opts->{format
} = $format if $format;
6671 print "drive mirror is starting for drive-$drive\n";
6673 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6676 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6677 die "mirroring error: $err";
6680 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6683 sub qemu_drive_mirror_monitor
{
6684 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6687 my $err_complete = 0;
6690 die "storage migration timed out\n" if $err_complete > 300;
6692 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6694 my $running_mirror_jobs = {};
6695 foreach my $stat (@$stats) {
6696 next if $stat->{type
} ne 'mirror';
6697 $running_mirror_jobs->{$stat->{device
}} = $stat;
6700 my $readycounter = 0;
6702 foreach my $job (keys %$jobs) {
6704 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6705 print "$job : finished\n";
6706 delete $jobs->{$job};
6710 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6712 my $busy = $running_mirror_jobs->{$job}->{busy
};
6713 my $ready = $running_mirror_jobs->{$job}->{ready
};
6714 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6715 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6716 my $remaining = $total - $transferred;
6717 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6719 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6722 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6725 last if scalar(keys %$jobs) == 0;
6727 if ($readycounter == scalar(keys %$jobs)) {
6728 print "all mirroring jobs are ready \n";
6729 last if $skipcomplete; #do the complete later
6731 if ($vmiddst && $vmiddst != $vmid) {
6732 my $agent_running = $qga && qga_check_running
($vmid);
6733 if ($agent_running) {
6734 print "freeze filesystem\n";
6735 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6737 print "suspend vm\n";
6738 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6741 # if we clone a disk for a new target vm, we don't switch the disk
6742 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6744 if ($agent_running) {
6745 print "unfreeze filesystem\n";
6746 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6748 print "resume vm\n";
6749 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6755 foreach my $job (keys %$jobs) {
6756 # try to switch the disk if source and destination are on the same guest
6757 print "$job: Completing block job...\n";
6759 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6760 if ($@ =~ m/cannot be completed/) {
6761 print "$job: Block job cannot be completed, try again.\n";
6764 print "$job: Completed successfully.\n";
6765 $jobs->{$job}->{complete
} = 1;
6776 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6777 die "mirroring error: $err";
6782 sub qemu_blockjobs_cancel
{
6783 my ($vmid, $jobs) = @_;
6785 foreach my $job (keys %$jobs) {
6786 print "$job: Cancelling block job\n";
6787 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6788 $jobs->{$job}->{cancel
} = 1;
6792 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6794 my $running_jobs = {};
6795 foreach my $stat (@$stats) {
6796 $running_jobs->{$stat->{device
}} = $stat;
6799 foreach my $job (keys %$jobs) {
6801 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6802 print "$job: Done.\n";
6803 delete $jobs->{$job};
6807 last if scalar(keys %$jobs) == 0;
6814 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6815 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6820 print "create linked clone of drive $drivename ($drive->{file})\n";
6821 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6822 push @$newvollist, $newvolid;
6825 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6826 $storeid = $storage if $storage;
6828 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6829 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6831 print "create full clone of drive $drivename ($drive->{file})\n";
6833 if (drive_is_cloudinit
($drive)) {
6834 $name = "vm-$newvmid-cloudinit";
6836 # cloudinit only supports raw and qcow2 atm:
6837 if ($dst_format eq 'qcow2') {
6839 } elsif ($dst_format ne 'raw') {
6840 die "clone: unhandled format for cloudinit image\n";
6843 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6844 push @$newvollist, $newvolid;
6846 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6848 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6849 if (!$running || $snapname) {
6850 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6853 my $kvmver = get_running_qemu_version
($vmid);
6854 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6855 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6856 if $drive->{iothread
};
6859 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6863 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6866 $disk->{format
} = undef;
6867 $disk->{file
} = $newvolid;
6868 $disk->{size
} = $size;
6873 # this only works if VM is running
6874 sub get_current_qemu_machine
{
6877 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6878 my $res = vm_qmp_command
($vmid, $cmd);
6880 my ($current, $default);
6881 foreach my $e (@$res) {
6882 $default = $e->{name
} if $e->{'is-default'};
6883 $current = $e->{name
} if $e->{'is-current'};
6886 # fallback to the default machine if current is not supported by qemu
6887 return $current || $default || 'pc';
6890 sub get_running_qemu_version
{
6892 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6893 my $res = vm_qmp_command
($vmid, $cmd);
6894 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6897 sub qemu_machine_feature_enabled
{
6898 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6903 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6905 $current_major = $3;
6906 $current_minor = $4;
6908 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6910 $current_major = $1;
6911 $current_minor = $2;
6914 return 1 if $current_major > $version_major ||
6915 ($current_major == $version_major &&
6916 $current_minor >= $version_minor);
6919 sub qemu_machine_pxe
{
6920 my ($vmid, $conf, $machine) = @_;
6922 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6924 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6931 sub qemu_use_old_bios_files
{
6932 my ($machine_type) = @_;
6934 return if !$machine_type;
6936 my $use_old_bios_files = undef;
6938 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6940 $use_old_bios_files = 1;
6942 my $kvmver = kvm_user_version
();
6943 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6944 # load new efi bios files on migration. So this hack is required to allow
6945 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6946 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6947 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6950 return ($use_old_bios_files, $machine_type);
6953 sub create_efidisk
($$$$$) {
6954 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6956 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6957 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6959 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6960 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6961 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6963 my $path = PVE
::Storage
::path
($storecfg, $volid);
6965 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6967 die "Copying EFI vars image failed: $@" if $@;
6969 return ($volid, $vars_size);
6972 sub vm_iothreads_list
{
6975 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6978 foreach my $iothread (@$res) {
6979 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6986 my ($conf, $drive) = @_;
6990 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6992 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6998 my $controller = int($drive->{index} / $maxdev);
6999 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
7001 return ($maxdev, $controller, $controller_prefix);
7004 sub add_hyperv_enlightenments
{
7005 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
7007 return if $winversion < 6;
7008 return if $bios && $bios eq 'ovmf' && $winversion < 8;
7010 if ($gpu_passthrough || defined($hv_vendor_id)) {
7011 $hv_vendor_id //= 'proxmox';
7012 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
7015 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
7016 push @$cpuFlags , 'hv_spinlocks=0x1fff';
7017 push @$cpuFlags , 'hv_vapic';
7018 push @$cpuFlags , 'hv_time';
7020 push @$cpuFlags , 'hv_spinlocks=0xffff';
7023 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
7024 push @$cpuFlags , 'hv_reset';
7025 push @$cpuFlags , 'hv_vpindex';
7026 push @$cpuFlags , 'hv_runtime';
7029 if ($winversion >= 7) {
7030 push @$cpuFlags , 'hv_relaxed';
7032 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
7033 push @$cpuFlags , 'hv_synic';
7034 push @$cpuFlags , 'hv_stimer';
7039 sub windows_version
{
7042 return 0 if !$ostype;
7046 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7048 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7050 } elsif ($ostype =~ m/^win(\d+)$/) {
7057 sub resolve_dst_disk_format
{
7058 my ($storecfg, $storeid, $src_volname, $format) = @_;
7059 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7062 # if no target format is specified, use the source disk format as hint
7064 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7065 $format = qemu_img_format
($scfg, $src_volname);
7071 # test if requested format is supported - else use default
7072 my $supported = grep { $_ eq $format } @$validFormats;
7073 $format = $defFormat if !$supported;
7077 sub resolve_first_disk
{
7079 my @disks = PVE
::QemuServer
::valid_drive_names
();
7081 foreach my $ds (reverse @disks) {
7082 next if !$conf->{$ds};
7083 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
7084 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
7091 my ($uuid, $uuid_str);
7092 UUID
::generate
($uuid);
7093 UUID
::unparse
($uuid, $uuid_str);
7097 sub generate_smbios1_uuid
{
7098 return "uuid=".generate_uuid
();
7104 vm_mon_cmd
($vmid, 'nbd-server-stop');
7107 # bash completion helper
7109 sub complete_backup_archives
{
7110 my ($cmdname, $pname, $cvalue) = @_;
7112 my $cfg = PVE
::Storage
::config
();
7116 if ($cvalue =~ m/^([^:]+):/) {
7120 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7123 foreach my $id (keys %$data) {
7124 foreach my $item (@{$data->{$id}}) {
7125 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7126 push @$res, $item->{volid
} if defined($item->{volid
});
7133 my $complete_vmid_full = sub {
7136 my $idlist = vmstatus
();
7140 foreach my $id (keys %$idlist) {
7141 my $d = $idlist->{$id};
7142 if (defined($running)) {
7143 next if $d->{template
};
7144 next if $running && $d->{status
} ne 'running';
7145 next if !$running && $d->{status
} eq 'running';
7154 return &$complete_vmid_full();
7157 sub complete_vmid_stopped
{
7158 return &$complete_vmid_full(0);
7161 sub complete_vmid_running
{
7162 return &$complete_vmid_full(1);
7165 sub complete_storage
{
7167 my $cfg = PVE
::Storage
::config
();
7168 my $ids = $cfg->{ids
};
7171 foreach my $sid (keys %$ids) {
7172 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7173 next if !$ids->{$sid}->{content
}->{images
};