1 package PVE
::QemuServer
;
11 use File
::Copy
qw(copy);
22 use List
::Util
qw(first);
25 use Storable
qw(dclone);
26 use Time
::HiRes
qw(gettimeofday usleep);
30 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file);
33 use PVE
::DataCenterConfig
;
34 use PVE
::Exception
qw(raise raise_param_exc);
35 use PVE
::Format
qw(render_duration render_bytes);
36 use PVE
::GuestHelpers
qw(safe_string_ne safe_num_ne safe_boolean_ne);
37 use PVE
::Mapping
::PCI
;
38 use PVE
::Mapping
::USB
;
40 use PVE
::JSONSchema
qw(get_standard_option parse_property_string);
43 use PVE
::RESTEnvironment
qw(log_warn);
44 use PVE
::RPCEnvironment
;
48 use PVE
::Tools
qw(run_command file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
52 use PVE
::QemuServer
::Helpers
qw(min_version config_aware_timeout windows_version);
53 use PVE
::QemuServer
::Cloudinit
;
54 use PVE
::QemuServer
::CGroup
;
55 use PVE
::QemuServer
::CPUConfig
qw(print_cpu_device get_cpu_options);
56 use PVE
::QemuServer
::Drive
qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom drive_is_read_only parse_drive print_drive);
57 use PVE
::QemuServer
::Machine
;
58 use PVE
::QemuServer
::Memory
;
59 use PVE
::QemuServer
::Monitor
qw(mon_cmd);
60 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
61 use PVE
::QemuServer
::USB
;
65 require PVE
::Network
::SDN
::Zones
;
69 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
73 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
74 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
77 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
78 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
81 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
82 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
85 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
86 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
89 "$EDK2_FW_BASE/OVMF_CODE.fd",
90 "$EDK2_FW_BASE/OVMF_VARS.fd",
95 "$EDK2_FW_BASE/AAVMF_CODE.fd",
96 "$EDK2_FW_BASE/AAVMF_VARS.fd",
101 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
103 # Note about locking: we use flock on the config file protect against concurent actions.
104 # Aditionaly, we have a 'lock' setting in the config file. This can be set to 'migrate',
105 # 'backup', 'snapshot' or 'rollback'. Most actions are not allowed when such lock is set.
106 # But you can ignore this kind of lock with the --skiplock flag.
114 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
115 description
=> "Some command save/restore state from this location.",
121 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
122 description
=> "Specifies the QEMU machine type.",
124 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
129 # FIXME: remove in favor of just using the INotify one, it's cached there exactly the same way
132 $nodename_cache //= PVE
::INotify
::nodename
();
133 return $nodename_cache;
140 enum
=> [qw(i6300esb ib700)],
141 description
=> "Watchdog type to emulate.",
142 default => 'i6300esb',
147 enum
=> [qw(reset shutdown poweroff pause debug none)],
148 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
152 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
156 description
=> "Enable/disable communication with a QEMU Guest Agent (QGA) running in the VM.",
161 fstrim_cloned_disks
=> {
162 description
=> "Run fstrim after moving a disk or migrating the VM.",
167 'freeze-fs-on-backup' => {
168 description
=> "Freeze/thaw guest filesystems on backup for consistency.",
174 description
=> "Select the agent type",
178 enum
=> [qw(virtio isa)],
184 description
=> "Select the VGA type.",
189 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio virtio-gl vmware)],
192 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
204 description
=> "The size of the file in MB.",
208 pattern
=> '[a-zA-Z0-9\-]+',
210 format_description
=> 'string',
211 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
218 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
219 description
=> "Configure an audio device."
223 enum
=> ['spice', 'none'],
226 description
=> "Driver backend for the audio device."
230 my $spice_enhancements_fmt = {
235 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
239 enum
=> ['off', 'all', 'filter'],
242 description
=> "Enable video streaming. Uses compression for detected video streams."
249 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
251 description
=> "The file on the host to gather entropy from. In most cases '/dev/urandom'"
252 ." should be preferred over '/dev/random' to avoid entropy-starvation issues on the"
253 ." host. Using urandom does *not* decrease security in any meaningful way, as it's"
254 ." still seeded from real entropy, and the bytes provided will most likely be mixed"
255 ." with real entropy on the guest as well. '/dev/hwrng' can be used to pass through"
256 ." a hardware RNG from the host.",
260 description
=> "Maximum bytes of entropy allowed to get injected into the guest every"
261 ." 'period' milliseconds. Prefer a lower value when using '/dev/random' as source. Use"
262 ." `0` to disable limiting (potentially dangerous!).",
265 # default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
266 # (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
267 # reading from /dev/urandom
272 description
=> "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
273 ." the guest to retrieve another 'max_bytes' of entropy.",
279 my $meta_info_fmt = {
282 description
=> "The guest creation timestamp as UNIX epoch time",
288 description
=> "The QEMU (machine) version from the time this VM was created.",
289 pattern
=> '\d+(\.\d+)+',
298 description
=> "Specifies whether a VM will be started during system bootup.",
304 description
=> "Automatic restart after crash (currently ignored).",
309 type
=> 'string', format
=> 'pve-hotplug-features',
310 description
=> "Selectively enable hotplug features. This is a comma separated list of"
311 ." hotplug features: 'network', 'disk', 'cpu', 'memory', 'usb' and 'cloudinit'. Use '0' to disable"
312 ." hotplug completely. Using '1' as value is an alias for the default `network,disk,usb`."
313 ." USB hotplugging is possible for guests with machine version >= 7.1 and ostype l26 or"
315 default => 'network,disk,usb',
320 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
326 description
=> "Lock/unlock the VM.",
327 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
332 description
=> "Limit of CPU usage.",
333 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has"
334 ." total of '2' CPU time. Value '0' indicates no CPU limit.",
342 description
=> "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
343 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler."
344 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
345 ." weights of all the other running VMs.",
348 default => 'cgroup v1: 1024, cgroup v2: 100',
353 description
=> "Amount of RAM for the VM in MiB. This is the maximum available memory when"
354 ." you use the balloon device.",
361 description
=> "Amount of target RAM for the VM in MiB. Using zero disables the ballon driver.",
367 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the"
368 ." more memory this VM gets. Number is relative to weights of all other running VMs."
369 ." Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
377 description
=> "Keyboard layout for VNC server. This option is generally not required and"
378 ." is often better handled from within the guest OS.",
379 enum
=> PVE
::Tools
::kvmkeymaplist
(),
384 type
=> 'string', format
=> 'dns-name',
385 description
=> "Set a name for the VM. Only used on the configuration web interface.",
390 description
=> "SCSI controller model",
391 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
397 description
=> "Description for the VM. Shown in the web-interface VM's summary."
398 ." This is saved as comment inside the configuration file.",
399 maxLength
=> 1024 * 8,
404 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
405 description
=> "Specify guest operating system.",
406 verbose_description
=> <<EODESC,
407 Specify guest operating system. This is used to enable special
408 optimization/features for specific operating systems:
411 other;; unspecified OS
412 wxp;; Microsoft Windows XP
413 w2k;; Microsoft Windows 2000
414 w2k3;; Microsoft Windows 2003
415 w2k8;; Microsoft Windows 2008
416 wvista;; Microsoft Windows Vista
417 win7;; Microsoft Windows 7
418 win8;; Microsoft Windows 8/2012/2012r2
419 win10;; Microsoft Windows 10/2016/2019
420 win11;; Microsoft Windows 11/2022
421 l24;; Linux 2.4 Kernel
422 l26;; Linux 2.6 - 6.X Kernel
423 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
428 type
=> 'string', format
=> 'pve-qm-boot',
429 description
=> "Specify guest boot order. Use the 'order=' sub-property as usage with no"
430 ." key or 'legacy=' is deprecated.",
434 type
=> 'string', format
=> 'pve-qm-bootdisk',
435 description
=> "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
436 pattern
=> '(ide|sata|scsi|virtio)\d+',
441 description
=> "The number of CPUs. Please use option -sockets instead.",
448 description
=> "The number of CPU sockets.",
455 description
=> "The number of cores per socket.",
462 description
=> "Enable/disable NUMA.",
468 description
=> "Enable/disable hugepages memory.",
469 enum
=> [qw(any 2 1024)],
475 description
=> "Use together with hugepages. If enabled, hugepages will not not be deleted"
476 ." after VM shutdown and can be used for subsequent starts.",
481 description
=> "Number of hotplugged vcpus.",
488 description
=> "Enable/disable ACPI.",
493 description
=> "Enable/disable communication with the QEMU Guest Agent and its properties.",
495 format
=> $agent_fmt,
500 description
=> "Enable/disable KVM hardware virtualization.",
506 description
=> "Enable/disable time drift fix.",
512 description
=> "Set the real time clock (RTC) to local time. This is enabled by default if"
513 ." the `ostype` indicates a Microsoft Windows OS.",
518 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
522 type
=> 'string', format
=> $vga_fmt,
523 description
=> "Configure the VGA hardware.",
524 verbose_description
=> "Configure the VGA Hardware. If you want to use high resolution"
525 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
526 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
527 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
528 ." display server. For win* OS you can select how many independent displays you want,"
529 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
530 ." using a serial device as terminal.",
534 type
=> 'string', format
=> 'pve-qm-watchdog',
535 description
=> "Create a virtual hardware watchdog device.",
536 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled (by a guest"
537 ." action), the watchdog must be periodically polled by an agent inside the guest or"
538 ." else the watchdog will reset the guest (or execute the respective action specified)",
543 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
544 description
=> "Set the initial date of the real time clock. Valid format for date are:"
545 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
546 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
549 startup
=> get_standard_option
('pve-startup-order'),
553 description
=> "Enable/disable Template.",
559 description
=> "Arbitrary arguments passed to kvm.",
560 verbose_description
=> <<EODESCR,
561 Arbitrary arguments passed to kvm, for example:
563 args: -no-reboot -smbios 'type=0,vendor=FOO'
565 NOTE: this option is for experts only.
572 description
=> "Enable/disable the USB tablet device.",
573 verbose_description
=> "Enable/disable the USB tablet device. This device is usually needed"
574 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
575 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
576 ." may consider disabling this to save some context switches. This is turned off by"
577 ." default if you use spice (`qm set <vmid> --vga qxl`).",
582 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
586 migrate_downtime
=> {
589 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
595 type
=> 'string', format
=> 'pve-qm-ide',
596 typetext
=> '<volume>',
597 description
=> "This is an alias for option -ide2",
601 description
=> "Emulated CPU type.",
603 format
=> 'pve-vm-cpu-conf',
605 parent
=> get_standard_option
('pve-snapshot-name', {
607 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
611 description
=> "Timestamp for snapshots.",
617 type
=> 'string', format
=> 'pve-volume-id',
618 description
=> "Reference to a volume which stores the VM state. This is used internally"
621 vmstatestorage
=> get_standard_option
('pve-storage-id', {
622 description
=> "Default storage for VM state volumes/files.",
625 runningmachine
=> get_standard_option
('pve-qemu-machine', {
626 description
=> "Specifies the QEMU machine type of the running vm. This is used internally"
630 description
=> "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
631 ." internally for snapshots.",
634 pattern
=> $PVE::QemuServer
::CPUConfig
::qemu_cmdline_cpu_re
,
635 format_description
=> 'QEMU -cpu parameter'
637 machine
=> get_standard_option
('pve-qemu-machine'),
639 description
=> "Virtual processor architecture. Defaults to the host.",
642 enum
=> [qw(x86_64 aarch64)],
645 description
=> "Specify SMBIOS type 1 fields.",
646 type
=> 'string', format
=> 'pve-qm-smbios1',
653 description
=> "Sets the protection flag of the VM. This will disable the remove VM and"
654 ." remove disk operations.",
660 enum
=> [ qw(seabios ovmf) ],
661 description
=> "Select BIOS implementation.",
662 default => 'seabios',
666 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
667 format_description
=> 'UUID',
668 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
669 ." to disable explicitly.",
670 verbose_description
=> "The VM generation ID (vmgenid) device exposes a 128-bit integer"
671 ." value identifier to the guest OS. This allows to notify the guest operating system"
672 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
673 ." execution or creation from a template). The guest operating system notices the"
674 ." change, and is then able to react as appropriate by marking its copies of"
675 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
676 ."Note that auto-creation only works when done through API/CLI create or update methods"
677 .", but not when manually editing the config file.",
678 default => "1 (autogenerated)",
683 format
=> 'pve-volume-id',
685 description
=> "Script that will be executed during various steps in the vms lifetime.",
689 format
=> $ivshmem_fmt,
690 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to"
696 format
=> $audio_fmt,
697 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
700 spice_enhancements
=> {
702 format
=> $spice_enhancements_fmt,
703 description
=> "Configure additional enhancements for SPICE.",
707 type
=> 'string', format
=> 'pve-tag-list',
708 description
=> 'Tags of the VM. This is only meta information.',
714 description
=> "Configure a VirtIO-based Random Number Generator.",
719 format
=> $meta_info_fmt,
720 description
=> "Some (read-only) meta-information about this guest.",
724 type
=> 'string', format
=> 'pve-cpuset',
725 description
=> "List of host cores used to execute guest processes, for example: 0,5,8-11",
734 description
=> 'Specify a custom file containing all meta data passed to the VM via"
735 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
736 format
=> 'pve-volume-id',
737 format_description
=> 'volume',
742 description
=> 'To pass a custom file containing all network data to the VM via cloud-init.',
743 format
=> 'pve-volume-id',
744 format_description
=> 'volume',
749 description
=> 'To pass a custom file containing all user data to the VM via cloud-init.',
750 format
=> 'pve-volume-id',
751 format_description
=> 'volume',
756 description
=> 'To pass a custom file containing all vendor data to the VM via cloud-init.',
757 format
=> 'pve-volume-id',
758 format_description
=> 'volume',
761 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
763 my $confdesc_cloudinit = {
767 description
=> 'Specifies the cloud-init configuration format. The default depends on the'
768 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
769 .' and `configdrive2` for windows.',
770 enum
=> ['configdrive2', 'nocloud', 'opennebula'],
775 description
=> "cloud-init: User name to change ssh keys and password for instead of the"
776 ." image's configured default user.",
781 description
=> 'cloud-init: Password to assign the user. Using this is generally not'
782 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
783 .' support hashed passwords.',
788 description
=> 'cloud-init: do an automatic package upgrade after the first boot.'
793 description
=> 'cloud-init: Specify custom files to replace the automatically generated'
795 format
=> 'pve-qm-cicustom',
800 description
=> 'cloud-init: Sets DNS search domains for a container. Create will'
801 .' automatically use the setting from the host if neither searchdomain nor nameserver'
806 type
=> 'string', format
=> 'address-list',
807 description
=> 'cloud-init: Sets DNS server IP address for a container. Create will'
808 .' automatically use the setting from the host if neither searchdomain nor nameserver'
814 format
=> 'urlencoded',
815 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
819 # what about other qemu settings ?
821 #machine => 'string',
834 ##soundhw => 'string',
836 while (my ($k, $v) = each %$confdesc) {
837 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
841 my $MAX_SERIAL_PORTS = 4;
842 my $MAX_PARALLEL_PORTS = 3;
848 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
849 description
=> "CPUs accessing this NUMA node.",
850 format_description
=> "id[-id];...",
854 description
=> "Amount of memory this NUMA node provides.",
859 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
860 description
=> "Host NUMA nodes to use.",
861 format_description
=> "id[-id];...",
866 enum
=> [qw(preferred bind interleave)],
867 description
=> "NUMA allocation policy.",
871 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
874 type
=> 'string', format
=> $numa_fmt,
875 description
=> "NUMA topology.",
877 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
879 for (my $i = 0; $i < $MAX_NUMA; $i++) {
880 $confdesc->{"numa$i"} = $numadesc;
883 my $nic_model_list = [
899 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
901 my $net_fmt_bridge_descr = <<__EOD__;
902 Bridge to attach the network device to. The Proxmox VE standard bridge
905 If you do not specify a bridge, we create a kvm user (NATed) network
906 device, which provides DHCP and DNS services. The following addresses
913 The DHCP server assign addresses to the guest starting from 10.0.2.15.
917 macaddr
=> get_standard_option
('mac-addr', {
918 description
=> "MAC address. That address must be unique withing your network. This is"
919 ." automatically generated if not specified.",
923 description
=> "Network Card Model. The 'virtio' model provides the best performance with"
924 ." very low CPU overhead. If your guest does not support this driver, it is usually"
925 ." best to use 'e1000'.",
926 enum
=> $nic_model_list,
929 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
930 bridge
=> get_standard_option
('pve-bridge-id', {
931 description
=> $net_fmt_bridge_descr,
936 minimum
=> 0, maximum
=> 64,
937 description
=> 'Number of packet queues to be used on the device.',
943 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
948 minimum
=> 1, maximum
=> 4094,
949 description
=> 'VLAN tag to apply to packets on this interface.',
954 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
955 description
=> 'VLAN trunks to pass through this interface.',
956 format_description
=> 'vlanid[;vlanid...]',
961 description
=> 'Whether this interface should be protected by the firewall.',
966 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
971 minimum
=> 1, maximum
=> 65520,
972 description
=> "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
979 type
=> 'string', format
=> $net_fmt,
980 description
=> "Specify network devices.",
983 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
988 format
=> 'pve-ipv4-config',
989 format_description
=> 'IPv4Format/CIDR',
990 description
=> 'IPv4 address in CIDR format.',
997 format_description
=> 'GatewayIPv4',
998 description
=> 'Default gateway for IPv4 traffic.',
1004 format
=> 'pve-ipv6-config',
1005 format_description
=> 'IPv6Format/CIDR',
1006 description
=> 'IPv6 address in CIDR format.',
1013 format_description
=> 'GatewayIPv6',
1014 description
=> 'Default gateway for IPv6 traffic.',
1019 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
1020 my $ipconfigdesc = {
1022 type
=> 'string', format
=> 'pve-qm-ipconfig',
1023 description
=> <<'EODESCR',
1024 cloud-init: Specify IP addresses and gateways for the corresponding interface.
1026 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
1028 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
1029 gateway should be provided.
1030 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
1031 cloud-init 19.4 or newer.
1033 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
1037 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
1039 for (my $i = 0; $i < $MAX_NETS; $i++) {
1040 $confdesc->{"net$i"} = $netdesc;
1041 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
1044 foreach my $key (keys %$confdesc_cloudinit) {
1045 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1048 PVE
::JSONSchema
::register_format
('pve-cpuset', \
&pve_verify_cpuset
);
1049 sub pve_verify_cpuset
{
1050 my ($set_text, $noerr) = @_;
1052 my ($count, $members) = eval { PVE
::CpuSet
::parse_cpuset
($set_text) };
1056 die "unable to parse cpuset option\n";
1059 return PVE
::CpuSet-
>new($members)->short_string();
1062 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
1063 sub verify_volume_id_or_qm_path
{
1064 my ($volid, $noerr) = @_;
1066 return $volid if $volid eq 'none' || $volid eq 'cdrom';
1068 return verify_volume_id_or_absolute_path
($volid, $noerr);
1071 PVE
::JSONSchema
::register_format
('pve-volume-id-or-absolute-path', \
&verify_volume_id_or_absolute_path
);
1072 sub verify_volume_id_or_absolute_path
{
1073 my ($volid, $noerr) = @_;
1075 return $volid if $volid =~ m
|^/|;
1077 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
1088 pattern
=> '(/dev/.+|socket)',
1089 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1090 verbose_description
=> <<EODESCR,
1091 Create a serial device inside the VM (n is 0 to 3), and pass through a
1092 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1093 host side (use 'qm terminal' to open a terminal connection).
1095 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1096 use with special care.
1098 CAUTION: Experimental! User reported problems with this option.
1105 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1106 description
=> "Map host parallel devices (n is 0 to 2).",
1107 verbose_description
=> <<EODESCR,
1108 Map host parallel devices (n is 0 to 2).
1110 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1111 machines - use with special care.
1113 CAUTION: Experimental! User reported problems with this option.
1117 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1118 $confdesc->{"parallel$i"} = $paralleldesc;
1121 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1122 $confdesc->{"serial$i"} = $serialdesc;
1125 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
1126 $confdesc->{"hostpci$i"} = $PVE::QemuServer
::PCI
::hostpcidesc
;
1129 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1130 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1133 for (my $i = 0; $i < $PVE::QemuServer
::USB
::MAX_USB_DEVICES
; $i++) {
1134 $confdesc->{"usb$i"} = $PVE::QemuServer
::USB
::usbdesc
;
1142 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1143 . " Deprecated, use 'order=' instead.",
1144 pattern
=> '[acdn]{1,4}',
1145 format_description
=> "[acdn]{1,4}",
1147 # note: this is also the fallback if boot: is not given at all
1153 format
=> 'pve-qm-bootdev-list',
1154 format_description
=> "device[;device...]",
1155 description
=> <<EODESC,
1156 The guest will attempt to boot from devices in the order they appear here.
1158 Disks, optical drives and passed-through storage USB devices will be directly
1159 booted from, NICs will load PXE, and PCIe devices will either behave like disks
1160 (e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1162 Note that only devices in this list will be marked as bootable and thus loaded
1163 by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1164 (e.g. software-raid), you need to specify all of them here.
1166 Overrides the deprecated 'legacy=[acdn]*' value when given.
1170 PVE
::JSONSchema
::register_format
('pve-qm-boot', $boot_fmt);
1172 PVE
::JSONSchema
::register_format
('pve-qm-bootdev', \
&verify_bootdev
);
1173 sub verify_bootdev
{
1174 my ($dev, $noerr) = @_;
1176 my $special = $dev =~ m/^efidisk/ || $dev =~ m/^tpmstate/;
1177 return $dev if PVE
::QemuServer
::Drive
::is_valid_drivename
($dev) && !$special;
1181 return 0 if $dev !~ m/^$base\d+$/;
1182 return 0 if !$confdesc->{$dev};
1186 return $dev if $check->("net");
1187 return $dev if $check->("usb");
1188 return $dev if $check->("hostpci");
1191 die "invalid boot device '$dev'\n";
1194 sub print_bootorder
{
1196 return "" if !@$devs;
1197 my $data = { order
=> join(';', @$devs) };
1198 return PVE
::JSONSchema
::print_property_string
($data, $boot_fmt);
1201 my $kvm_api_version = 0;
1204 return $kvm_api_version if $kvm_api_version;
1206 open my $fh, '<', '/dev/kvm' or return;
1208 # 0xae00 => KVM_GET_API_VERSION
1209 $kvm_api_version = ioctl($fh, 0xae00, 0);
1212 return $kvm_api_version;
1215 my $kvm_user_version = {};
1218 sub kvm_user_version
{
1221 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1222 my $st = stat($binary);
1224 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1225 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1226 $cachedmtime == $st->mtime;
1228 $kvm_user_version->{$binary} = 'unknown';
1229 $kvm_mtime->{$binary} = $st->mtime;
1233 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1234 $kvm_user_version->{$binary} = $2;
1238 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1241 return $kvm_user_version->{$binary};
1244 my sub extract_version
{
1245 my ($machine_type, $version) = @_;
1246 $version = kvm_user_version
() if !defined($version);
1247 return PVE
::QemuServer
::Machine
::extract_version
($machine_type, $version)
1250 sub kernel_has_vhost_net
{
1251 return -c
'/dev/vhost-net';
1256 return defined($confdesc->{$key});
1260 sub get_cdrom_path
{
1262 return $cdrom_path if defined($cdrom_path);
1264 $cdrom_path = first
{ -l
$_ } map { "/dev/cdrom$_" } ('', '1', '2');
1266 if (!defined($cdrom_path)) {
1267 log_warn
("no physical CD-ROM available, ignoring");
1275 my ($storecfg, $vmid, $cdrom) = @_;
1277 if ($cdrom eq 'cdrom') {
1278 return get_cdrom_path
();
1279 } elsif ($cdrom eq 'none') {
1281 } elsif ($cdrom =~ m
|^/|) {
1284 return PVE
::Storage
::path
($storecfg, $cdrom);
1288 # try to convert old style file names to volume IDs
1289 sub filename_to_volume_id
{
1290 my ($vmid, $file, $media) = @_;
1292 if (!($file eq 'none' || $file eq 'cdrom' ||
1293 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1295 return if $file =~ m
|/|;
1297 if ($media && $media eq 'cdrom') {
1298 $file = "local:iso/$file";
1300 $file = "local:$vmid/$file";
1307 sub verify_media_type
{
1308 my ($opt, $vtype, $media) = @_;
1313 if ($media eq 'disk') {
1315 } elsif ($media eq 'cdrom') {
1318 die "internal error";
1321 return if ($vtype eq $etype);
1323 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1326 sub cleanup_drive_path
{
1327 my ($opt, $storecfg, $drive) = @_;
1329 # try to convert filesystem paths to volume IDs
1331 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1332 ($drive->{file
} !~ m
|^/dev/.+|) &&
1333 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1334 ($drive->{file
} !~ m/^\d+$/)) {
1335 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1336 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1338 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1339 verify_media_type
($opt, $vtype, $drive->{media
});
1340 $drive->{file
} = $volid;
1343 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1346 sub parse_hotplug_features
{
1351 return $res if $data eq '0';
1353 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1355 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1356 if ($feature =~ m/^(network|disk|cpu|memory|usb|cloudinit)$/) {
1359 die "invalid hotplug feature '$feature'\n";
1365 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1366 sub pve_verify_hotplug_features
{
1367 my ($value, $noerr) = @_;
1369 return $value if parse_hotplug_features
($value);
1373 die "unable to parse hotplug option\n";
1377 my($fh, $noerr) = @_;
1380 my $SG_GET_VERSION_NUM = 0x2282;
1382 my $versionbuf = "\x00" x
8;
1383 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1385 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1388 my $version = unpack("I", $versionbuf);
1389 if ($version < 30000) {
1390 die "scsi generic interface too old\n" if !$noerr;
1394 my $buf = "\x00" x
36;
1395 my $sensebuf = "\x00" x
8;
1396 my $cmd = pack("C x3 C x1", 0x12, 36);
1398 # see /usr/include/scsi/sg.h
1399 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";
1402 $sg_io_hdr_t, ord('S'), -3, length($cmd), length($sensebuf), 0, length($buf), $buf, $cmd, $sensebuf, 6000
1405 $ret = ioctl($fh, $SG_IO, $packet);
1407 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1411 my @res = unpack($sg_io_hdr_t, $packet);
1412 if ($res[17] || $res[18]) {
1413 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1418 $res->@{qw(type removable vendor product revision)} = unpack("C C x6 A8 A16 A4", $buf);
1420 $res->{removable
} = $res->{removable
} & 128 ?
1 : 0;
1421 $res->{type
} &= 0x1F;
1429 my $fh = IO
::File-
>new("+<$path") || return;
1430 my $res = scsi_inquiry
($fh, 1);
1436 sub print_tabletdevice_full
{
1437 my ($conf, $arch) = @_;
1439 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1441 # we use uhci for old VMs because tablet driver was buggy in older qemu
1443 if ($q35 || $arch eq 'aarch64') {
1449 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1452 sub print_keyboarddevice_full
{
1453 my ($conf, $arch) = @_;
1455 return if $arch ne 'aarch64';
1457 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1460 my sub get_drive_id
{
1462 return "$drive->{interface}$drive->{index}";
1465 sub print_drivedevice_full
{
1466 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1471 my $drive_id = get_drive_id
($drive);
1472 if ($drive->{interface
} eq 'virtio') {
1473 my $pciaddr = print_pci_addr
("$drive_id", $bridges, $arch, $machine_type);
1474 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1475 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread
};
1476 } elsif ($drive->{interface
} eq 'scsi') {
1478 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1479 my $unit = $drive->{index} % $maxdev;
1480 my $devicetype = 'hd';
1482 if (drive_is_cdrom
($drive)) {
1485 if ($drive->{file
} =~ m
|^/|) {
1486 $path = $drive->{file
};
1487 if (my $info = path_is_scsi
($path)) {
1488 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1489 $devicetype = 'block';
1490 } elsif ($info->{type
} == 1) { # tape
1491 $devicetype = 'generic';
1495 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1498 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1499 my $version = extract_version
($machine_type, kvm_user_version
());
1500 if ($path =~ m/^iscsi\:\/\
// &&
1501 !min_version
($version, 4, 1)) {
1502 $devicetype = 'generic';
1506 if (!$conf->{scsihw
} || $conf->{scsihw
} =~ m/^lsi/ || $conf->{scsihw
} eq 'pvscsi') {
1507 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
1509 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1510 .",lun=$drive->{index}";
1512 $device .= ",drive=drive-$drive_id,id=$drive_id";
1514 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1515 $device .= ",rotation_rate=1";
1517 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1519 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1520 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1521 my $controller = int($drive->{index} / $maxdev);
1522 my $unit = $drive->{index} % $maxdev;
1523 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1525 $device = "ide-$devicetype";
1526 if ($drive->{interface
} eq 'ide') {
1527 $device .= ",bus=ide.$controller,unit=$unit";
1529 $device .= ",bus=ahci$controller.$unit";
1531 $device .= ",drive=drive-$drive_id,id=$drive_id";
1533 if ($devicetype eq 'hd') {
1534 if (my $model = $drive->{model
}) {
1535 $model = URI
::Escape
::uri_unescape
($model);
1536 $device .= ",model=$model";
1538 if ($drive->{ssd
}) {
1539 $device .= ",rotation_rate=1";
1542 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1543 } elsif ($drive->{interface
} eq 'usb') {
1545 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1547 die "unsupported interface type";
1550 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1552 if (my $serial = $drive->{serial
}) {
1553 $serial = URI
::Escape
::uri_unescape
($serial);
1554 $device .= ",serial=$serial";
1561 sub get_initiator_name
{
1564 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return;
1565 while (defined(my $line = <$fh>)) {
1566 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1575 my sub storage_allows_io_uring_default
{
1576 my ($scfg, $cache_direct) = @_;
1578 # io_uring with cache mode writeback or writethrough on krbd will hang...
1579 return if $scfg && $scfg->{type
} eq 'rbd' && $scfg->{krbd
} && !$cache_direct;
1581 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1582 # sometimes, just plain disable...
1583 return if $scfg && $scfg->{type
} eq 'lvm';
1585 # io_uring causes problems when used with CIFS since kernel 5.15
1586 # Some discussion: https://www.spinics.net/lists/linux-cifs/msg26734.html
1587 return if $scfg && $scfg->{type
} eq 'cifs';
1592 my sub drive_uses_cache_direct
{
1593 my ($drive, $scfg) = @_;
1595 my $cache_direct = 0;
1597 if (my $cache = $drive->{cache
}) {
1598 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1599 } elsif (!drive_is_cdrom
($drive) && !($scfg && $scfg->{type
} eq 'btrfs' && !$scfg->{nocow
})) {
1603 return $cache_direct;
1606 sub print_drive_commandline_full
{
1607 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1610 my $volid = $drive->{file
};
1611 my $format = $drive->{format
};
1612 my $drive_id = get_drive_id
($drive);
1614 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1615 my $scfg = $storeid ? PVE
::Storage
::storage_config
($storecfg, $storeid) : undef;
1617 if (drive_is_cdrom
($drive)) {
1618 $path = get_iso_path
($storecfg, $vmid, $volid);
1619 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
1622 $path = PVE
::Storage
::path
($storecfg, $volid);
1623 $format //= qemu_img_format
($scfg, $volname);
1630 my $is_rbd = $path =~ m/^rbd:/;
1633 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1634 foreach my $o (@qemu_drive_options) {
1635 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1638 # snapshot only accepts on|off
1639 if (defined($drive->{snapshot
})) {
1640 my $v = $drive->{snapshot
} ?
'on' : 'off';
1641 $opts .= ",snapshot=$v";
1644 if (defined($drive->{ro
})) { # ro maps to QEMUs `readonly`, which accepts `on` or `off` only
1645 $opts .= ",readonly=" . ($drive->{ro
} ?
'on' : 'off');
1648 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1649 my ($dir, $qmpname) = @$type;
1650 if (my $v = $drive->{"mbps$dir"}) {
1651 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1653 if (my $v = $drive->{"mbps${dir}_max"}) {
1654 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1656 if (my $v = $drive->{"bps${dir}_max_length"}) {
1657 $opts .= ",throttling.bps$qmpname-max-length=$v";
1659 if (my $v = $drive->{"iops${dir}"}) {
1660 $opts .= ",throttling.iops$qmpname=$v";
1662 if (my $v = $drive->{"iops${dir}_max"}) {
1663 $opts .= ",throttling.iops$qmpname-max=$v";
1665 if (my $v = $drive->{"iops${dir}_max_length"}) {
1666 $opts .= ",throttling.iops$qmpname-max-length=$v";
1671 $format = "rbd" if $is_rbd;
1672 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1674 $opts .= ",format=alloc-track,file.driver=$format";
1676 $opts .= ",format=$format";
1679 my $cache_direct = drive_uses_cache_direct
($drive, $scfg);
1681 $opts .= ",cache=none" if !$drive->{cache
} && $cache_direct;
1683 if (!$drive->{aio
}) {
1684 if ($io_uring && storage_allows_io_uring_default
($scfg, $cache_direct)) {
1685 # io_uring supports all cache modes
1686 $opts .= ",aio=io_uring";
1688 # aio native works only with O_DIRECT
1690 $opts .= ",aio=native";
1692 $opts .= ",aio=threads";
1697 if (!drive_is_cdrom
($drive)) {
1699 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1700 $detectzeroes = 'off';
1701 } elsif ($drive->{discard
}) {
1702 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1704 # This used to be our default with discard not being specified:
1705 $detectzeroes = 'on';
1708 # note: 'detect-zeroes' works per blockdev and we want it to persist
1709 # after the alloc-track is removed, so put it on 'file' directly
1710 my $dz_param = $pbs_name ?
"file.detect-zeroes" : "detect-zeroes";
1711 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
1715 $opts .= ",backing=$pbs_name";
1716 $opts .= ",auto-remove=on";
1719 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1720 my $file_param = "file";
1722 # non-rbd drivers require the underlying file to be a seperate block
1723 # node, so add a second .file indirection
1724 $file_param .= ".file" if !$is_rbd;
1725 $file_param .= ".filename";
1727 my $pathinfo = $path ?
"$file_param=$path," : '';
1729 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1732 sub print_pbs_blockdev
{
1733 my ($pbs_conf, $pbs_name) = @_;
1734 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1735 $blockdev .= ",repository=$pbs_conf->{repository}";
1736 $blockdev .= ",namespace=$pbs_conf->{namespace}" if $pbs_conf->{namespace
};
1737 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1738 $blockdev .= ",archive=$pbs_conf->{archive}";
1739 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile
};
1743 sub print_netdevice_full
{
1744 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type, $machine_version) = @_;
1746 my $device = $net->{model
};
1747 if ($net->{model
} eq 'virtio') {
1748 $device = 'virtio-net-pci';
1751 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1752 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1753 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1754 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1755 # and out of each queue plus one config interrupt and control vector queue
1756 my $vectors = $net->{queues
} * 2 + 2;
1757 $tmpstr .= ",vectors=$vectors,mq=on";
1758 if (min_version
($machine_version, 7, 1)) {
1759 $tmpstr .= ",packed=on";
1763 if (min_version
($machine_version, 7, 1) && $net->{model
} eq 'virtio'){
1764 $tmpstr .= ",rx_queue_size=1024,tx_queue_size=1024";
1767 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1769 if (my $mtu = $net->{mtu
}) {
1770 if ($net->{model
} eq 'virtio' && $net->{bridge
}) {
1771 my $bridge_mtu = PVE
::Network
::read_bridge_mtu
($net->{bridge
});
1774 } elsif ($mtu < 576) {
1775 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1776 } elsif ($mtu > $bridge_mtu) {
1777 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1779 $tmpstr .= ",host_mtu=$mtu";
1781 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
1785 if ($use_old_bios_files) {
1787 if ($device eq 'virtio-net-pci') {
1788 $romfile = 'pxe-virtio.rom';
1789 } elsif ($device eq 'e1000') {
1790 $romfile = 'pxe-e1000.rom';
1791 } elsif ($device eq 'e1000e') {
1792 $romfile = 'pxe-e1000e.rom';
1793 } elsif ($device eq 'ne2k') {
1794 $romfile = 'pxe-ne2k_pci.rom';
1795 } elsif ($device eq 'pcnet') {
1796 $romfile = 'pxe-pcnet.rom';
1797 } elsif ($device eq 'rtl8139') {
1798 $romfile = 'pxe-rtl8139.rom';
1800 $tmpstr .= ",romfile=$romfile" if $romfile;
1806 sub print_netdev_full
{
1807 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1810 if ($netid =~ m/^net(\d+)$/) {
1814 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1816 my $ifname = "tap${vmid}i$i";
1818 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1819 die "interface name '$ifname' is too long (max 15 character)\n"
1820 if length($ifname) >= 16;
1822 my $vhostparam = '';
1823 if (is_native
($arch)) {
1824 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1827 my $vmname = $conf->{name
} || "vm$vmid";
1830 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1832 if ($net->{bridge
}) {
1833 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1834 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1836 $netdev = "type=user,id=$netid,hostname=$vmname";
1839 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1845 'cirrus' => 'cirrus-vga',
1847 'vmware' => 'vmware-svga',
1848 'virtio' => 'virtio-vga',
1849 'virtio-gl' => 'virtio-vga-gl',
1852 sub print_vga_device
{
1853 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1855 my $type = $vga_map->{$vga->{type
}};
1856 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1857 $type = 'virtio-gpu';
1859 my $vgamem_mb = $vga->{memory
};
1861 my $max_outputs = '';
1863 $type = $id ?
'qxl' : 'qxl-vga';
1865 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1866 # set max outputs so linux can have up to 4 qxl displays with one device
1867 if (min_version
($machine_version, 4, 1)) {
1868 $max_outputs = ",max_outputs=4";
1873 die "no devicetype for $vga->{type}\n" if !$type;
1877 if ($vga->{type
} =~ /^virtio/) {
1878 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1879 $memory = ",max_hostmem=$bytes";
1881 # from https://www.spice-space.org/multiple-monitors.html
1882 $memory = ",vgamem_mb=$vga->{memory}";
1883 my $ram = $vgamem_mb * 4;
1884 my $vram = $vgamem_mb * 2;
1885 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1887 $memory = ",vgamem_mb=$vga->{memory}";
1889 } elsif ($qxlnum && $id) {
1890 $memory = ",ram_size=67108864,vram_size=33554432";
1894 if ($type eq 'VGA' && windows_version
($conf->{ostype
})) {
1895 $edidoff=",edid=off" if (!defined($conf->{bios
}) || $conf->{bios
} ne 'ovmf');
1898 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1899 my $vgaid = "vga" . ($id // '');
1901 if ($q35 && $vgaid eq 'vga') {
1902 # the first display uses pcie.0 bus on q35 machines
1903 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1905 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1908 if ($vga->{type
} eq 'virtio-gl') {
1909 my $base = '/usr/lib/x86_64-linux-gnu/lib';
1910 die "missing libraries for '$vga->{type}' detected! Please install 'libgl1' and 'libegl1'\n"
1911 if !-e
"${base}EGL.so.1" || !-e
"${base}GL.so.1";
1913 die "no DRM render node detected (/dev/dri/renderD*), no GPU? - needed for '$vga->{type}' display\n"
1914 if !PVE
::Tools
::dir_glob_regex
('/dev/dri/', "renderD.*");
1917 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
1920 sub parse_number_sets
{
1923 foreach my $part (split(/;/, $set)) {
1924 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1925 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1926 push @$res, [ $1, $2 ];
1928 die "invalid range: $part\n";
1937 my $res = parse_property_string
($numa_fmt, $data);
1938 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1939 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1943 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1945 my ($data, $disable_mac_autogen) = @_;
1947 my $res = eval { parse_property_string
($net_fmt, $data) };
1952 if (!defined($res->{macaddr
}) && !$disable_mac_autogen) {
1953 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1954 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1959 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1960 sub parse_ipconfig
{
1963 my $res = eval { parse_property_string
($ipconfig_fmt, $data) };
1969 if ($res->{gw
} && !$res->{ip
}) {
1970 warn 'gateway specified without specifying an IP address';
1973 if ($res->{gw6
} && !$res->{ip6
}) {
1974 warn 'IPv6 gateway specified without specifying an IPv6 address';
1977 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1978 warn 'gateway specified together with DHCP';
1981 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1983 warn "IPv6 gateway specified together with $res->{ip6} address";
1987 if (!$res->{ip
} && !$res->{ip6
}) {
1988 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1997 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2000 sub add_random_macs
{
2001 my ($settings) = @_;
2003 foreach my $opt (keys %$settings) {
2004 next if $opt !~ m/^net(\d+)$/;
2005 my $net = parse_net
($settings->{$opt});
2007 $settings->{$opt} = print_net
($net);
2011 sub vm_is_volid_owner
{
2012 my ($storecfg, $vmid, $volid) = @_;
2014 if ($volid !~ m
|^/|) {
2016 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2017 if ($owner && ($owner == $vmid)) {
2025 sub vmconfig_register_unused_drive
{
2026 my ($storecfg, $vmid, $conf, $drive) = @_;
2028 if (drive_is_cloudinit
($drive)) {
2029 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2031 delete $conf->{cloudinit
};
2032 } elsif (!drive_is_cdrom
($drive)) {
2033 my $volid = $drive->{file
};
2034 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2035 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2040 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
2044 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2045 format_description
=> 'UUID',
2046 description
=> "Set SMBIOS1 UUID.",
2051 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2052 format_description
=> 'Base64 encoded string',
2053 description
=> "Set SMBIOS1 version.",
2058 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2059 format_description
=> 'Base64 encoded string',
2060 description
=> "Set SMBIOS1 serial number.",
2065 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2066 format_description
=> 'Base64 encoded string',
2067 description
=> "Set SMBIOS1 manufacturer.",
2072 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2073 format_description
=> 'Base64 encoded string',
2074 description
=> "Set SMBIOS1 product ID.",
2079 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2080 format_description
=> 'Base64 encoded string',
2081 description
=> "Set SMBIOS1 SKU string.",
2086 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2087 format_description
=> 'Base64 encoded string',
2088 description
=> "Set SMBIOS1 family string.",
2093 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
2101 my $res = eval { parse_property_string
($smbios1_fmt, $data) };
2108 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2111 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2113 sub parse_watchdog
{
2118 my $res = eval { parse_property_string
($watchdog_fmt, $value) };
2123 sub parse_guest_agent
{
2126 return {} if !defined($conf->{agent
});
2128 my $res = eval { parse_property_string
($agent_fmt, $conf->{agent
}) };
2131 # if the agent is disabled ignore the other potentially set properties
2132 return {} if !$res->{enabled
};
2137 my ($conf, $key) = @_;
2138 return undef if !defined($conf->{agent
});
2140 my $agent = parse_guest_agent
($conf);
2141 return $agent->{$key};
2147 return {} if !$value;
2148 my $res = eval { parse_property_string
($vga_fmt, $value) };
2158 my $res = eval { parse_property_string
($rng_fmt, $value) };
2163 sub parse_meta_info
{
2168 my $res = eval { parse_property_string
($meta_info_fmt, $value) };
2173 sub new_meta_info_string
{
2174 my () = @_; # for now do not allow to override any value
2176 return PVE
::JSONSchema
::print_property_string
(
2178 'creation-qemu' => kvm_user_version
(),
2179 ctime
=> "". int(time()),
2185 sub qemu_created_version_fixups
{
2186 my ($conf, $forcemachine, $kvmver) = @_;
2188 my $meta = parse_meta_info
($conf->{meta
}) // {};
2189 my $forced_vers = PVE
::QemuServer
::Machine
::extract_version
($forcemachine);
2191 # check if we need to apply some handling for VMs that always use the latest machine version but
2192 # had a machine version transition happen that affected HW such that, e.g., an OS config change
2193 # would be required (we do not want to pin machine version for non-windows OS type)
2195 (!defined($conf->{machine
}) || $conf->{machine
} =~ m/^(?:pc|q35|virt)$/) # non-versioned machine
2196 && (!defined($meta->{'creation-qemu'}) || !min_version
($meta->{'creation-qemu'}, 6, 1)) # created before 6.1
2197 && (!$forced_vers || min_version
($forced_vers, 6, 1)) # handle snapshot-rollback/migrations
2198 && min_version
($kvmver, 6, 1) # only need to apply the change since 6.1
2200 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
2201 if ($q35 && $conf->{ostype
} && $conf->{ostype
} eq 'l26') {
2202 # this changed to default-on in Q 6.1 for q35 machines, it will mess with PCI slot view
2203 # and thus with the predictable interface naming of systemd
2204 return ['-global', 'ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off'];
2210 # add JSON properties for create and set function
2211 sub json_config_properties
{
2212 my ($prop, $with_disk_alloc) = @_;
2214 my $skip_json_config_opts = {
2218 runningmachine
=> 1,
2223 foreach my $opt (keys %$confdesc) {
2224 next if $skip_json_config_opts->{$opt};
2226 if ($with_disk_alloc && is_valid_drivename
($opt)) {
2227 $prop->{$opt} = $PVE::QemuServer
::Drive
::drivedesc_hash_with_alloc-
>{$opt};
2229 $prop->{$opt} = $confdesc->{$opt};
2236 # Properties that we can read from an OVF file
2237 sub json_ovf_properties
{
2240 for my $device (PVE
::QemuServer
::Drive
::valid_drive_names
()) {
2241 $prop->{$device} = {
2243 format
=> 'pve-volume-id-or-absolute-path',
2244 description
=> "Disk image that gets imported to $device",
2251 description
=> "The number of CPU cores.",
2256 description
=> "Amount of RAM for the VM in MB.",
2261 description
=> "Name of the VM.",
2268 # return copy of $confdesc_cloudinit to generate documentation
2269 sub cloudinit_config_properties
{
2271 return dclone
($confdesc_cloudinit);
2274 sub cloudinit_pending_properties
{
2276 map { $_ => 1 } keys $confdesc_cloudinit->%*,
2279 $p->{"net$_"} = 1 for 0..($MAX_NETS-1);
2284 my ($key, $value) = @_;
2286 die "unknown setting '$key'\n" if !$confdesc->{$key};
2288 my $type = $confdesc->{$key}->{type
};
2290 if (!defined($value)) {
2291 die "got undefined value\n";
2294 if ($value =~ m/[\n\r]/) {
2295 die "property contains a line feed\n";
2298 if ($type eq 'boolean') {
2299 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2300 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2301 die "type check ('boolean') failed - got '$value'\n";
2302 } elsif ($type eq 'integer') {
2303 return int($1) if $value =~ m/^(\d+)$/;
2304 die "type check ('integer') failed - got '$value'\n";
2305 } elsif ($type eq 'number') {
2306 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2307 die "type check ('number') failed - got '$value'\n";
2308 } elsif ($type eq 'string') {
2309 if (my $fmt = $confdesc->{$key}->{format
}) {
2310 PVE
::JSONSchema
::check_format
($fmt, $value);
2313 $value =~ s/^\"(.*)\"$/$1/;
2316 die "internal error"
2321 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
2323 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2325 if (!$skiplock && !PVE
::QemuConfig-
>has_lock($conf, 'suspended')) {
2326 PVE
::QemuConfig-
>check_lock($conf);
2329 if ($conf->{template
}) {
2330 # check if any base image is still used by a linked clone
2331 PVE
::QemuConfig-
>foreach_volume_full($conf, { include_unused
=> 1 }, sub {
2332 my ($ds, $drive) = @_;
2333 return if drive_is_cdrom
($drive);
2335 my $volid = $drive->{file
};
2336 return if !$volid || $volid =~ m
|^/|;
2338 die "base volume '$volid' is still in use by linked cloned\n"
2339 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2345 my $remove_owned_drive = sub {
2346 my ($ds, $drive) = @_;
2347 return if drive_is_cdrom
($drive, 1);
2349 my $volid = $drive->{file
};
2350 return if !$volid || $volid =~ m
|^/|;
2351 return if $volids->{$volid};
2353 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2354 return if !$path || !$owner || ($owner != $vmid);
2356 $volids->{$volid} = 1;
2357 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2358 warn "Could not remove disk '$volid', check manually: $@" if $@;
2361 # only remove disks owned by this VM (referenced in the config)
2362 my $include_opts = {
2363 include_unused
=> 1,
2364 extra_keys
=> ['vmstate'],
2366 PVE
::QemuConfig-
>foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2368 for my $snap (values %{$conf->{snapshots
}}) {
2369 next if !defined($snap->{vmstate
});
2370 my $drive = PVE
::QemuConfig-
>parse_volume('vmstate', $snap->{vmstate
}, 1);
2371 next if !defined($drive);
2372 $remove_owned_drive->('vmstate', $drive);
2375 PVE
::QemuConfig-
>foreach_volume_full($conf->{pending
}, $include_opts, $remove_owned_drive);
2377 if ($purge_unreferenced) { # also remove unreferenced disk
2378 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid, undef, 'images');
2379 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2380 my ($volid, $sid, $volname, $d) = @_;
2381 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2386 if (defined $replacement_conf) {
2387 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2389 PVE
::QemuConfig-
>destroy_config($vmid);
2393 sub parse_vm_config
{
2394 my ($filename, $raw, $strict) = @_;
2396 return if !defined($raw);
2399 digest
=> Digest
::SHA
::sha1_hex
($raw),
2405 my $handle_error = sub {
2415 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2416 || die "got strange filename '$filename'";
2422 my $finish_description = sub {
2423 if (defined($descr)) {
2425 $conf->{description
} = $descr;
2431 my @lines = split(/\n/, $raw);
2432 foreach my $line (@lines) {
2433 next if $line =~ m/^\s*$/;
2435 if ($line =~ m/^\[PENDING\]\s*$/i) {
2436 $section = 'pending';
2437 $finish_description->();
2438 $conf = $res->{$section} = {};
2440 } elsif ($line =~ m/^\[special:cloudinit\]\s*$/i) {
2441 $section = 'cloudinit';
2442 $finish_description->();
2443 $conf = $res->{$section} = {};
2446 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2448 $finish_description->();
2449 $conf = $res->{snapshots
}->{$section} = {};
2453 if ($line =~ m/^\#(.*)$/) {
2454 $descr = '' if !defined($descr);
2455 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2459 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2460 $descr = '' if !defined($descr);
2461 $descr .= PVE
::Tools
::decode_text
($2);
2462 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2463 $conf->{snapstate
} = $1;
2464 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2467 $conf->{$key} = $value;
2468 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2470 if ($section eq 'pending') {
2471 $conf->{delete} = $value; # we parse this later
2473 $handle_error->("vm $vmid - property 'delete' is only allowed in [PENDING]\n");
2475 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2478 if ($section eq 'cloudinit') {
2479 # ignore validation only used for informative purpose
2480 $conf->{$key} = $value;
2483 eval { $value = check_type
($key, $value); };
2485 $handle_error->("vm $vmid - unable to parse value of '$key' - $@");
2487 $key = 'ide2' if $key eq 'cdrom';
2488 my $fmt = $confdesc->{$key}->{format
};
2489 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2490 my $v = parse_drive
($key, $value);
2491 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2492 $v->{file
} = $volid;
2493 $value = print_drive
($v);
2495 $handle_error->("vm $vmid - unable to parse value of '$key'\n");
2500 $conf->{$key} = $value;
2503 $handle_error->("vm $vmid - unable to parse config: $line\n");
2507 $finish_description->();
2508 delete $res->{snapstate
}; # just to be sure
2513 sub write_vm_config
{
2514 my ($filename, $conf) = @_;
2516 delete $conf->{snapstate
}; # just to be sure
2518 if ($conf->{cdrom
}) {
2519 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2520 $conf->{ide2
} = $conf->{cdrom
};
2521 delete $conf->{cdrom
};
2524 # we do not use 'smp' any longer
2525 if ($conf->{sockets
}) {
2526 delete $conf->{smp
};
2527 } elsif ($conf->{smp
}) {
2528 $conf->{sockets
} = $conf->{smp
};
2529 delete $conf->{cores
};
2530 delete $conf->{smp
};
2533 my $used_volids = {};
2535 my $cleanup_config = sub {
2536 my ($cref, $pending, $snapname) = @_;
2538 foreach my $key (keys %$cref) {
2539 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2540 $key eq 'snapstate' || $key eq 'pending' || $key eq 'cloudinit';
2541 my $value = $cref->{$key};
2542 if ($key eq 'delete') {
2543 die "propertry 'delete' is only allowed in [PENDING]\n"
2545 # fixme: check syntax?
2548 eval { $value = check_type
($key, $value); };
2549 die "unable to parse value of '$key' - $@" if $@;
2551 $cref->{$key} = $value;
2553 if (!$snapname && is_valid_drivename
($key)) {
2554 my $drive = parse_drive
($key, $value);
2555 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2560 &$cleanup_config($conf);
2562 &$cleanup_config($conf->{pending
}, 1);
2564 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2565 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2566 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2569 # remove 'unusedX' settings if we re-add a volume
2570 foreach my $key (keys %$conf) {
2571 my $value = $conf->{$key};
2572 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2573 delete $conf->{$key};
2577 my $generate_raw_config = sub {
2578 my ($conf, $pending) = @_;
2582 # add description as comment to top of file
2583 if (defined(my $descr = $conf->{description
})) {
2585 foreach my $cl (split(/\n/, $descr)) {
2586 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2589 $raw .= "#\n" if $pending;
2593 foreach my $key (sort keys %$conf) {
2594 next if $key =~ /^(digest|description|pending|cloudinit|snapshots)$/;
2595 $raw .= "$key: $conf->{$key}\n";
2600 my $raw = &$generate_raw_config($conf);
2602 if (scalar(keys %{$conf->{pending
}})){
2603 $raw .= "\n[PENDING]\n";
2604 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2607 if (scalar(keys %{$conf->{cloudinit
}}) && PVE
::QemuConfig-
>has_cloudinit($conf)){
2608 $raw .= "\n[special:cloudinit]\n";
2609 $raw .= &$generate_raw_config($conf->{cloudinit
});
2612 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2613 $raw .= "\n[$snapname]\n";
2614 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2624 # we use static defaults from our JSON schema configuration
2625 foreach my $key (keys %$confdesc) {
2626 if (defined(my $default = $confdesc->{$key}->{default})) {
2627 $res->{$key} = $default;
2635 my $vmlist = PVE
::Cluster
::get_vmlist
();
2637 return $res if !$vmlist || !$vmlist->{ids
};
2638 my $ids = $vmlist->{ids
};
2639 my $nodename = nodename
();
2641 foreach my $vmid (keys %$ids) {
2642 my $d = $ids->{$vmid};
2643 next if !$d->{node
} || $d->{node
} ne $nodename;
2644 next if !$d->{type
} || $d->{type
} ne 'qemu';
2645 $res->{$vmid}->{exists} = 1;
2650 # test if VM uses local resources (to prevent migration)
2651 sub check_local_resources
{
2652 my ($conf, $noerr) = @_;
2655 my $mapped_res = [];
2657 my $nodelist = PVE
::Cluster
::get_nodelist
();
2658 my $pci_map = PVE
::Mapping
::PCI
::config
();
2659 my $usb_map = PVE
::Mapping
::USB
::config
();
2661 my $missing_mappings_by_node = { map { $_ => [] } @$nodelist };
2663 my $add_missing_mapping = sub {
2664 my ($type, $key, $id) = @_;
2665 for my $node (@$nodelist) {
2667 if ($type eq 'pci') {
2668 $entry = PVE
::Mapping
::PCI
::get_node_mapping
($pci_map, $id, $node);
2669 } elsif ($type eq 'usb') {
2670 $entry = PVE
::Mapping
::USB
::get_node_mapping
($usb_map, $id, $node);
2672 if (!scalar($entry->@*)) {
2673 push @{$missing_mappings_by_node->{$node}}, $key;
2678 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2679 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2681 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2683 foreach my $k (keys %$conf) {
2684 if ($k =~ m/^usb/) {
2685 my $entry = parse_property_string
('pve-qm-usb', $conf->{$k});
2686 next if $entry->{host
} =~ m/^spice$/i;
2687 if ($entry->{mapping
}) {
2688 $add_missing_mapping->('usb', $k, $entry->{mapping
});
2689 push @$mapped_res, $k;
2692 if ($k =~ m/^hostpci/) {
2693 my $entry = parse_property_string
('pve-qm-hostpci', $conf->{$k});
2694 if ($entry->{mapping
}) {
2695 $add_missing_mapping->('pci', $k, $entry->{mapping
});
2696 push @$mapped_res, $k;
2699 # sockets are safe: they will recreated be on the target side post-migrate
2700 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2701 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2704 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2706 return wantarray ?
(\
@loc_res, $mapped_res, $missing_mappings_by_node) : \
@loc_res;
2709 # check if used storages are available on all nodes (use by migrate)
2710 sub check_storage_availability
{
2711 my ($storecfg, $conf, $node) = @_;
2713 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2714 my ($ds, $drive) = @_;
2716 my $volid = $drive->{file
};
2719 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2722 # check if storage is available on both nodes
2723 my $scfg = PVE
::Storage
::storage_check_enabled
($storecfg, $sid);
2724 PVE
::Storage
::storage_check_enabled
($storecfg, $sid, $node);
2726 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $volid);
2728 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2729 if !$scfg->{content
}->{$vtype};
2733 # list nodes where all VM images are available (used by has_feature API)
2735 my ($conf, $storecfg) = @_;
2737 my $nodelist = PVE
::Cluster
::get_nodelist
();
2738 my $nodehash = { map { $_ => 1 } @$nodelist };
2739 my $nodename = nodename
();
2741 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2742 my ($ds, $drive) = @_;
2744 my $volid = $drive->{file
};
2747 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2749 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2750 if ($scfg->{disable
}) {
2752 } elsif (my $avail = $scfg->{nodes
}) {
2753 foreach my $node (keys %$nodehash) {
2754 delete $nodehash->{$node} if !$avail->{$node};
2756 } elsif (!$scfg->{shared
}) {
2757 foreach my $node (keys %$nodehash) {
2758 delete $nodehash->{$node} if $node ne $nodename
2767 sub check_local_storage_availability
{
2768 my ($conf, $storecfg) = @_;
2770 my $nodelist = PVE
::Cluster
::get_nodelist
();
2771 my $nodehash = { map { $_ => {} } @$nodelist };
2773 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2774 my ($ds, $drive) = @_;
2776 my $volid = $drive->{file
};
2779 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2781 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2783 if ($scfg->{disable
}) {
2784 foreach my $node (keys %$nodehash) {
2785 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2787 } elsif (my $avail = $scfg->{nodes
}) {
2788 foreach my $node (keys %$nodehash) {
2789 if (!$avail->{$node}) {
2790 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2797 foreach my $node (values %$nodehash) {
2798 if (my $unavail = $node->{unavailable_storages
}) {
2799 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2806 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2808 my ($vmid, $nocheck, $node) = @_;
2810 # $nocheck is set when called during a migration, in which case the config
2811 # file might still or already reside on the *other* node
2812 # - because rename has already happened, and current node is source
2813 # - because rename hasn't happened yet, and current node is target
2814 # - because rename has happened, current node is target, but hasn't yet
2816 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2817 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2822 my $vzlist = config_list
();
2824 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2826 while (defined(my $de = $fd->read)) {
2827 next if $de !~ m/^(\d+)\.pid$/;
2829 next if !defined($vzlist->{$vmid});
2830 if (my $pid = check_running
($vmid)) {
2831 $vzlist->{$vmid}->{pid
} = $pid;
2838 our $vmstatus_return_properties = {
2839 vmid
=> get_standard_option
('pve-vmid'),
2841 description
=> "QEMU process status.",
2843 enum
=> ['stopped', 'running'],
2846 description
=> "Maximum memory in bytes.",
2849 renderer
=> 'bytes',
2852 description
=> "Root disk size in bytes.",
2855 renderer
=> 'bytes',
2858 description
=> "VM name.",
2863 description
=> "VM run state from the 'query-status' QMP monitor command.",
2868 description
=> "PID of running qemu process.",
2873 description
=> "Uptime.",
2876 renderer
=> 'duration',
2879 description
=> "Maximum usable CPUs.",
2884 description
=> "The current config lock, if any.",
2889 description
=> "The current configured tags, if any",
2893 'running-machine' => {
2894 description
=> "The currently running machine type (if running).",
2899 description
=> "The currently running QEMU version (if running).",
2905 my $last_proc_pid_stat;
2907 # get VM status information
2908 # This must be fast and should not block ($full == false)
2909 # We only query KVM using QMP if $full == true (this can be slow)
2911 my ($opt_vmid, $full) = @_;
2915 my $storecfg = PVE
::Storage
::config
();
2917 my $list = vzlist
();
2918 my $defaults = load_defaults
();
2920 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2922 my $cpucount = $cpuinfo->{cpus
} || 1;
2924 foreach my $vmid (keys %$list) {
2925 next if $opt_vmid && ($vmid ne $opt_vmid);
2927 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2929 my $d = { vmid
=> int($vmid) };
2930 $d->{pid
} = int($list->{$vmid}->{pid
}) if $list->{$vmid}->{pid
};
2932 # fixme: better status?
2933 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2935 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2936 if (defined($size)) {
2937 $d->{disk
} = 0; # no info available
2938 $d->{maxdisk
} = $size;
2944 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2945 * ($conf->{cores
} || $defaults->{cores
});
2946 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2947 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2949 $d->{name
} = $conf->{name
} || "VM $vmid";
2950 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2951 : $defaults->{memory
}*(1024*1024);
2953 if ($conf->{balloon
}) {
2954 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2955 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2956 : $defaults->{shares
};
2967 $d->{diskwrite
} = 0;
2969 $d->{template
} = 1 if PVE
::QemuConfig-
>is_template($conf);
2971 $d->{serial
} = 1 if conf_has_serial
($conf);
2972 $d->{lock} = $conf->{lock} if $conf->{lock};
2973 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2978 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2979 foreach my $dev (keys %$netdev) {
2980 next if $dev !~ m/^tap([1-9]\d*)i/;
2982 my $d = $res->{$vmid};
2985 $d->{netout
} += $netdev->{$dev}->{receive
};
2986 $d->{netin
} += $netdev->{$dev}->{transmit
};
2989 $d->{nics
}->{$dev}->{netout
} = int($netdev->{$dev}->{receive
});
2990 $d->{nics
}->{$dev}->{netin
} = int($netdev->{$dev}->{transmit
});
2995 my $ctime = gettimeofday
;
2997 foreach my $vmid (keys %$list) {
2999 my $d = $res->{$vmid};
3000 my $pid = $d->{pid
};
3003 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3004 next if !$pstat; # not running
3006 my $used = $pstat->{utime} + $pstat->{stime
};
3008 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3010 if ($pstat->{vsize
}) {
3011 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3014 my $old = $last_proc_pid_stat->{$pid};
3016 $last_proc_pid_stat->{$pid} = {
3024 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3026 if ($dtime > 1000) {
3027 my $dutime = $used - $old->{used
};
3029 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3030 $last_proc_pid_stat->{$pid} = {
3036 $d->{cpu
} = $old->{cpu
};
3040 return $res if !$full;
3042 my $qmpclient = PVE
::QMPClient-
>new();
3044 my $ballooncb = sub {
3045 my ($vmid, $resp) = @_;
3047 my $info = $resp->{'return'};
3048 return if !$info->{max_mem
};
3050 my $d = $res->{$vmid};
3052 # use memory assigned to VM
3053 $d->{maxmem
} = $info->{max_mem
};
3054 $d->{balloon
} = $info->{actual
};
3056 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3057 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3058 $d->{freemem
} = $info->{free_mem
};
3061 $d->{ballooninfo
} = $info;
3064 my $blockstatscb = sub {
3065 my ($vmid, $resp) = @_;
3066 my $data = $resp->{'return'} || [];
3067 my $totalrdbytes = 0;
3068 my $totalwrbytes = 0;
3070 for my $blockstat (@$data) {
3071 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3072 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3074 $blockstat->{device
} =~ s/drive-//;
3075 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3077 $res->{$vmid}->{diskread
} = $totalrdbytes;
3078 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3081 my $machinecb = sub {
3082 my ($vmid, $resp) = @_;
3083 my $data = $resp->{'return'} || [];
3085 $res->{$vmid}->{'running-machine'} =
3086 PVE
::QemuServer
::Machine
::current_from_query_machines
($data);
3089 my $versioncb = sub {
3090 my ($vmid, $resp) = @_;
3091 my $data = $resp->{'return'} // {};
3092 my $version = 'unknown';
3094 if (my $v = $data->{qemu
}) {
3095 $version = $v->{major
} . "." . $v->{minor
} . "." . $v->{micro
};
3098 $res->{$vmid}->{'running-qemu'} = $version;
3101 my $statuscb = sub {
3102 my ($vmid, $resp) = @_;
3104 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3105 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
3106 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
3107 # this fails if ballon driver is not loaded, so this must be
3108 # the last commnand (following command are aborted if this fails).
3109 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3111 my $status = 'unknown';
3112 if (!defined($status = $resp->{'return'}->{status
})) {
3113 warn "unable to get VM status\n";
3117 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3120 foreach my $vmid (keys %$list) {
3121 next if $opt_vmid && ($vmid ne $opt_vmid);
3122 next if !$res->{$vmid}->{pid
}; # not running
3123 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3126 $qmpclient->queue_execute(undef, 2);
3128 foreach my $vmid (keys %$list) {
3129 next if $opt_vmid && ($vmid ne $opt_vmid);
3130 next if !$res->{$vmid}->{pid
}; #not running
3132 # we can't use the $qmpclient since it might have already aborted on
3133 # 'query-balloon', but this might also fail for older versions...
3134 my $qemu_support = eval { mon_cmd
($vmid, "query-proxmox-support") };
3135 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
3138 foreach my $vmid (keys %$list) {
3139 next if $opt_vmid && ($vmid ne $opt_vmid);
3140 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3146 sub conf_has_serial
{
3149 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3150 if ($conf->{"serial$i"}) {
3158 sub conf_has_audio
{
3159 my ($conf, $id) = @_;
3162 my $audio = $conf->{"audio$id"};
3163 return if !defined($audio);
3165 my $audioproperties = parse_property_string
($audio_fmt, $audio);
3166 my $audiodriver = $audioproperties->{driver
} // 'spice';
3169 dev
=> $audioproperties->{device
},
3170 dev_id
=> "audiodev$id",
3171 backend
=> $audiodriver,
3172 backend_id
=> "$audiodriver-backend${id}",
3177 my ($audio, $audiopciaddr, $machine_version) = @_;
3181 my $id = $audio->{dev_id
};
3183 if (min_version
($machine_version, 4, 2)) {
3184 $audiodev = ",audiodev=$audio->{backend_id}";
3187 if ($audio->{dev
} eq 'AC97') {
3188 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
3189 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
3190 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3191 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
3192 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
3194 die "unkown audio device '$audio->{dev}', implement me!";
3197 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3205 socket => "/var/run/qemu-server/$vmid.swtpm",
3206 pid
=> "/var/run/qemu-server/$vmid.swtpm.pid",
3210 sub add_tpm_device
{
3211 my ($vmid, $devices, $conf) = @_;
3213 return if !$conf->{tpmstate0
};
3215 my $paths = get_tpm_paths
($vmid);
3217 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
3218 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
3219 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
3223 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
3225 return if !$tpmdrive;
3228 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
3229 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
3231 $state = PVE
::Storage
::map_volume
($storecfg, $tpm->{file
});
3233 $state = $tpm->{file
};
3236 my $paths = get_tpm_paths
($vmid);
3238 # during migration, we will get state from remote
3241 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3248 "--create-platform-cert",
3251 "/etc/swtpm_setup.conf", # do not use XDG configs
3253 "0", # force creation as root, error if not possible
3254 "--not-overwrite", # ignore existing state, do not modify
3257 push @$setup_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3258 # TPM 2.0 supports ECC crypto, use if possible
3259 push @$setup_cmd, "--ecc" if $tpm->{version
} eq 'v2.0';
3261 run_command
($setup_cmd, outfunc
=> sub {
3262 print "swtpm_setup: $1\n";
3266 # Used to distinguish different invocations in the log.
3267 my $log_prefix = "[id=" . int(time()) . "] ";
3269 my $emulator_cmd = [
3273 "backend-uri=file://$state,mode=0600",
3275 "type=unixio,path=$paths->{socket},mode=0600",
3277 "file=$paths->{pid}",
3278 "--terminate", # terminate on QEMU disconnect
3281 "file=/run/qemu-server/$vmid-swtpm.log,level=1,prefix=$log_prefix",
3283 push @$emulator_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3284 run_command
($emulator_cmd, outfunc
=> sub { print $1; });
3286 my $tries = 100; # swtpm may take a bit to start before daemonizing, wait up to 5s for pid
3287 while (! -e
$paths->{pid
}) {
3288 die "failed to start swtpm: pid file '$paths->{pid}' wasn't created.\n" if --$tries == 0;
3292 # return untainted PID of swtpm daemon so it can be killed on error
3293 file_read_firstline
($paths->{pid
}) =~ m/(\d+)/;
3297 sub vga_conf_has_spice
{
3300 my $vgaconf = parse_vga
($vga);
3301 my $vgatype = $vgaconf->{type
};
3302 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3309 return get_host_arch
() eq $arch;
3314 return $conf->{arch
} // get_host_arch
();
3317 my $default_machines = {
3322 sub get_installed_machine_version
{
3323 my ($kvmversion) = @_;
3324 $kvmversion = kvm_user_version
() if !defined($kvmversion);
3325 $kvmversion =~ m/^(\d+\.\d+)/;
3329 sub windows_get_pinned_machine_version
{
3330 my ($machine, $base_version, $kvmversion) = @_;
3332 my $pin_version = $base_version;
3333 if (!defined($base_version) ||
3334 !PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($base_version, $kvmversion)
3336 $pin_version = get_installed_machine_version
($kvmversion);
3338 if (!$machine || $machine eq 'pc') {
3339 $machine = "pc-i440fx-$pin_version";
3340 } elsif ($machine eq 'q35') {
3341 $machine = "pc-q35-$pin_version";
3342 } elsif ($machine eq 'virt') {
3343 $machine = "virt-$pin_version";
3345 warn "unknown machine type '$machine', not touching that!\n";
3351 sub get_vm_machine
{
3352 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
3354 my $machine = $forcemachine || $conf->{machine
};
3356 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
3357 $kvmversion //= kvm_user_version
();
3358 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3359 # layout which confuses windows quite a bit and may result in various regressions..
3360 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3361 if (windows_version
($conf->{ostype
})) {
3362 $machine = windows_get_pinned_machine_version
($machine, '5.1', $kvmversion);
3365 $machine ||= $default_machines->{$arch};
3366 if ($add_pve_version) {
3367 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
3368 $machine .= "+pve$pvever";
3372 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3373 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3374 $machine = $1 if $is_pxe;
3376 # for version-pinned machines that do not include a pve-version (e.g.
3377 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3378 $machine .= '+pve0';
3380 $machine .= '.pxe' if $is_pxe;
3386 sub get_ovmf_files
($$$) {
3387 my ($arch, $efidisk, $smm) = @_;
3389 my $types = $OVMF->{$arch}
3390 or die "no OVMF images known for architecture '$arch'\n";
3392 my $type = 'default';
3393 if ($arch ne "aarch64" && defined($efidisk->{efitype
}) && $efidisk->{efitype
} eq '4m') {
3394 $type = $smm ?
"4m" : "4m-no-smm";
3395 $type .= '-ms' if $efidisk->{'pre-enrolled-keys'};
3398 my ($ovmf_code, $ovmf_vars) = $types->{$type}->@*;
3399 die "EFI base image '$ovmf_code' not found\n" if ! -f
$ovmf_code;
3400 die "EFI vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
3402 return ($ovmf_code, $ovmf_vars);
3406 aarch64
=> '/usr/bin/qemu-system-aarch64',
3407 x86_64
=> '/usr/bin/qemu-system-x86_64',
3409 sub get_command_for_arch
($) {
3411 return '/usr/bin/kvm' if is_native
($arch);
3413 my $cmd = $Arch2Qemu->{$arch}
3414 or die "don't know how to emulate architecture '$arch'\n";
3418 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3419 # to use in a QEMU command line (-cpu element), first array_intersect the result
3420 # of query_supported_ with query_understood_. This is necessary because:
3422 # a) query_understood_ returns flags the host cannot use and
3423 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
3424 # flags, but CPU settings - with most of them being flags. Those settings
3425 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
3427 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3428 # expensive. If you need the value returned from this, you can get it much
3429 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3430 # $accel being 'kvm' or 'tcg'.
3432 # pvestatd calls this function on startup and whenever the QEMU/KVM version
3433 # changes, automatically populating pmxcfs.
3435 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3436 # since kvm and tcg machines support different flags
3438 sub query_supported_cpu_flags
{
3441 $arch //= get_host_arch
();
3442 my $default_machine = $default_machines->{$arch};
3446 # FIXME: Once this is merged, the code below should work for ARM as well:
3447 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3448 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3451 my $kvm_supported = defined(kvm_version
());
3452 my $qemu_cmd = get_command_for_arch
($arch);
3454 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
3456 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3457 my $query_supported_run_qemu = sub {
3463 '-machine', $default_machine,
3465 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
3466 '-mon', 'chardev=qmp,mode=control',
3467 '-pidfile', $pidfile,
3472 push @$cmd, '-accel', 'tcg';
3475 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
3476 die "QEMU flag querying VM exited with code " . $rc if $rc;
3479 my $cmd_result = mon_cmd
(
3481 'query-cpu-model-expansion',
3483 model
=> { name
=> 'host' }
3486 my $props = $cmd_result->{model
}->{props
};
3487 foreach my $prop (keys %$props) {
3488 next if $props->{$prop} ne '1';
3489 # QEMU returns some flags multiple times, with '_', '.' or '-'
3490 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3491 # We only keep those with underscores, to match /proc/cpuinfo
3492 $prop =~ s/\.|-/_/g;
3493 $flags->{$prop} = 1;
3498 # force stop with 10 sec timeout and 'nocheck', always stop, even if QMP failed
3499 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
3503 return [ sort keys %$flags ];
3506 # We need to query QEMU twice, since KVM and TCG have different supported flags
3507 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
3508 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
3509 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3511 if ($kvm_supported) {
3512 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
3513 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3520 # Understood CPU flags are written to a file at 'pve-qemu' compile time
3521 my $understood_cpu_flag_dir = "/usr/share/kvm";
3522 sub query_understood_cpu_flags
{
3523 my $arch = get_host_arch
();
3524 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3526 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3529 my $raw = file_get_contents
($filepath);
3530 $raw =~ s/^\s+|\s+$//g;
3531 my @flags = split(/\s+/, $raw);
3536 # Since commit 277d33454f77ec1d1e0bc04e37621e4dd2424b67 in pve-qemu, smm is not off by default
3537 # anymore. But smm=off seems to be required when using SeaBIOS and serial display.
3538 my sub should_disable_smm
{
3539 my ($conf, $vga, $machine) = @_;
3541 return if $machine =~ m/^virt/; # there is no smm flag that could be disabled
3543 return (!defined($conf->{bios
}) || $conf->{bios
} eq 'seabios') &&
3544 $vga->{type
} && $vga->{type
} =~ m/^(serial\d+|none)$/;
3547 my sub print_ovmf_drive_commandlines
{
3548 my ($conf, $storecfg, $vmid, $arch, $q35, $version_guard) = @_;
3550 my $d = $conf->{efidisk0
} ? parse_drive
('efidisk0', $conf->{efidisk0
}) : undef;
3552 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch, $d, $q35);
3554 my $var_drive_str = "if=pflash,unit=1,id=drive-efidisk0";
3556 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3557 my ($path, $format) = $d->@{'file', 'format'};
3559 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3560 if (!defined($format)) {
3561 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3562 $format = qemu_img_format
($scfg, $volname);
3564 } elsif (!defined($format)) {
3565 die "efidisk format must be specified\n";
3567 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3568 if ($path =~ m/^rbd:/) {
3569 $var_drive_str .= ',cache=writeback';
3570 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3572 $var_drive_str .= ",format=$format,file=$path";
3574 $var_drive_str .= ",size=" . (-s
$ovmf_vars) if $format eq 'raw' && $version_guard->(4, 1, 2);
3575 $var_drive_str .= ',readonly=on' if drive_is_read_only
($conf, $d);
3577 log_warn
("no efidisk configured! Using temporary efivars disk.");
3578 my $path = "/tmp/$vmid-ovmf.fd";
3579 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3580 $var_drive_str .= ",format=raw,file=$path";
3581 $var_drive_str .= ",size=" . (-s
$ovmf_vars) if $version_guard->(4, 1, 2);
3584 return ("if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code", $var_drive_str);
3587 sub config_to_command
{
3588 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3591 my ($globalFlags, $machineFlags, $rtcFlags) = ([], [], []);
3594 my $ostype = $conf->{ostype
};
3595 my $winversion = windows_version
($ostype);
3596 my $kvm = $conf->{kvm
};
3597 my $nodename = nodename
();
3599 my $arch = get_vm_arch
($conf);
3600 my $kvm_binary = get_command_for_arch
($arch);
3601 my $kvmver = kvm_user_version
($kvm_binary);
3603 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3604 $kvmver //= "undefined";
3605 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3608 my $add_pve_version = min_version
($kvmver, 4, 1);
3610 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
3611 my $machine_version = extract_version
($machine_type, $kvmver);
3612 $kvm //= 1 if is_native
($arch);
3614 $machine_version =~ m/(\d+)\.(\d+)/;
3615 my ($machine_major, $machine_minor) = ($1, $2);
3617 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3618 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3619 } elsif (!min_version
($kvmver, $machine_major, $machine_minor)) {
3620 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3621 ." please upgrade node '$nodename'\n"
3622 } elsif (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
3623 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
3624 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3625 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3626 ." node '$nodename'\n";
3629 # if a specific +pve version is required for a feature, use $version_guard
3630 # instead of min_version to allow machines to be run with the minimum
3632 my $required_pve_version = 0;
3633 my $version_guard = sub {
3634 my ($major, $minor, $pve) = @_;
3635 return 0 if !min_version
($machine_version, $major, $minor, $pve);
3636 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
3637 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
3638 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3642 if ($kvm && !defined kvm_version
()) {
3643 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3644 ." or enable in BIOS.\n";
3647 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3648 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3649 my $use_old_bios_files = undef;
3650 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3653 if ($conf->{affinity
}) {
3654 push @$cmd, '/usr/bin/taskset', '--cpu-list', '--all-tasks', $conf->{affinity
};
3657 push @$cmd, $kvm_binary;
3659 push @$cmd, '-id', $vmid;
3661 my $vmname = $conf->{name
} || "vm$vmid";
3663 push @$cmd, '-name', "$vmname,debug-threads=on";
3665 push @$cmd, '-no-shutdown';
3669 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3670 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
3671 push @$cmd, '-mon', "chardev=qmp,mode=control";
3673 if (min_version
($machine_version, 2, 12)) {
3674 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3675 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3678 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3680 push @$cmd, '-daemonize';
3682 if ($conf->{smbios1
}) {
3683 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3684 if ($smbios_conf->{base64
}) {
3685 # Do not pass base64 flag to qemu
3686 delete $smbios_conf->{base64
};
3687 my $smbios_string = "";
3688 foreach my $key (keys %$smbios_conf) {
3690 if ($key eq "uuid") {
3691 $value = $smbios_conf->{uuid
}
3693 $value = decode_base64
($smbios_conf->{$key});
3695 # qemu accepts any binary data, only commas need escaping by double comma
3697 $smbios_string .= "," . $key . "=" . $value if $value;
3699 push @$cmd, '-smbios', "type=1" . $smbios_string;
3701 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3705 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3706 my ($code_drive_str, $var_drive_str) =
3707 print_ovmf_drive_commandlines
($conf, $storecfg, $vmid, $arch, $q35, $version_guard);
3708 push $cmd->@*, '-drive', $code_drive_str;
3709 push $cmd->@*, '-drive', $var_drive_str;
3712 if ($q35) { # tell QEMU to load q35 config early
3713 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3714 if (min_version
($machine_version, 4, 0)) {
3715 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3717 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3721 if (defined(my $fixups = qemu_created_version_fixups
($conf, $forcemachine, $kvmver))) {
3722 push @$cmd, $fixups->@*;
3725 if ($conf->{vmgenid
}) {
3726 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3729 # add usb controllers
3730 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
(
3731 $conf, $bridges, $arch, $machine_type, $machine_version);
3732 push @$devices, @usbcontrollers if @usbcontrollers;
3733 my $vga = parse_vga
($conf->{vga
});
3735 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3736 $vga->{type
} = 'qxl' if $qxlnum;
3738 if (!$vga->{type
}) {
3739 if ($arch eq 'aarch64') {
3740 $vga->{type
} = 'virtio';
3741 } elsif (min_version
($machine_version, 2, 9)) {
3742 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3744 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3748 # enable absolute mouse coordinates (needed by vnc)
3749 my $tablet = $conf->{tablet
};
3750 if (!defined($tablet)) {
3751 $tablet = $defaults->{tablet
};
3752 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3753 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3757 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3758 my $kbd = print_keyboarddevice_full
($conf, $arch);
3759 push @$devices, '-device', $kbd if defined($kbd);
3762 my $bootorder = device_bootorder
($conf);
3764 # host pci device passthrough
3765 my ($kvm_off, $gpu_passthrough, $legacy_igd, $pci_devices) = PVE
::QemuServer
::PCI
::print_hostpci_devices
(
3766 $vmid, $conf, $devices, $vga, $winversion, $bridges, $arch, $machine_type, $bootorder);
3769 my $usb_dev_features = {};
3770 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3772 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
(
3773 $conf, $usb_dev_features, $bootorder, $machine_version);
3774 push @$devices, @usbdevices if @usbdevices;
3777 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3778 my $path = $conf->{"serial$i"} or next;
3779 if ($path eq 'socket') {
3780 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3781 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3782 # On aarch64, serial0 is the UART device. QEMU only allows
3783 # connecting UART devices via the '-serial' command line, as
3784 # the device has a fixed slot on the hardware...
3785 if ($arch eq 'aarch64' && $i == 0) {
3786 push @$devices, '-serial', "chardev:serial$i";
3788 push @$devices, '-device', "isa-serial,chardev=serial$i";
3791 die "no such serial device\n" if ! -c
$path;
3792 push @$devices, '-chardev', "serial,id=serial$i,path=$path";
3793 push @$devices, '-device', "isa-serial,chardev=serial$i";
3798 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3799 if (my $path = $conf->{"parallel$i"}) {
3800 die "no such parallel device\n" if ! -c
$path;
3801 my $devtype = $path =~ m!^/dev/usb/lp! ?
'serial' : 'parallel';
3802 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3803 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3807 if (min_version
($machine_version, 4, 0) && (my $audio = conf_has_audio
($conf))) {
3808 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3809 my $audio_devs = audio_devs
($audio, $audiopciaddr, $machine_version);
3810 push @$devices, @$audio_devs;
3813 add_tpm_device
($vmid, $devices, $conf);
3816 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3817 $sockets = $conf->{sockets
} if $conf->{sockets
};
3819 my $cores = $conf->{cores
} || 1;
3821 my $maxcpus = $sockets * $cores;
3823 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3825 my $allowed_vcpus = $cpuinfo->{cpus
};
3827 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n" if ($allowed_vcpus < $maxcpus);
3829 if ($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3830 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3831 for (my $i = 2; $i <= $vcpus; $i++) {
3832 my $cpustr = print_cpu_device
($conf,$i);
3833 push @$cmd, '-device', $cpustr;
3838 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3840 push @$cmd, '-nodefaults';
3842 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3844 push $machineFlags->@*, 'acpi=off' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3846 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3848 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3849 push @$devices, '-device', print_vga_device
(
3850 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3852 push @$cmd, '-display', 'egl-headless,gl=core' if $vga->{type
} eq 'virtio-gl'; # VIRGL
3854 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3855 push @$cmd, '-vnc', "unix:$socket,password=on";
3857 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3858 push @$cmd, '-nographic';
3862 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3863 my $useLocaltime = $conf->{localtime};
3865 if ($winversion >= 5) { # windows
3866 $useLocaltime = 1 if !defined($conf->{localtime});
3868 # use time drift fix when acpi is enabled
3869 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3870 $tdf = 1 if !defined($conf->{tdf
});
3874 if ($winversion >= 6) {
3875 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3876 push @$machineFlags, 'hpet=off';
3879 push @$rtcFlags, 'driftfix=slew' if $tdf;
3881 if ($conf->{startdate
} && $conf->{startdate
} ne 'now') {
3882 push @$rtcFlags, "base=$conf->{startdate}";
3883 } elsif ($useLocaltime) {
3884 push @$rtcFlags, 'base=localtime';
3888 push @$cmd, '-cpu', $forcecpu;
3890 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3893 PVE
::QemuServer
::Memory
::config
(
3894 $conf, $vmid, $sockets, $cores, $defaults, $hotplug_features->{memory
}, $cmd);
3896 push @$cmd, '-S' if $conf->{freeze
};
3898 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3900 my $guest_agent = parse_guest_agent
($conf);
3902 if ($guest_agent->{enabled
}) {
3903 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3904 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
3906 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3907 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3908 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3909 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3910 } elsif ($guest_agent->{type
} eq 'isa') {
3911 push @$devices, '-device', "isa-serial,chardev=qga0";
3915 my $rng = $conf->{rng0
} ? parse_rng
($conf->{rng0
}) : undef;
3916 if ($rng && $version_guard->(4, 1, 2)) {
3917 check_rng_source
($rng->{source
});
3919 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3920 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3921 my $limiter_str = "";
3923 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3926 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3927 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3928 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3933 if ($qxlnum || $vga->{type
} =~ /^virtio/) {
3936 for (my $i = 1; $i < $qxlnum; $i++){
3937 push @$devices, '-device', print_vga_device
(
3938 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3941 # assume other OS works like Linux
3942 my ($ram, $vram) = ("134217728", "67108864");
3943 if ($vga->{memory
}) {
3944 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3945 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3947 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3948 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3952 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3954 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3955 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3956 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3958 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3959 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3960 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3962 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3963 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3965 my $spice_enhancement_str = $conf->{spice_enhancements
} // '';
3966 my $spice_enhancement = parse_property_string
($spice_enhancements_fmt, $spice_enhancement_str);
3967 if ($spice_enhancement->{foldersharing
}) {
3968 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3969 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3972 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3973 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3974 if $spice_enhancement->{videostreaming
};
3976 push @$devices, '-spice', "$spice_opts";
3979 # enable balloon by default, unless explicitly disabled
3980 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3981 my $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3982 my $ballooncmd = "virtio-balloon-pci,id=balloon0$pciaddr";
3983 $ballooncmd .= ",free-page-reporting=on" if min_version
($machine_version, 6, 2);
3984 push @$devices, '-device', $ballooncmd;
3987 if ($conf->{watchdog
}) {
3988 my $wdopts = parse_watchdog
($conf->{watchdog
});
3989 my $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3990 my $watchdog = $wdopts->{model
} || 'i6300esb';
3991 push @$devices, '-device', "$watchdog$pciaddr";
3992 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3996 my $scsicontroller = {};
3997 my $ahcicontroller = {};
3998 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
4000 # Add iscsi initiator name if available
4001 if (my $initiator = get_initiator_name
()) {
4002 push @$devices, '-iscsi', "initiator-name=$initiator";
4005 PVE
::QemuConfig-
>foreach_volume($conf, sub {
4006 my ($ds, $drive) = @_;
4008 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
4009 check_volume_storage_type
($storecfg, $drive->{file
});
4010 push @$vollist, $drive->{file
};
4013 # ignore efidisk here, already added in bios/fw handling code above
4014 return if $drive->{interface
} eq 'efidisk';
4016 return if $drive->{interface
} eq 'tpmstate';
4018 $use_virtio = 1 if $ds =~ m/^virtio/;
4020 $drive->{bootindex
} = $bootorder->{$ds} if $bootorder->{$ds};
4022 if ($drive->{interface
} eq 'virtio'){
4023 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
4026 if ($drive->{interface
} eq 'scsi') {
4028 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
4030 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
4031 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
4033 my $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
4034 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
4037 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
4038 $iothread .= ",iothread=iothread-$controller_prefix$controller";
4039 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
4040 } elsif ($drive->{iothread
}) {
4042 "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n"
4047 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
4048 $queues = ",num_queues=$drive->{queues}";
4051 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
4052 if !$scsicontroller->{$controller};
4053 $scsicontroller->{$controller}=1;
4056 if ($drive->{interface
} eq 'sata') {
4057 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
4058 my $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
4059 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
4060 if !$ahcicontroller->{$controller};
4061 $ahcicontroller->{$controller}=1;
4064 my $pbs_conf = $pbs_backing->{$ds};
4065 my $pbs_name = undef;
4067 $pbs_name = "drive-$ds-pbs";
4068 push @$devices, '-blockdev', print_pbs_blockdev
($pbs_conf, $pbs_name);
4071 my $drive_cmd = print_drive_commandline_full
(
4072 $storecfg, $vmid, $drive, $pbs_name, min_version
($kvmver, 6, 0));
4074 # extra protection for templates, but SATA and IDE don't support it..
4075 $drive_cmd .= ',readonly=on' if drive_is_read_only
($conf, $drive);
4077 push @$devices, '-drive',$drive_cmd;
4078 push @$devices, '-device', print_drivedevice_full
(
4079 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
4082 for (my $i = 0; $i < $MAX_NETS; $i++) {
4083 my $netname = "net$i";
4085 next if !$conf->{$netname};
4086 my $d = parse_net
($conf->{$netname});
4088 # save the MAC addr here (could be auto-gen. in some odd setups) for FDB registering later?
4090 $use_virtio = 1 if $d->{model
} eq 'virtio';
4092 $d->{bootindex
} = $bootorder->{$netname} if $bootorder->{$netname};
4094 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, $netname);
4095 push @$devices, '-netdev', $netdevfull;
4097 my $netdevicefull = print_netdevice_full
(
4098 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type, $machine_version);
4100 push @$devices, '-device', $netdevicefull;
4103 if ($conf->{ivshmem
}) {
4104 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
4108 $bus = print_pcie_addr
("ivshmem");
4110 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
4113 my $ivshmem_name = $ivshmem->{name
} // $vmid;
4114 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4116 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4117 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
4118 .",size=$ivshmem->{size}M";
4121 # pci.4 is nested in pci.1
4122 $bridges->{1} = 1 if $bridges->{4};
4124 if (!$q35) { # add pci bridges
4125 if (min_version
($machine_version, 2, 3)) {
4129 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
4132 for my $k (sort {$b cmp $a} keys %$bridges) {
4133 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
4136 if ($k == 2 && $legacy_igd) {
4139 my $pciaddr = print_pci_addr
("pci.$k_name", undef, $arch, $machine_type);
4140 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
4142 if ($q35) { # add after -readconfig pve-q35.cfg
4143 splice @$devices, 2, 0, '-device', $devstr;
4145 unshift @$devices, '-device', $devstr if $k > 0;
4150 push @$machineFlags, 'accel=tcg';
4153 push @$machineFlags, 'smm=off' if should_disable_smm
($conf, $vga, $machine_type);
4155 my $machine_type_min = $machine_type;
4156 if ($add_pve_version) {
4157 $machine_type_min =~ s/\+pve\d+$//;
4158 $machine_type_min .= "+pve$required_pve_version";
4160 push @$machineFlags, "type=${machine_type_min}";
4162 push @$cmd, @$devices;
4163 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
4164 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
4165 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
4167 if (my $vmstate = $conf->{vmstate
}) {
4168 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
4169 push @$vollist, $vmstate;
4170 push @$cmd, '-loadstate', $statepath;
4171 print "activating and using '$vmstate' as vmstate\n";
4174 if (PVE
::QemuConfig-
>is_template($conf)) {
4175 # needed to workaround base volumes being read-only
4176 push @$cmd, '-snapshot';
4180 if ($conf->{args
}) {
4181 my $aa = PVE
::Tools
::split_args
($conf->{args
});
4185 return wantarray ?
($cmd, $vollist, $spice_port, $pci_devices) : $cmd;
4188 sub check_rng_source
{
4191 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
4192 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
4195 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
4196 if ($source eq '/dev/hwrng' && file_read_firstline
($rng_current) eq 'none') {
4197 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
4198 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
4199 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
4200 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
4208 my $res = mon_cmd
($vmid, 'query-spice');
4210 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
4213 sub vm_devices_list
{
4216 my $res = mon_cmd
($vmid, 'query-pci');
4217 my $devices_to_check = [];
4219 foreach my $pcibus (@$res) {
4220 push @$devices_to_check, @{$pcibus->{devices
}},
4223 while (@$devices_to_check) {
4225 for my $d (@$devices_to_check) {
4226 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4227 next if !$d->{'pci_bridge'} || !$d->{'pci_bridge'}->{devices
};
4229 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
4230 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
4232 $devices_to_check = $to_check;
4235 my $resblock = mon_cmd
($vmid, 'query-block');
4236 foreach my $block (@$resblock) {
4237 if($block->{device
} =~ m/^drive-(\S+)/){
4242 my $resmice = mon_cmd
($vmid, 'query-mice');
4243 foreach my $mice (@$resmice) {
4244 if ($mice->{name
} eq 'QEMU HID Tablet') {
4245 $devices->{tablet
} = 1;
4250 # for usb devices there is no query-usb
4251 # but we can iterate over the entries in
4252 # qom-list path=/machine/peripheral
4253 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4254 foreach my $per (@$resperipheral) {
4255 if ($per->{name
} =~ m/^usb(?:redirdev)?\d+$/) {
4256 $devices->{$per->{name
}} = 1;
4264 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4266 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
4268 my $devices_list = vm_devices_list
($vmid);
4269 return 1 if defined($devices_list->{$deviceid});
4271 # add PCI bridge if we need it for the device
4272 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
4274 if ($deviceid eq 'tablet') {
4275 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4276 } elsif ($deviceid eq 'keyboard') {
4277 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4278 } elsif ($deviceid =~ m/^usbredirdev(\d+)$/) {
4280 qemu_spice_usbredir_chardev_add
($vmid, "usbredirchardev$id");
4281 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_spice_usbdevice
($id, "xhci", $id + 1));
4282 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4283 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device, {}, $1 + 1));
4284 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4285 qemu_iothread_add
($vmid, $deviceid, $device);
4287 qemu_driveadd
($storecfg, $vmid, $device);
4288 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4290 qemu_deviceadd
($vmid, $devicefull);
4291 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4293 eval { qemu_drivedel
($vmid, $deviceid); };
4297 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4298 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4299 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4300 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4302 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4304 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4305 qemu_iothread_add
($vmid, $deviceid, $device);
4306 $devicefull .= ",iothread=iothread-$deviceid";
4309 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4310 $devicefull .= ",num_queues=$device->{queues}";
4313 qemu_deviceadd
($vmid, $devicefull);
4314 qemu_deviceaddverify
($vmid, $deviceid);
4315 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4316 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4317 qemu_driveadd
($storecfg, $vmid, $device);
4319 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4320 eval { qemu_deviceadd
($vmid, $devicefull); };
4322 eval { qemu_drivedel
($vmid, $deviceid); };
4326 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4327 return if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4329 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
4330 my $machine_version = PVE
::QemuServer
::Machine
::extract_version
($machine_type);
4331 my $use_old_bios_files = undef;
4332 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4334 my $netdevicefull = print_netdevice_full
(
4335 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type, $machine_version);
4336 qemu_deviceadd
($vmid, $netdevicefull);
4338 qemu_deviceaddverify
($vmid, $deviceid);
4339 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4342 eval { qemu_netdevdel
($vmid, $deviceid); };
4346 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4348 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4349 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4351 qemu_deviceadd
($vmid, $devicefull);
4352 qemu_deviceaddverify
($vmid, $deviceid);
4354 die "can't hotplug device '$deviceid'\n";
4360 # fixme: this should raise exceptions on error!
4361 sub vm_deviceunplug
{
4362 my ($vmid, $conf, $deviceid) = @_;
4364 my $devices_list = vm_devices_list
($vmid);
4365 return 1 if !defined($devices_list->{$deviceid});
4367 my $bootdisks = PVE
::QemuServer
::Drive
::get_bootdisks
($conf);
4368 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
4370 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard' || $deviceid eq 'xhci') {
4371 qemu_devicedel
($vmid, $deviceid);
4372 } elsif ($deviceid =~ m/^usbredirdev\d+$/) {
4373 qemu_devicedel
($vmid, $deviceid);
4374 qemu_devicedelverify
($vmid, $deviceid);
4375 } elsif ($deviceid =~ m/^usb\d+$/) {
4376 qemu_devicedel
($vmid, $deviceid);
4377 qemu_devicedelverify
($vmid, $deviceid);
4378 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4379 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4381 qemu_devicedel
($vmid, $deviceid);
4382 qemu_devicedelverify
($vmid, $deviceid);
4383 qemu_drivedel
($vmid, $deviceid);
4384 qemu_iothread_del
($vmid, $deviceid, $device);
4385 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4386 qemu_devicedel
($vmid, $deviceid);
4387 qemu_devicedelverify
($vmid, $deviceid);
4388 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4389 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4391 qemu_devicedel
($vmid, $deviceid);
4392 qemu_devicedelverify
($vmid, $deviceid);
4393 qemu_drivedel
($vmid, $deviceid);
4394 qemu_deletescsihw
($conf, $vmid, $deviceid);
4396 qemu_iothread_del
($vmid, "virtioscsi$device->{index}", $device)
4397 if $conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single');
4398 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4399 qemu_devicedel
($vmid, $deviceid);
4400 qemu_devicedelverify
($vmid, $deviceid);
4401 qemu_netdevdel
($vmid, $deviceid);
4403 die "can't unplug device '$deviceid'\n";
4409 sub qemu_spice_usbredir_chardev_add
{
4410 my ($vmid, $id) = @_;
4412 mon_cmd
($vmid, "chardev-add" , (
4423 sub qemu_deviceadd
{
4424 my ($vmid, $devicefull) = @_;
4426 $devicefull = "driver=".$devicefull;
4427 my %options = split(/[=,]/, $devicefull);
4429 mon_cmd
($vmid, "device_add" , %options);
4432 sub qemu_devicedel
{
4433 my ($vmid, $deviceid) = @_;
4435 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
4438 sub qemu_iothread_add
{
4439 my ($vmid, $deviceid, $device) = @_;
4441 if ($device->{iothread
}) {
4442 my $iothreads = vm_iothreads_list
($vmid);
4443 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4447 sub qemu_iothread_del
{
4448 my ($vmid, $deviceid, $device) = @_;
4450 if ($device->{iothread
}) {
4451 my $iothreads = vm_iothreads_list
($vmid);
4452 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4456 sub qemu_objectadd
{
4457 my ($vmid, $objectid, $qomtype) = @_;
4459 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4464 sub qemu_objectdel
{
4465 my ($vmid, $objectid) = @_;
4467 mon_cmd
($vmid, "object-del", id
=> $objectid);
4473 my ($storecfg, $vmid, $device) = @_;
4475 my $kvmver = get_running_qemu_version
($vmid);
4476 my $io_uring = min_version
($kvmver, 6, 0);
4477 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device, undef, $io_uring);
4478 $drive =~ s/\\/\\\\/g;
4479 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
4481 # If the command succeeds qemu prints: "OK
"
4482 return 1 if $ret =~ m/OK/s;
4484 die "adding drive failed
: $ret\n";
4488 my ($vmid, $deviceid) = @_;
4490 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
4493 return 1 if $ret eq "";
4495 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4496 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4498 die "deleting drive
$deviceid failed
: $ret\n";
4501 sub qemu_deviceaddverify {
4502 my ($vmid, $deviceid) = @_;
4504 for (my $i = 0; $i <= 5; $i++) {
4505 my $devices_list = vm_devices_list($vmid);
4506 return 1 if defined($devices_list->{$deviceid});
4510 die "error on hotplug device
'$deviceid'\n";
4514 sub qemu_devicedelverify {
4515 my ($vmid, $deviceid) = @_;
4517 # need to verify that the device is correctly removed as device_del
4518 # is async and empty return is not reliable
4520 for (my $i = 0; $i <= 5; $i++) {
4521 my $devices_list = vm_devices_list($vmid);
4522 return 1 if !defined($devices_list->{$deviceid});
4526 die "error on hot-unplugging device
'$deviceid'\n";
4529 sub qemu_findorcreatescsihw {
4530 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4532 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4534 my $scsihwid="$controller_prefix$controller";
4535 my $devices_list = vm_devices_list($vmid);
4537 if (!defined($devices_list->{$scsihwid})) {
4538 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4544 sub qemu_deletescsihw {
4545 my ($conf, $vmid, $opt) = @_;
4547 my $device = parse_drive($opt, $conf->{$opt});
4549 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4550 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4554 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4556 my $devices_list = vm_devices_list($vmid);
4557 foreach my $opt (keys %{$devices_list}) {
4558 if (is_valid_drivename($opt)) {
4559 my $drive = parse_drive($opt, $conf->{$opt});
4560 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4566 my $scsihwid="scsihw
$controller";
4568 vm_deviceunplug($vmid, $conf, $scsihwid);
4573 sub qemu_add_pci_bridge {
4574 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4580 print_pci_addr($device, $bridges, $arch, $machine_type);
4582 while (my ($k, $v) = each %$bridges) {
4585 return 1 if !defined($bridgeid) || $bridgeid < 1;
4587 my $bridge = "pci
.$bridgeid";
4588 my $devices_list = vm_devices_list($vmid);
4590 if (!defined($devices_list->{$bridge})) {
4591 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4597 sub qemu_set_link_status {
4598 my ($vmid, $device, $up) = @_;
4600 mon_cmd($vmid, "set_link
", name => $device,
4601 up => $up ? JSON::true : JSON::false);
4604 sub qemu_netdevadd {
4605 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4607 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4608 my %options = split(/[=,]/, $netdev);
4610 if (defined(my $vhost = $options{vhost})) {
4611 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4614 if (defined(my $queues = $options{queues})) {
4615 $options{queues} = $queues + 0;
4618 mon_cmd($vmid, "netdev_add
", %options);
4622 sub qemu_netdevdel {
4623 my ($vmid, $deviceid) = @_;
4625 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4628 sub qemu_usb_hotplug {
4629 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4633 # remove the old one first
4634 vm_deviceunplug($vmid, $conf, $deviceid);
4636 # check if xhci controller is necessary and available
4637 my $devicelist = vm_devices_list($vmid);
4639 if (!$devicelist->{xhci}) {
4640 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4641 qemu_deviceadd($vmid, PVE::QemuServer::USB::print_qemu_xhci_controller($pciaddr));
4645 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type);
4648 sub qemu_cpu_hotplug {
4649 my ($vmid, $conf, $vcpus) = @_;
4651 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4654 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4655 $sockets = $conf->{sockets} if $conf->{sockets};
4656 my $cores = $conf->{cores} || 1;
4657 my $maxcpus = $sockets * $cores;
4659 $vcpus = $maxcpus if !$vcpus;
4661 die "you can
't add more vcpus than maxcpus\n"
4662 if $vcpus > $maxcpus;
4664 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4666 if ($vcpus < $currentvcpus) {
4668 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4670 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4671 qemu_devicedel($vmid, "cpu$i");
4673 my $currentrunningvcpus = undef;
4675 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4676 last if scalar(@{$currentrunningvcpus}) == $i-1;
4677 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4681 #update conf after each succesfull cpu unplug
4682 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4683 PVE::QemuConfig->write_config($vmid, $conf);
4686 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4692 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4693 die "vcpus in running vm does not match its configuration\n"
4694 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4696 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4698 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4699 my $cpustr = print_cpu_device($conf, $i);
4700 qemu_deviceadd($vmid, $cpustr);
4703 my $currentrunningvcpus = undef;
4705 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4706 last if scalar(@{$currentrunningvcpus}) == $i;
4707 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4711 #update conf after each succesfull cpu hotplug
4712 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4713 PVE::QemuConfig->write_config($vmid, $conf);
4717 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4718 mon_cmd($vmid, "cpu-add", id => int($i));
4723 sub qemu_block_set_io_throttle {
4724 my ($vmid, $deviceid,
4725 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4726 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4727 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4728 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4730 return if !check_running($vmid) ;
4732 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4734 bps_rd => int($bps_rd),
4735 bps_wr => int($bps_wr),
4737 iops_rd => int($iops_rd),
4738 iops_wr => int($iops_wr),
4739 bps_max => int($bps_max),
4740 bps_rd_max => int($bps_rd_max),
4741 bps_wr_max => int($bps_wr_max),
4742 iops_max => int($iops_max),
4743 iops_rd_max => int($iops_rd_max),
4744 iops_wr_max => int($iops_wr_max),
4745 bps_max_length => int($bps_max_length),
4746 bps_rd_max_length => int($bps_rd_max_length),
4747 bps_wr_max_length => int($bps_wr_max_length),
4748 iops_max_length => int($iops_max_length),
4749 iops_rd_max_length => int($iops_rd_max_length),
4750 iops_wr_max_length => int($iops_wr_max_length),
4755 sub qemu_block_resize {
4756 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4758 my $running = check_running($vmid);
4760 PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4762 return if !$running;
4764 my $padding = (1024 - $size % 1024) % 1024;
4765 $size = $size + $padding;
4770 device => $deviceid,
4776 sub qemu_volume_snapshot {
4777 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4779 my $running = check_running($vmid);
4781 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4782 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4784 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4788 sub qemu_volume_snapshot_delete {
4789 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4791 my $running = check_running($vmid);
4796 my $conf = PVE::QemuConfig->load_config($vmid);
4797 PVE::QemuConfig->foreach_volume($conf, sub {
4798 my ($ds, $drive) = @_;
4799 $running = 1 if $drive->{file} eq $volid;
4803 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4804 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4806 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4810 sub set_migration_caps {
4811 my ($vmid, $savevm) = @_;
4813 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4815 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm
' : 'pbs-dirty-bitmap-migration
';
4816 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4821 "auto-converge" => 1,
4823 "x-rdma-pin-all" => 0,
4826 "dirty-bitmaps" => $dirty_bitmaps,
4829 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4831 for my $supported_capability (@$supported_capabilities) {
4833 capability => $supported_capability->{capability},
4834 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4838 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4842 my ($conf, $func, @param) = @_;
4846 my $test_volid = sub {
4847 my ($key, $drive, $snapname) = @_;
4849 my $volid = $drive->{file};
4852 $volhash->{$volid}->{cdrom} //= 1;
4853 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
4855 my $replicate = $drive->{replicate} // 1;
4856 $volhash->{$volid}->{replicate} //= 0;
4857 $volhash->{$volid}->{replicate} = 1 if $replicate;
4859 $volhash->{$volid}->{shared} //= 0;
4860 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
4862 $volhash->{$volid}->{referenced_in_config} //= 0;
4863 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4865 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4866 if defined($snapname);
4868 my $size = $drive->{size};
4869 $volhash->{$volid}->{size} //= $size if $size;
4871 $volhash->{$volid}->{is_vmstate} //= 0;
4872 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate
';
4874 $volhash->{$volid}->{is_tpmstate} //= 0;
4875 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0
';
4877 $volhash->{$volid}->{is_unused} //= 0;
4878 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
4880 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
4883 my $include_opts = {
4884 extra_keys => ['vmstate
'],
4885 include_unused => 1,
4888 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
4889 foreach my $snapname (keys %{$conf->{snapshots}}) {
4890 my $snap = $conf->{snapshots}->{$snapname};
4891 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
4894 foreach my $volid (keys %$volhash) {
4895 &$func($volid, $volhash->{$volid}, @param);
4899 my $fast_plug_option = {
4903 'migrate_downtime
' => 1,
4904 'migrate_speed
' => 1,
4911 'vmstatestorage
' => 1,
4914 for my $opt (keys %$confdesc_cloudinit) {
4915 $fast_plug_option->{$opt} = 1;
4918 # hotplug changes in [PENDING]
4919 # $selection hash can be used to only apply specified options, for
4920 # example: { cores => 1 } (only apply changed 'cores
')
4921 # $errors ref is used to return error messages
4922 sub vmconfig_hotplug_pending {
4923 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4925 my $defaults = load_defaults();
4926 my $arch = get_vm_arch($conf);
4927 my $machine_type = get_vm_machine($conf, undef, $arch);
4929 # commit values which do not have any impact on running VM first
4930 # Note: those option cannot raise errors, we we do not care about
4931 # $selection and always apply them.
4933 my $add_error = sub {
4934 my ($opt, $msg) = @_;
4935 $errors->{$opt} = "hotplug problem - $msg";
4938 my $cloudinit_pending_properties = PVE::QemuServer::cloudinit_pending_properties();
4940 my $cloudinit_record_changed = sub {
4941 my ($conf, $opt, $old, $new) = @_;
4942 return if !$cloudinit_pending_properties->{$opt};
4944 my $ci = ($conf->{cloudinit} //= {});
4946 my $recorded = $ci->{$opt};
4947 my %added = map { $_ => 1 } PVE::Tools::split_list(delete($ci->{added}) // '');
4949 if (defined($new)) {
4950 if (defined($old)) {
4951 # an existing value is being modified
4952 if (defined($recorded)) {
4953 # the value was already not in sync
4954 if ($new eq $recorded) {
4955 # a value is being reverted to the cloud-init state:
4957 delete $added{$opt};
4959 # the value was changed multiple times, do nothing
4961 } elsif ($added{$opt}) {
4962 # the value had been marked as added and is being changed, do nothing
4964 # the value is new, record it:
4968 # a new value is being added
4969 if (defined($recorded)) {
4970 # it was already not in sync
4971 if ($new eq $recorded) {
4972 # a value is being reverted to the cloud-init state:
4974 delete $added{$opt};
4976 # the value had temporarily been removed, do nothing
4978 } elsif ($added{$opt}) {
4979 # the value had been marked as added already, do nothing
4981 # the value is new, add it
4985 } elsif (!defined($old)) {
4986 # a non-existent value is being removed? ignore...
4988 # a value is being deleted
4989 if (defined($recorded)) {
4990 # a value was already recorded, just keep it
4991 } elsif ($added{$opt}) {
4992 # the value was marked as added, remove it
4993 delete $added{$opt};
4995 # a previously unrecorded value is being removed, record the old value:
5000 my $added = join(',', sort keys %added);
5001 $ci->{added} = $added if length($added);
5005 foreach my $opt (keys %{$conf->{pending}}) { # add/change
5006 if ($fast_plug_option->{$opt}) {
5007 my $new = delete $conf->{pending}->{$opt};
5008 $cloudinit_record_changed->($conf, $opt, $conf->{$opt}, $new);
5009 $conf->{$opt} = $new;
5015 PVE::QemuConfig->write_config($vmid, $conf);
5018 my $ostype = $conf->{ostype};
5019 my $version = extract_version($machine_type, get_running_qemu_version($vmid));
5020 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
5021 my $usb_hotplug = $hotplug_features->{usb}
5022 && min_version($version, 7, 1)
5023 && defined($ostype) && ($ostype eq 'l26
' || windows_version($ostype) > 7);
5025 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
5026 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
5028 foreach my $opt (sort keys %$pending_delete_hash) {
5029 next if $selection && !$selection->{$opt};
5030 my $force = $pending_delete_hash->{$opt}->{force};
5032 if ($opt eq 'hotplug
') {
5033 die "skip\n" if ($conf->{hotplug} =~ /memory/);
5034 } elsif ($opt eq 'tablet
') {
5035 die "skip\n" if !$hotplug_features->{usb};
5036 if ($defaults->{tablet}) {
5037 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
5038 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
5039 if $arch eq 'aarch64
';
5041 vm_deviceunplug($vmid, $conf, 'tablet
');
5042 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
5044 } elsif ($opt =~ m/^usb(\d+)$/) {
5046 die "skip\n" if !$usb_hotplug;
5047 vm_deviceunplug($vmid, $conf, "usbredirdev$index"); # if it's a spice port
5048 vm_deviceunplug
($vmid, $conf, $opt);
5049 } elsif ($opt eq 'vcpus') {
5050 die "skip\n" if !$hotplug_features->{cpu
};
5051 qemu_cpu_hotplug
($vmid, $conf, undef);
5052 } elsif ($opt eq 'balloon') {
5053 # enable balloon device is not hotpluggable
5054 die "skip\n" if defined($conf->{balloon
}) && $conf->{balloon
} == 0;
5055 # here we reset the ballooning value to memory
5056 my $balloon = $conf->{memory
} || $defaults->{memory
};
5057 mon_cmd
($vmid, "balloon", value
=> $balloon*1024*1024);
5058 } elsif ($fast_plug_option->{$opt}) {
5060 } elsif ($opt =~ m/^net(\d+)$/) {
5061 die "skip\n" if !$hotplug_features->{network
};
5062 vm_deviceunplug
($vmid, $conf, $opt);
5063 } elsif (is_valid_drivename
($opt)) {
5064 die "skip\n" if !$hotplug_features->{disk
} || $opt =~ m/(ide|sata)(\d+)/;
5065 vm_deviceunplug
($vmid, $conf, $opt);
5066 vmconfig_delete_or_detach_drive
($vmid, $storecfg, $conf, $opt, $force);
5067 } elsif ($opt =~ m/^memory$/) {
5068 die "skip\n" if !$hotplug_features->{memory
};
5069 PVE
::QemuServer
::Memory
::qemu_memory_hotplug
($vmid, $conf, $defaults);
5070 } elsif ($opt eq 'cpuunits') {
5071 $cgroup->change_cpu_shares(undef);
5072 } elsif ($opt eq 'cpulimit') {
5073 $cgroup->change_cpu_quota(undef, undef); # reset, cgroup module can better decide values
5079 &$add_error($opt, $err) if $err ne "skip\n";
5081 my $old = delete $conf->{$opt};
5082 $cloudinit_record_changed->($conf, $opt, $old, undef);
5083 PVE
::QemuConfig-
>remove_from_pending_delete($conf, $opt);
5088 foreach my $opt (keys %{$conf->{pending
}}) {
5089 next if $selection && !$selection->{$opt};
5090 my $value = $conf->{pending
}->{$opt};
5092 if ($opt eq 'hotplug') {
5093 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug
} =~ /memory/);
5094 } elsif ($opt eq 'tablet') {
5095 die "skip\n" if !$hotplug_features->{usb
};
5097 vm_deviceplug
($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
5098 vm_deviceplug
($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
5099 if $arch eq 'aarch64';
5100 } elsif ($value == 0) {
5101 vm_deviceunplug
($vmid, $conf, 'tablet');
5102 vm_deviceunplug
($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
5104 } elsif ($opt =~ m/^usb(\d+)$/) {
5106 die "skip\n" if !$usb_hotplug;
5107 my $d = eval { parse_property_string
('pve-qm-usb', $value) };
5109 if ($d->{host
} =~ m/^spice$/i) {
5110 $id = "usbredirdev$index";
5112 qemu_usb_hotplug
($storecfg, $conf, $vmid, $id, $d, $arch, $machine_type);
5113 } elsif ($opt eq 'vcpus') {
5114 die "skip\n" if !$hotplug_features->{cpu
};
5115 qemu_cpu_hotplug
($vmid, $conf, $value);
5116 } elsif ($opt eq 'balloon') {
5117 # enable/disable balloning device is not hotpluggable
5118 my $old_balloon_enabled = !!(!defined($conf->{balloon
}) || $conf->{balloon
});
5119 my $new_balloon_enabled = !!(!defined($conf->{pending
}->{balloon
}) || $conf->{pending
}->{balloon
});
5120 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
5122 # allow manual ballooning if shares is set to zero
5123 if ((defined($conf->{shares
}) && ($conf->{shares
} == 0))) {
5124 my $balloon = $conf->{pending
}->{balloon
} || $conf->{memory
} || $defaults->{memory
};
5125 mon_cmd
($vmid, "balloon", value
=> $balloon*1024*1024);
5127 } elsif ($opt =~ m/^net(\d+)$/) {
5128 # some changes can be done without hotplug
5129 vmconfig_update_net
($storecfg, $conf, $hotplug_features->{network
},
5130 $vmid, $opt, $value, $arch, $machine_type);
5131 } elsif (is_valid_drivename
($opt)) {
5132 die "skip\n" if $opt eq 'efidisk0' || $opt eq 'tpmstate0';
5133 # some changes can be done without hotplug
5134 my $drive = parse_drive
($opt, $value);
5135 if (drive_is_cloudinit
($drive)) {
5136 $cloudinit_opt = [$opt, $drive];
5137 # apply all the other changes first, then generate the cloudinit disk
5140 vmconfig_update_disk
($storecfg, $conf, $hotplug_features->{disk
},
5141 $vmid, $opt, $value, $arch, $machine_type);
5142 } elsif ($opt =~ m/^memory$/) { #dimms
5143 die "skip\n" if !$hotplug_features->{memory
};
5144 $value = PVE
::QemuServer
::Memory
::qemu_memory_hotplug
($vmid, $conf, $defaults, $value);
5145 } elsif ($opt eq 'cpuunits') {
5146 my $new_cpuunits = PVE
::CGroup
::clamp_cpu_shares
($conf->{pending
}->{$opt}); #clamp
5147 $cgroup->change_cpu_shares($new_cpuunits);
5148 } elsif ($opt eq 'cpulimit') {
5149 my $cpulimit = $conf->{pending
}->{$opt} == 0 ?
-1 : int($conf->{pending
}->{$opt} * 100000);
5150 $cgroup->change_cpu_quota($cpulimit, 100000);
5151 } elsif ($opt eq 'agent') {
5152 vmconfig_update_agent
($conf, $opt, $value);
5154 die "skip\n"; # skip non-hot-pluggable options
5158 &$add_error($opt, $err) if $err ne "skip\n";
5160 $cloudinit_record_changed->($conf, $opt, $conf->{$opt}, $value);
5161 $conf->{$opt} = $value;
5162 delete $conf->{pending
}->{$opt};
5166 if (defined($cloudinit_opt)) {
5167 my ($opt, $drive) = @$cloudinit_opt;
5168 my $value = $conf->{pending
}->{$opt};
5170 my $temp = {%$conf, $opt => $value};
5171 PVE
::QemuServer
::Cloudinit
::apply_cloudinit_config
($temp, $vmid);
5172 vmconfig_update_disk
($storecfg, $conf, $hotplug_features->{disk
},
5173 $vmid, $opt, $value, $arch, $machine_type);
5176 &$add_error($opt, $err) if $err ne "skip\n";
5178 $conf->{$opt} = $value;
5179 delete $conf->{pending
}->{$opt};
5183 # unplug xhci controller if no usb device is left
5186 for (my $i = 0; $i < $PVE::QemuServer
::USB
::MAX_USB_DEVICES
; $i++) {
5187 next if !defined($conf->{"usb$i"});
5192 vm_deviceunplug
($vmid, $conf, 'xhci');
5196 PVE
::QemuConfig-
>write_config($vmid, $conf);
5198 if ($hotplug_features->{cloudinit
} && PVE
::QemuServer
::Cloudinit
::has_changes
($conf)) {
5199 PVE
::QemuServer
::vmconfig_update_cloudinit_drive
($storecfg, $conf, $vmid);
5203 sub try_deallocate_drive
{
5204 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
5206 if (($force || $key =~ /^unused/) && !drive_is_cdrom
($drive, 1)) {
5207 my $volid = $drive->{file
};
5208 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
5209 my $sid = PVE
::Storage
::parse_volume_id
($volid);
5210 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
5212 # check if the disk is really unused
5213 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
5214 if PVE
::QemuServer
::Drive
::is_volume_in_use
($storecfg, $conf, $key, $volid);
5215 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5218 # If vm is not owner of this disk remove from config
5226 sub vmconfig_delete_or_detach_drive
{
5227 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
5229 my $drive = parse_drive
($opt, $conf->{$opt});
5231 my $rpcenv = PVE
::RPCEnvironment
::get
();
5232 my $authuser = $rpcenv->get_user();
5235 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
5236 try_deallocate_drive
($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
5238 vmconfig_register_unused_drive
($storecfg, $vmid, $conf, $drive);
5244 sub vmconfig_apply_pending
{
5245 my ($vmid, $conf, $storecfg, $errors, $skip_cloud_init) = @_;
5247 return if !scalar(keys %{$conf->{pending
}});
5249 my $add_apply_error = sub {
5250 my ($opt, $msg) = @_;
5251 my $err_msg = "unable to apply pending change $opt : $msg";
5252 $errors->{$opt} = $err_msg;
5258 my $pending_delete_hash = PVE
::QemuConfig-
>parse_pending_delete($conf->{pending
}->{delete});
5259 foreach my $opt (sort keys %$pending_delete_hash) {
5260 my $force = $pending_delete_hash->{$opt}->{force
};
5262 if ($opt =~ m/^unused/) {
5263 die "internal error";
5264 } elsif (defined($conf->{$opt}) && is_valid_drivename
($opt)) {
5265 vmconfig_delete_or_detach_drive
($vmid, $storecfg, $conf, $opt, $force);
5269 $add_apply_error->($opt, $err);
5271 PVE
::QemuConfig-
>remove_from_pending_delete($conf, $opt);
5272 delete $conf->{$opt};
5276 PVE
::QemuConfig-
>cleanup_pending($conf);
5278 my $generate_cloudinit = $skip_cloud_init ?
0 : undef;
5280 foreach my $opt (keys %{$conf->{pending
}}) { # add/change
5281 next if $opt eq 'delete'; # just to be sure
5283 if (defined($conf->{$opt}) && is_valid_drivename
($opt)) {
5284 vmconfig_register_unused_drive
($storecfg, $vmid, $conf, parse_drive
($opt, $conf->{$opt}))
5288 $add_apply_error->($opt, $err);
5291 if (is_valid_drivename
($opt)) {
5292 my $drive = parse_drive
($opt, $conf->{pending
}->{$opt});
5293 $generate_cloudinit //= 1 if drive_is_cloudinit
($drive);
5296 $conf->{$opt} = delete $conf->{pending
}->{$opt};
5300 # write all changes at once to avoid unnecessary i/o
5301 PVE
::QemuConfig-
>write_config($vmid, $conf);
5302 if ($generate_cloudinit) {
5303 if (PVE
::QemuServer
::Cloudinit
::apply_cloudinit_config
($conf, $vmid)) {
5304 # After successful generation and if there were changes to be applied, update the
5305 # config to drop the {cloudinit} entry.
5306 PVE
::QemuConfig-
>write_config($vmid, $conf);
5311 sub vmconfig_update_net
{
5312 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5314 my $newnet = parse_net
($value);
5316 if ($conf->{$opt}) {
5317 my $oldnet = parse_net
($conf->{$opt});
5319 if (safe_string_ne
($oldnet->{model
}, $newnet->{model
}) ||
5320 safe_string_ne
($oldnet->{macaddr
}, $newnet->{macaddr
}) ||
5321 safe_num_ne
($oldnet->{queues
}, $newnet->{queues
}) ||
5322 safe_num_ne
($oldnet->{mtu
}, $newnet->{mtu
}) ||
5323 !($newnet->{bridge
} && $oldnet->{bridge
})) { # bridge/nat mode change
5325 # for non online change, we try to hot-unplug
5326 die "skip\n" if !$hotplug;
5327 vm_deviceunplug
($vmid, $conf, $opt);
5330 die "internal error" if $opt !~ m/net(\d+)/;
5331 my $iface = "tap${vmid}i$1";
5333 if (safe_string_ne
($oldnet->{bridge
}, $newnet->{bridge
}) ||
5334 safe_num_ne
($oldnet->{tag
}, $newnet->{tag
}) ||
5335 safe_string_ne
($oldnet->{trunks
}, $newnet->{trunks
}) ||
5336 safe_num_ne
($oldnet->{firewall
}, $newnet->{firewall
})) {
5337 PVE
::Network
::tap_unplug
($iface);
5340 PVE
::Network
::SDN
::Zones
::tap_plug
($iface, $newnet->{bridge
}, $newnet->{tag
}, $newnet->{firewall
}, $newnet->{trunks
}, $newnet->{rate
});
5342 PVE
::Network
::tap_plug
($iface, $newnet->{bridge
}, $newnet->{tag
}, $newnet->{firewall
}, $newnet->{trunks
}, $newnet->{rate
});
5344 } elsif (safe_num_ne
($oldnet->{rate
}, $newnet->{rate
})) {
5345 # Rate can be applied on its own but any change above needs to
5346 # include the rate in tap_plug since OVS resets everything.
5347 PVE
::Network
::tap_rate_limit
($iface, $newnet->{rate
});
5350 if (safe_string_ne
($oldnet->{link_down
}, $newnet->{link_down
})) {
5351 qemu_set_link_status
($vmid, $opt, !$newnet->{link_down
});
5359 vm_deviceplug
($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5365 sub vmconfig_update_agent
{
5366 my ($conf, $opt, $value) = @_;
5368 die "skip\n" if !$conf->{$opt};
5370 my $hotplug_options = { fstrim_cloned_disks
=> 1 };
5372 my $old_agent = parse_guest_agent
($conf);
5373 my $agent = parse_guest_agent
({$opt => $value});
5375 for my $option (keys %$agent) { # added/changed options
5376 next if defined($hotplug_options->{$option});
5377 die "skip\n" if safe_string_ne
($agent->{$option}, $old_agent->{$option});
5380 for my $option (keys %$old_agent) { # removed options
5381 next if defined($hotplug_options->{$option});
5382 die "skip\n" if safe_string_ne
($old_agent->{$option}, $agent->{$option});
5385 return; # either no actual change (e.g., format string reordered) or just hotpluggable changes
5388 sub vmconfig_update_disk
{
5389 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5391 my $drive = parse_drive
($opt, $value);
5393 if ($conf->{$opt} && (my $old_drive = parse_drive
($opt, $conf->{$opt}))) {
5394 my $media = $drive->{media
} || 'disk';
5395 my $oldmedia = $old_drive->{media
} || 'disk';
5396 die "unable to change media type\n" if $media ne $oldmedia;
5398 if (!drive_is_cdrom
($old_drive)) {
5400 if ($drive->{file
} ne $old_drive->{file
}) {
5402 die "skip\n" if !$hotplug;
5404 # unplug and register as unused
5405 vm_deviceunplug
($vmid, $conf, $opt);
5406 vmconfig_register_unused_drive
($storecfg, $vmid, $conf, $old_drive)
5409 # update existing disk
5411 # skip non hotpluggable value
5412 if (safe_string_ne
($drive->{aio
}, $old_drive->{aio
}) ||
5413 safe_string_ne
($drive->{discard
}, $old_drive->{discard
}) ||
5414 safe_string_ne
($drive->{iothread
}, $old_drive->{iothread
}) ||
5415 safe_string_ne
($drive->{queues
}, $old_drive->{queues
}) ||
5416 safe_string_ne
($drive->{cache
}, $old_drive->{cache
}) ||
5417 safe_string_ne
($drive->{ssd
}, $old_drive->{ssd
}) ||
5418 safe_string_ne
($drive->{ro
}, $old_drive->{ro
})) {
5423 if (safe_num_ne
($drive->{mbps
}, $old_drive->{mbps
}) ||
5424 safe_num_ne
($drive->{mbps_rd
}, $old_drive->{mbps_rd
}) ||
5425 safe_num_ne
($drive->{mbps_wr
}, $old_drive->{mbps_wr
}) ||
5426 safe_num_ne
($drive->{iops
}, $old_drive->{iops
}) ||
5427 safe_num_ne
($drive->{iops_rd
}, $old_drive->{iops_rd
}) ||
5428 safe_num_ne
($drive->{iops_wr
}, $old_drive->{iops_wr
}) ||
5429 safe_num_ne
($drive->{mbps_max
}, $old_drive->{mbps_max
}) ||
5430 safe_num_ne
($drive->{mbps_rd_max
}, $old_drive->{mbps_rd_max
}) ||
5431 safe_num_ne
($drive->{mbps_wr_max
}, $old_drive->{mbps_wr_max
}) ||
5432 safe_num_ne
($drive->{iops_max
}, $old_drive->{iops_max
}) ||
5433 safe_num_ne
($drive->{iops_rd_max
}, $old_drive->{iops_rd_max
}) ||
5434 safe_num_ne
($drive->{iops_wr_max
}, $old_drive->{iops_wr_max
}) ||
5435 safe_num_ne
($drive->{bps_max_length
}, $old_drive->{bps_max_length
}) ||
5436 safe_num_ne
($drive->{bps_rd_max_length
}, $old_drive->{bps_rd_max_length
}) ||
5437 safe_num_ne
($drive->{bps_wr_max_length
}, $old_drive->{bps_wr_max_length
}) ||
5438 safe_num_ne
($drive->{iops_max_length
}, $old_drive->{iops_max_length
}) ||
5439 safe_num_ne
($drive->{iops_rd_max_length
}, $old_drive->{iops_rd_max_length
}) ||
5440 safe_num_ne
($drive->{iops_wr_max_length
}, $old_drive->{iops_wr_max_length
})) {
5442 qemu_block_set_io_throttle
(
5444 ($drive->{mbps
} || 0)*1024*1024,
5445 ($drive->{mbps_rd
} || 0)*1024*1024,
5446 ($drive->{mbps_wr
} || 0)*1024*1024,
5447 $drive->{iops
} || 0,
5448 $drive->{iops_rd
} || 0,
5449 $drive->{iops_wr
} || 0,
5450 ($drive->{mbps_max
} || 0)*1024*1024,
5451 ($drive->{mbps_rd_max
} || 0)*1024*1024,
5452 ($drive->{mbps_wr_max
} || 0)*1024*1024,
5453 $drive->{iops_max
} || 0,
5454 $drive->{iops_rd_max
} || 0,
5455 $drive->{iops_wr_max
} || 0,
5456 $drive->{bps_max_length
} || 1,
5457 $drive->{bps_rd_max_length
} || 1,
5458 $drive->{bps_wr_max_length
} || 1,
5459 $drive->{iops_max_length
} || 1,
5460 $drive->{iops_rd_max_length
} || 1,
5461 $drive->{iops_wr_max_length
} || 1,
5471 if ($drive->{file
} eq 'none') {
5472 mon_cmd
($vmid, "eject", force
=> JSON
::true
, id
=> "$opt");
5473 if (drive_is_cloudinit
($old_drive)) {
5474 vmconfig_register_unused_drive
($storecfg, $vmid, $conf, $old_drive);
5477 my $path = get_iso_path
($storecfg, $vmid, $drive->{file
});
5479 # force eject if locked
5480 mon_cmd
($vmid, "eject", force
=> JSON
::true
, id
=> "$opt");
5483 mon_cmd
($vmid, "blockdev-change-medium",
5484 id
=> "$opt", filename
=> "$path");
5492 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5494 PVE
::Storage
::activate_volumes
($storecfg, [$drive->{file
}]) if $drive->{file
} !~ m
|^/dev/.+|;
5495 vm_deviceplug
($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5498 sub vmconfig_update_cloudinit_drive
{
5499 my ($storecfg, $conf, $vmid) = @_;
5501 my $cloudinit_ds = undef;
5502 my $cloudinit_drive = undef;
5504 PVE
::QemuConfig-
>foreach_volume($conf, sub {
5505 my ($ds, $drive) = @_;
5506 if (PVE
::QemuServer
::drive_is_cloudinit
($drive)) {
5507 $cloudinit_ds = $ds;
5508 $cloudinit_drive = $drive;
5512 return if !$cloudinit_drive;
5514 if (PVE
::QemuServer
::Cloudinit
::apply_cloudinit_config
($conf, $vmid)) {
5515 PVE
::QemuConfig-
>write_config($vmid, $conf);
5518 my $running = PVE
::QemuServer
::check_running
($vmid);
5521 my $path = PVE
::Storage
::path
($storecfg, $cloudinit_drive->{file
});
5523 mon_cmd
($vmid, "eject", force
=> JSON
::true
, id
=> "$cloudinit_ds");
5524 mon_cmd
($vmid, "blockdev-change-medium", id
=> "$cloudinit_ds", filename
=> "$path");
5529 # called in locked context by incoming migration
5530 sub vm_migrate_get_nbd_disks
{
5531 my ($storecfg, $conf, $replicated_volumes) = @_;
5533 my $local_volumes = {};
5534 PVE
::QemuConfig-
>foreach_volume($conf, sub {
5535 my ($ds, $drive) = @_;
5537 return if drive_is_cdrom
($drive);
5538 return if $ds eq 'tpmstate0';
5540 my $volid = $drive->{file
};
5544 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid);
5546 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5547 return if $scfg->{shared
};
5549 # replicated disks re-use existing state via bitmap
5550 my $use_existing = $replicated_volumes->{$volid} ?
1 : 0;
5551 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
5553 return $local_volumes;
5556 # called in locked context by incoming migration
5557 sub vm_migrate_alloc_nbd_disks
{
5558 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
5561 foreach my $opt (sort keys %$source_volumes) {
5562 my ($volid, $storeid, $volname, $drive, $use_existing, $format) = @{$source_volumes->{$opt}};
5564 if ($use_existing) {
5565 $nbd->{$opt}->{drivestr
} = print_drive
($drive);
5566 $nbd->{$opt}->{volid
} = $volid;
5567 $nbd->{$opt}->{replicated
} = 1;
5571 # storage mapping + volname = regular migration
5572 # storage mapping + format = remote migration
5573 # order of precedence, filtered by whether storage supports it:
5574 # 1. explicit requested format
5575 # 2. format of current volume
5576 # 3. default format of storage
5577 if (!$storagemap->{identity
}) {
5578 $storeid = PVE
::JSONSchema
::map_id
($storagemap, $storeid);
5579 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5580 if (!$format || !grep { $format eq $_ } @$validFormats) {
5582 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5583 my $fileFormat = qemu_img_format
($scfg, $volname);
5584 $format = $fileFormat
5585 if grep { $fileFormat eq $_ } @$validFormats;
5587 $format //= $defFormat;
5590 # can't happen for remote migration, so $volname is always defined
5591 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5592 $format = qemu_img_format
($scfg, $volname);
5595 my $size = $drive->{size
} / 1024;
5596 my $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $format, undef, $size);
5597 my $newdrive = $drive;
5598 $newdrive->{format
} = $format;
5599 $newdrive->{file
} = $newvolid;
5600 my $drivestr = print_drive
($newdrive);
5601 $nbd->{$opt}->{drivestr
} = $drivestr;
5602 $nbd->{$opt}->{volid
} = $newvolid;
5608 # see vm_start_nolock for parameters, additionally:
5610 # storagemap = parsed storage map for allocating NBD disks
5612 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5614 return PVE
::QemuConfig-
>lock_config($vmid, sub {
5615 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migrate_opts->{migratedfrom
});
5617 die "you can't start a vm if it's a template\n"
5618 if !$params->{skiptemplate
} && PVE
::QemuConfig-
>is_template($conf);
5620 my $has_suspended_lock = PVE
::QemuConfig-
>has_lock($conf, 'suspended');
5621 my $has_backup_lock = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5623 my $running = check_running
($vmid, undef, $migrate_opts->{migratedfrom
});
5625 if ($has_backup_lock && $running) {
5626 # a backup is currently running, attempt to start the guest in the
5627 # existing QEMU instance
5628 return vm_resume
($vmid);
5631 PVE
::QemuConfig-
>check_lock($conf)
5632 if !($params->{skiplock
} || $has_suspended_lock);
5634 $params->{resume
} = $has_suspended_lock || defined($conf->{vmstate
});
5636 die "VM $vmid already running\n" if $running;
5638 if (my $storagemap = $migrate_opts->{storagemap
}) {
5639 my $replicated = $migrate_opts->{replicated_volumes
};
5640 my $disks = vm_migrate_get_nbd_disks
($storecfg, $conf, $replicated);
5641 $migrate_opts->{nbd
} = vm_migrate_alloc_nbd_disks
($storecfg, $vmid, $disks, $storagemap);
5643 foreach my $opt (keys %{$migrate_opts->{nbd
}}) {
5644 $conf->{$opt} = $migrate_opts->{nbd
}->{$opt}->{drivestr
};
5648 return vm_start_nolock
($storecfg, $vmid, $conf, $params, $migrate_opts);
5654 # statefile => 'tcp', 'unix' for migration or path/volid for RAM state
5655 # skiplock => 0/1, skip checking for config lock
5656 # skiptemplate => 0/1, skip checking whether VM is template
5657 # forcemachine => to force QEMU machine (rollback/migration)
5658 # forcecpu => a QEMU '-cpu' argument string to override get_cpu_options
5659 # timeout => in seconds
5660 # paused => start VM in paused state (backup)
5661 # resume => resume from hibernation
5672 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
5673 # migratedfrom => source node
5674 # spice_ticket => used for spice migration, passed via tunnel/stdin
5675 # network => CIDR of migration network
5676 # type => secure/insecure - tunnel over encrypted connection or plain-text
5677 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
5678 # replicated_volumes => which volids should be re-used with bitmaps for nbd migration
5679 # offline_volumes => new volids of offline migrated disks like tpmstate and cloudinit, not yet
5680 # contained in config
5681 sub vm_start_nolock
{
5682 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
5684 my $statefile = $params->{statefile
};
5685 my $resume = $params->{resume
};
5687 my $migratedfrom = $migrate_opts->{migratedfrom
};
5688 my $migration_type = $migrate_opts->{type
};
5692 # clean up leftover reboot request files
5693 eval { clear_reboot_request
($vmid); };
5696 if (!$statefile && scalar(keys %{$conf->{pending
}})) {
5697 vmconfig_apply_pending
($vmid, $conf, $storecfg);
5698 $conf = PVE
::QemuConfig-
>load_config($vmid); # update/reload
5701 # don't regenerate the ISO if the VM is started as part of a live migration
5702 # this way we can reuse the old ISO with the correct config
5703 if (!$migratedfrom) {
5704 if (PVE
::QemuServer
::Cloudinit
::apply_cloudinit_config
($conf, $vmid)) {
5705 # FIXME: apply_cloudinit_config updates $conf in this case, and it would only drop
5706 # $conf->{cloudinit}, so we could just not do this?
5707 # But we do it above, so for now let's be consistent.
5708 $conf = PVE
::QemuConfig-
>load_config($vmid); # update/reload
5712 # override offline migrated volumes, conf is out of date still
5713 if (my $offline_volumes = $migrate_opts->{offline_volumes
}) {
5714 for my $key (sort keys $offline_volumes->%*) {
5715 my $parsed = parse_drive
($key, $conf->{$key});
5716 $parsed->{file
} = $offline_volumes->{$key};
5717 $conf->{$key} = print_drive
($parsed);
5721 my $defaults = load_defaults
();
5723 # set environment variable useful inside network script
5724 # for remote migration the config is available on the target node!
5725 if (!$migrate_opts->{remote_node
}) {
5726 $ENV{PVE_MIGRATED_FROM
} = $migratedfrom;
5729 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-start', 1);
5731 my $forcemachine = $params->{forcemachine
};
5732 my $forcecpu = $params->{forcecpu
};
5734 # enforce machine and CPU type on suspended vm to ensure HW compatibility
5735 $forcemachine = $conf->{runningmachine
};
5736 $forcecpu = $conf->{runningcpu
};
5737 print "Resuming suspended VM\n";
5740 my ($cmd, $vollist, $spice_port, $pci_devices) = config_to_command
($storecfg, $vmid,
5741 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
5744 my $get_migration_ip = sub {
5745 my ($nodename) = @_;
5747 return $migration_ip if defined($migration_ip);
5749 my $cidr = $migrate_opts->{network
};
5751 if (!defined($cidr)) {
5752 my $dc_conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5753 $cidr = $dc_conf->{migration
}->{network
};
5756 if (defined($cidr)) {
5757 my $ips = PVE
::Network
::get_local_ip_from_cidr
($cidr);
5759 die "could not get IP: no address configured on local " .
5760 "node for network '$cidr'\n" if scalar(@$ips) == 0;
5762 die "could not get IP: multiple addresses configured on local " .
5763 "node for network '$cidr'\n" if scalar(@$ips) > 1;
5765 $migration_ip = @$ips[0];
5768 $migration_ip = PVE
::Cluster
::remote_node_ip
($nodename, 1)
5769 if !defined($migration_ip);
5771 return $migration_ip;
5775 if ($statefile eq 'tcp') {
5776 my $migrate = $res->{migrate
} = { proto
=> 'tcp' };
5777 $migrate->{addr
} = "localhost";
5778 my $datacenterconf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5779 my $nodename = nodename
();
5781 if (!defined($migration_type)) {
5782 if (defined($datacenterconf->{migration
}->{type
})) {
5783 $migration_type = $datacenterconf->{migration
}->{type
};
5785 $migration_type = 'secure';
5789 if ($migration_type eq 'insecure') {
5790 $migrate->{addr
} = $get_migration_ip->($nodename);
5791 $migrate->{addr
} = "[$migrate->{addr}]" if Net
::IP
::ip_is_ipv6
($migrate->{addr
});
5794 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5795 $migrate->{port
} = PVE
::Tools
::next_migrate_port
($pfamily);
5796 $migrate->{uri
} = "tcp:$migrate->{addr}:$migrate->{port}";
5797 push @$cmd, '-incoming', $migrate->{uri
};
5800 } elsif ($statefile eq 'unix') {
5801 # should be default for secure migrations as a ssh TCP forward
5802 # tunnel is not deterministic reliable ready and fails regurarly
5803 # to set up in time, so use UNIX socket forwards
5804 my $migrate = $res->{migrate
} = { proto
=> 'unix' };
5805 $migrate->{addr
} = "/run/qemu-server/$vmid.migrate";
5806 unlink $migrate->{addr
};
5808 $migrate->{uri
} = "unix:$migrate->{addr}";
5809 push @$cmd, '-incoming', $migrate->{uri
};
5812 } elsif (-e
$statefile) {
5813 push @$cmd, '-loadstate', $statefile;
5815 my $statepath = PVE
::Storage
::path
($storecfg, $statefile);
5816 push @$vollist, $statefile;
5817 push @$cmd, '-loadstate', $statepath;
5819 } elsif ($params->{paused
}) {
5823 my $start_timeout = $params->{timeout
} // config_aware_timeout
($conf, $resume);
5825 my $pci_reserve_list = [];
5826 for my $device (values $pci_devices->%*) {
5827 next if $device->{mdev
}; # we don't reserve for mdev devices
5828 push $pci_reserve_list->@*, map { $_->{id
} } $device->{ids
}->@*;
5831 # reserve all PCI IDs before actually doing anything with them
5832 PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_reserve_list, $vmid, $start_timeout);
5836 for my $id (sort keys %$pci_devices) {
5837 my $d = $pci_devices->{$id};
5838 my ($index) = ($id =~ m/^hostpci(\d+)$/);
5841 for my $dev ($d->{ids
}->@*) {
5842 my $info = eval { PVE
::QemuServer
::PCI
::prepare_pci_device
($vmid, $dev->{id
}, $index, $d->{mdev
}) };
5845 $chosen_mdev = $info;
5846 last if $chosen_mdev; # if successful, we're done
5852 next if !$d->{mdev
};
5853 die "could not create mediated device\n" if !defined($chosen_mdev);
5855 # nvidia grid needs the uuid of the mdev as qemu parameter
5856 if (!defined($uuid) && $chosen_mdev->{vendor
} =~ m/^(0x)?10de$/) {
5857 if (defined($conf->{smbios1
})) {
5858 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
5859 $uuid = $smbios_conf->{uuid
} if defined($smbios_conf->{uuid
});
5861 $uuid = PVE
::QemuServer
::PCI
::generate_mdev_uuid
($vmid, $index) if !defined($uuid);
5864 push @$cmd, '-uuid', $uuid if defined($uuid);
5867 eval { cleanup_pci_devices
($vmid, $conf) };
5872 PVE
::Storage
::activate_volumes
($storecfg, $vollist);
5875 run_command
(['/bin/systemctl', 'stop', "$vmid.scope"], outfunc
=> sub{}, errfunc
=> sub{});
5877 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5878 # timeout should be more than enough here...
5879 PVE
::Systemd
::wait_for_unit_removed
("$vmid.scope", 20);
5881 my $cpuunits = PVE
::CGroup
::clamp_cpu_shares
($conf->{cpuunits
});
5884 timeout
=> $statefile ?
undef : $start_timeout,
5889 # when migrating, prefix QEMU output so other side can pick up any
5890 # errors that might occur and show the user
5891 if ($migratedfrom) {
5892 $run_params{quiet
} = 1;
5893 $run_params{logfunc
} = sub { print "QEMU: $_[0]\n" };
5896 my %systemd_properties = (
5897 Slice
=> 'qemu.slice',
5898 KillMode
=> 'process',
5900 TimeoutStopUSec
=> ULONG_MAX
, # infinity
5903 if (PVE
::CGroup
::cgroup_mode
() == 2) {
5904 $systemd_properties{CPUWeight
} = $cpuunits;
5906 $systemd_properties{CPUShares
} = $cpuunits;
5909 if (my $cpulimit = $conf->{cpulimit
}) {
5910 $systemd_properties{CPUQuota
} = int($cpulimit * 100);
5912 $systemd_properties{timeout
} = 10 if $statefile; # setting up the scope shoul be quick
5914 my $run_qemu = sub {
5915 PVE
::Tools
::run_fork
sub {
5916 PVE
::Systemd
::enter_systemd_scope
($vmid, "Proxmox VE VM $vmid", %systemd_properties);
5919 if (my $tpm = $conf->{tpmstate0
}) {
5920 # start the TPM emulator so QEMU can connect on start
5921 $tpmpid = start_swtpm
($storecfg, $vmid, $tpm, $migratedfrom);
5924 my $exitcode = run_command
($cmd, %run_params);
5927 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
5928 kill 'TERM', $tpmpid;
5930 die "QEMU exited with code $exitcode\n";
5935 if ($conf->{hugepages
}) {
5938 my $hotplug_features =
5939 parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
5940 my $hugepages_topology =
5941 PVE
::QemuServer
::Memory
::hugepages_topology
($conf, $hotplug_features->{memory
});
5943 my $hugepages_host_topology = PVE
::QemuServer
::Memory
::hugepages_host_topology
();
5945 PVE
::QemuServer
::Memory
::hugepages_mount
();
5946 PVE
::QemuServer
::Memory
::hugepages_allocate
($hugepages_topology, $hugepages_host_topology);
5948 eval { $run_qemu->() };
5950 PVE
::QemuServer
::Memory
::hugepages_reset
($hugepages_host_topology)
5951 if !$conf->{keephugepages
};
5955 PVE
::QemuServer
::Memory
::hugepages_pre_deallocate
($hugepages_topology)
5956 if !$conf->{keephugepages
};
5958 eval { PVE
::QemuServer
::Memory
::hugepages_update_locked
($code); };
5961 eval { $run_qemu->() };
5965 # deactivate volumes if start fails
5966 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
5968 eval { cleanup_pci_devices
($vmid, $conf) };
5971 die "start failed: $err";
5974 # re-reserve all PCI IDs now that we can know the actual VM PID
5975 my $pid = PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
5976 eval { PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_reserve_list, $vmid, undef, $pid) };
5979 if (defined($res->{migrate
})) {
5980 print "migration listens on $res->{migrate}->{uri}\n";
5981 } elsif ($statefile) {
5982 eval { mon_cmd
($vmid, "cont"); };
5986 #start nbd server for storage migration
5987 if (my $nbd = $migrate_opts->{nbd
}) {
5988 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version
} // 0;
5990 my $migrate_storage_uri;
5991 # nbd_protocol_version > 0 for unix socket support
5992 if ($nbd_protocol_version > 0 && ($migration_type eq 'secure' || $migration_type eq 'websocket')) {
5993 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5994 mon_cmd
($vmid, "nbd-server-start", addr
=> { type
=> 'unix', data
=> { path
=> $socket_path } } );
5995 $migrate_storage_uri = "nbd:unix:$socket_path";
5996 $res->{migrate
}->{unix_sockets
} = [$socket_path];
5998 my $nodename = nodename
();
5999 my $localip = $get_migration_ip->($nodename);
6000 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
6001 my $storage_migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
6003 mon_cmd
($vmid, "nbd-server-start", addr
=> {
6006 host
=> "${localip}",
6007 port
=> "${storage_migrate_port}",
6010 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
6011 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
6014 my $block_info = mon_cmd
($vmid, "query-block");
6015 $block_info = { map { $_->{device
} => $_ } $block_info->@* };
6017 foreach my $opt (sort keys %$nbd) {
6018 my $drivestr = $nbd->{$opt}->{drivestr
};
6019 my $volid = $nbd->{$opt}->{volid
};
6021 my $block_node = $block_info->{"drive-$opt"}->{inserted
}->{'node-name'};
6027 'node-name' => $block_node,
6028 writable
=> JSON
::true
,
6030 name
=> "drive-$opt", # NBD export name
6033 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
6034 print "storage migration listens on $nbd_uri volume:$drivestr\n";
6035 print "re-using replicated volume: $opt - $volid\n"
6036 if $nbd->{$opt}->{replicated
};
6038 $res->{drives
}->{$opt} = $nbd->{$opt};
6039 $res->{drives
}->{$opt}->{nbd_uri
} = $nbd_uri;
6043 if ($migratedfrom) {
6045 set_migration_caps
($vmid);
6050 print "spice listens on port $spice_port\n";
6051 $res->{spice_port
} = $spice_port;
6052 if ($migrate_opts->{spice_ticket
}) {
6053 mon_cmd
($vmid, "set_password", protocol
=> 'spice', password
=>
6054 $migrate_opts->{spice_ticket
});
6055 mon_cmd
($vmid, "expire_password", protocol
=> 'spice', time => "+30");
6060 mon_cmd
($vmid, "balloon", value
=> $conf->{balloon
}*1024*1024)
6061 if !$statefile && $conf->{balloon
};
6063 foreach my $opt (keys %$conf) {
6064 next if $opt !~ m/^net\d+$/;
6065 my $nicconf = parse_net
($conf->{$opt});
6066 qemu_set_link_status
($vmid, $opt, 0) if $nicconf->{link_down
};
6068 add_nets_bridge_fdb
($conf, $vmid);
6071 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
6076 path
=> "machine/peripheral/balloon0",
6077 property
=> "guest-stats-polling-interval",
6081 log_warn
("could not set polling interval for ballooning - $@") if $@;
6085 print "Resumed VM, removing state\n";
6086 if (my $vmstate = $conf->{vmstate
}) {
6087 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
6088 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
6090 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
6091 PVE
::QemuConfig-
>write_config($vmid, $conf);
6094 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
6099 sub vm_commandline
{
6100 my ($storecfg, $vmid, $snapname) = @_;
6102 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6104 my ($forcemachine, $forcecpu);
6106 my $snapshot = $conf->{snapshots
}->{$snapname};
6107 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
6109 # check for machine or CPU overrides in snapshot
6110 $forcemachine = $snapshot->{runningmachine
};
6111 $forcecpu = $snapshot->{runningcpu
};
6113 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
6118 my $defaults = load_defaults
();
6120 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu);
6122 return PVE
::Tools
::cmd2string
($cmd);
6126 my ($vmid, $skiplock) = @_;
6128 PVE
::QemuConfig-
>lock_config($vmid, sub {
6130 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6132 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
6134 mon_cmd
($vmid, "system_reset");
6138 sub get_vm_volumes
{
6142 foreach_volid
($conf, sub {
6143 my ($volid, $attr) = @_;
6145 return if $volid =~ m
|^/|;
6147 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6150 push @$vollist, $volid;
6156 sub cleanup_pci_devices
{
6157 my ($vmid, $conf) = @_;
6159 foreach my $key (keys %$conf) {
6160 next if $key !~ m/^hostpci(\d+)$/;
6161 my $hostpciindex = $1;
6162 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
6163 my $d = parse_hostpci
($conf->{$key});
6165 # NOTE: avoid PVE::SysFSTools::pci_cleanup_mdev_device as it requires PCI ID and we
6166 # don't want to break ABI just for this two liner
6167 my $dev_sysfs_dir = "/sys/bus/mdev/devices/$uuid";
6169 # some nvidia vgpu driver versions want to clean the mdevs up themselves, and error
6170 # out when we do it first. so wait for 10 seconds and then try it
6171 if ($d->{ids
}->[0]->[0]->{vendor
} =~ m/^(0x)?10de$/) {
6175 PVE
::SysFSTools
::file_write
("$dev_sysfs_dir/remove", "1") if -e
$dev_sysfs_dir;
6178 PVE
::QemuServer
::PCI
::remove_pci_reservation
($vmid);
6181 sub vm_stop_cleanup
{
6182 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
6187 my $vollist = get_vm_volumes
($conf);
6188 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
6190 if (my $tpmdrive = $conf->{tpmstate0
}) {
6191 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
6192 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
6194 PVE
::Storage
::unmap_volume
($storecfg, $tpm->{file
});
6199 foreach my $ext (qw(mon qmp pid vnc qga)) {
6200 unlink "/var/run/qemu-server/${vmid}.$ext";
6203 if ($conf->{ivshmem
}) {
6204 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
6205 # just delete it for now, VMs which have this already open do not
6206 # are affected, but new VMs will get a separated one. If this
6207 # becomes an issue we either add some sort of ref-counting or just
6208 # add a "don't delete on stop" flag to the ivshmem format.
6209 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
6212 cleanup_pci_devices
($vmid, $conf);
6214 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
6216 warn $@ if $@; # avoid errors - just warn
6219 # call only in locked context
6221 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
6223 my $pid = check_running
($vmid, $nocheck);
6228 $conf = PVE
::QemuConfig-
>load_config($vmid);
6229 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
6230 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
6231 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
6232 $timeout = $opts->{down
} if $opts->{down
};
6234 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
6239 if (defined($conf) && get_qga_key
($conf, 'enabled')) {
6240 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
6242 mon_cmd
($vmid, "system_powerdown");
6245 mon_cmd
($vmid, "quit");
6251 $timeout = 60 if !defined($timeout);
6254 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
6259 if ($count >= $timeout) {
6261 warn "VM still running - terminating now with SIGTERM\n";
6264 die "VM quit/powerdown failed - got timeout\n";
6267 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
6271 if (!check_running
($vmid, $nocheck)) {
6272 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
6276 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
6279 die "VM quit/powerdown failed\n";
6287 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
6292 if ($count >= $timeout) {
6293 warn "VM still running - terminating now with SIGKILL\n";
6298 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
6301 # Note: use $nocheck to skip tests if VM configuration file exists.
6302 # We need that when migration VMs to other nodes (files already moved)
6303 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
6305 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
6307 $force = 1 if !defined($force) && !$shutdown;
6310 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
6311 kill 15, $pid if $pid;
6312 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
6313 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
6317 PVE
::QemuConfig-
>lock_config($vmid, sub {
6318 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
6323 my ($vmid, $timeout) = @_;
6325 PVE
::QemuConfig-
>lock_config($vmid, sub {
6328 # only reboot if running, as qmeventd starts it again on a stop event
6329 return if !check_running
($vmid);
6331 create_reboot_request
($vmid);
6333 my $storecfg = PVE
::Storage
::config
();
6334 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
6338 # avoid that the next normal shutdown will be confused for a reboot
6339 clear_reboot_request
($vmid);
6345 # note: if using the statestorage parameter, the caller has to check privileges
6347 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
6354 PVE
::QemuConfig-
>lock_config($vmid, sub {
6356 $conf = PVE
::QemuConfig-
>load_config($vmid);
6358 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
6359 PVE
::QemuConfig-
>check_lock($conf)
6360 if !($skiplock || $is_backing_up);
6362 die "cannot suspend to disk during backup\n"
6363 if $is_backing_up && $includestate;
6365 if ($includestate) {
6366 $conf->{lock} = 'suspending';
6367 my $date = strftime
("%Y-%m-%d", localtime(time()));
6368 $storecfg = PVE
::Storage
::config
();
6369 if (!$statestorage) {
6370 $statestorage = find_vmstate_storage
($conf, $storecfg);
6371 # check permissions for the storage
6372 my $rpcenv = PVE
::RPCEnvironment
::get
();
6373 if ($rpcenv->{type
} ne 'cli') {
6374 my $authuser = $rpcenv->get_user();
6375 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
6380 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate(
6381 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
6382 $path = PVE
::Storage
::path
($storecfg, $vmstate);
6383 PVE
::QemuConfig-
>write_config($vmid, $conf);
6385 mon_cmd
($vmid, "stop");
6389 if ($includestate) {
6391 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
6394 set_migration_caps
($vmid, 1);
6395 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
6397 my $state = mon_cmd
($vmid, "query-savevm");
6398 if (!$state->{status
}) {
6399 die "savevm not active\n";
6400 } elsif ($state->{status
} eq 'active') {
6403 } elsif ($state->{status
} eq 'completed') {
6404 print "State saved, quitting\n";
6406 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
6407 die "query-savevm failed with error '$state->{error}'\n"
6409 die "query-savevm returned status '$state->{status}'\n";
6415 PVE
::QemuConfig-
>lock_config($vmid, sub {
6416 $conf = PVE
::QemuConfig-
>load_config($vmid);
6418 # cleanup, but leave suspending lock, to indicate something went wrong
6420 mon_cmd
($vmid, "savevm-end");
6421 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
6422 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
6423 delete $conf->@{qw(vmstate runningmachine runningcpu)};
6424 PVE
::QemuConfig-
>write_config($vmid, $conf);
6430 die "lock changed unexpectedly\n"
6431 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
6433 mon_cmd
($vmid, "quit");
6434 $conf->{lock} = 'suspended';
6435 PVE
::QemuConfig-
>write_config($vmid, $conf);
6440 # $nocheck is set when called as part of a migration - in this context the
6441 # location of the config file (source or target node) is not deterministic,
6442 # since migration cannot wait for pmxcfs to process the rename
6444 my ($vmid, $skiplock, $nocheck) = @_;
6446 PVE
::QemuConfig-
>lock_config($vmid, sub {
6447 my $res = mon_cmd
($vmid, 'query-status');
6448 my $resume_cmd = 'cont';
6452 $conf = eval { PVE
::QemuConfig-
>load_config($vmid) }; # try on target node
6454 my $vmlist = PVE
::Cluster
::get_vmlist
();
6455 if (exists($vmlist->{ids
}->{$vmid})) {
6456 my $node = $vmlist->{ids
}->{$vmid}->{node
};
6457 $conf = eval { PVE
::QemuConfig-
>load_config($vmid, $node) }; # try on source node
6460 PVE
::Cluster
::cfs_update
(); # vmlist was wrong, invalidate cache
6461 $conf = PVE
::QemuConfig-
>load_config($vmid); # last try on target node again
6465 $conf = PVE
::QemuConfig-
>load_config($vmid);
6468 if ($res->{status
}) {
6469 return if $res->{status
} eq 'running'; # job done, go home
6470 $resume_cmd = 'system_wakeup' if $res->{status
} eq 'suspended';
6471 $reset = 1 if $res->{status
} eq 'shutdown';
6475 PVE
::QemuConfig-
>check_lock($conf)
6476 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
6480 # required if a VM shuts down during a backup and we get a resume
6481 # request before the backup finishes for example
6482 mon_cmd
($vmid, "system_reset");
6485 add_nets_bridge_fdb
($conf, $vmid) if $resume_cmd eq 'cont';
6487 mon_cmd
($vmid, $resume_cmd);
6492 my ($vmid, $skiplock, $key) = @_;
6494 PVE
::QemuConfig-
>lock_config($vmid, sub {
6496 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6498 # there is no qmp command, so we use the human monitor command
6499 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
6500 die $res if $res ne '';
6504 sub check_bridge_access
{
6505 my ($rpcenv, $authuser, $conf) = @_;
6507 return 1 if $authuser eq 'root@pam';
6509 for my $opt (sort keys $conf->%*) {
6510 next if $opt !~ m/^net\d+$/;
6511 my $net = parse_net
($conf->{$opt});
6512 my ($bridge, $tag, $trunks) = $net->@{'bridge', 'tag', 'trunks'};
6513 PVE
::GuestHelpers
::check_vnet_access
($rpcenv, $authuser, $bridge, $tag, $trunks);
6518 sub check_mapping_access
{
6519 my ($rpcenv, $user, $conf) = @_;
6521 for my $opt (keys $conf->%*) {
6522 if ($opt =~ m/^usb\d+$/) {
6523 my $device = PVE
::JSONSchema
::parse_property_string
('pve-qm-usb', $conf->{$opt});
6524 if (my $host = $device->{host
}) {
6525 die "only root can set '$opt' config for real devices\n"
6526 if $host !~ m/^spice$/i && $user ne 'root@pam';
6527 } elsif ($device->{mapping
}) {
6528 $rpcenv->check_full($user, "/mapping/usb/$device->{mapping}", ['Mapping.Use']);
6530 die "either 'host' or 'mapping' must be set.\n";
6532 } elsif ($opt =~ m/^hostpci\d+$/) {
6533 my $device = PVE
::JSONSchema
::parse_property_string
('pve-qm-hostpci', $conf->{$opt});
6534 if ($device->{host
}) {
6535 die "only root can set '$opt' config for non-mapped devices\n" if $user ne 'root@pam';
6536 } elsif ($device->{mapping
}) {
6537 $rpcenv->check_full($user, "/mapping/pci/$device->{mapping}", ['Mapping.Use']);
6539 die "either 'host' or 'mapping' must be set.\n";
6545 # FIXME: improve checks on restore by checking before actually extracing and
6546 # merging the new config
6547 sub check_restore_permissions
{
6548 my ($rpcenv, $user, $conf) = @_;
6549 check_bridge_access
($rpcenv, $user, $conf);
6550 check_mapping_access
($rpcenv, $user, $conf);
6552 # vzdump restore implementaion
6554 sub tar_archive_read_firstfile
{
6555 my $archive = shift;
6557 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
6559 # try to detect archive type first
6560 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
6561 die "unable to open file '$archive'\n";
6562 my $firstfile = <$fh>;
6566 die "ERROR: archive contaions no data\n" if !$firstfile;
6572 sub tar_restore_cleanup
{
6573 my ($storecfg, $statfile) = @_;
6575 print STDERR
"starting cleanup\n";
6577 if (my $fd = IO
::File-
>new($statfile, "r")) {
6578 while (defined(my $line = <$fd>)) {
6579 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6582 if ($volid =~ m
|^/|) {
6583 unlink $volid || die 'unlink failed\n';
6585 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6587 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6589 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6591 print STDERR
"unable to parse line in statfile - $line";
6598 sub restore_file_archive
{
6599 my ($archive, $vmid, $user, $opts) = @_;
6601 return restore_vma_archive
($archive, $vmid, $user, $opts)
6604 my $info = PVE
::Storage
::archive_info
($archive);
6605 my $format = $opts->{format
} // $info->{format
};
6606 my $comp = $info->{compression
};
6608 # try to detect archive format
6609 if ($format eq 'tar') {
6610 return restore_tar_archive
($archive, $vmid, $user, $opts);
6612 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
6616 # hepler to remove disks that will not be used after restore
6617 my $restore_cleanup_oldconf = sub {
6618 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6620 my $kept_disks = {};
6622 PVE
::QemuConfig-
>foreach_volume($oldconf, sub {
6623 my ($ds, $drive) = @_;
6625 return if drive_is_cdrom
($drive, 1);
6627 my $volid = $drive->{file
};
6628 return if !$volid || $volid =~ m
|^/|;
6630 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
6631 return if !$path || !$owner || ($owner != $vmid);
6633 # Note: only delete disk we want to restore
6634 # other volumes will become unused
6635 if ($virtdev_hash->{$ds}) {
6636 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
6641 $kept_disks->{$volid} = 1;
6645 # after the restore we have no snapshots anymore
6646 for my $snapname (keys $oldconf->{snapshots
}->%*) {
6647 my $snap = $oldconf->{snapshots
}->{$snapname};
6648 if ($snap->{vmstate
}) {
6649 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
6655 for my $volid (keys $kept_disks->%*) {
6656 eval { PVE
::Storage
::volume_snapshot_delete
($storecfg, $volid, $snapname); };
6662 # Helper to parse vzdump backup device hints
6664 # $rpcenv: Environment, used to ckeck storage permissions
6665 # $user: User ID, to check storage permissions
6666 # $storecfg: Storage configuration
6667 # $fh: the file handle for reading the configuration
6668 # $devinfo: should contain device sizes for all backu-up'ed devices
6669 # $options: backup options (pool, default storage)
6671 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6672 my $parse_backup_hints = sub {
6673 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
6675 my $check_storage = sub { # assert if an image can be allocate
6676 my ($storeid, $scfg) = @_;
6677 die "Content type 'images' is not available on storage '$storeid'\n"
6678 if !$scfg->{content
}->{images
};
6679 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace'])
6680 if $user ne 'root@pam';
6683 my $virtdev_hash = {};
6684 while (defined(my $line = <$fh>)) {
6685 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6686 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6687 die "archive does not contain data for drive '$virtdev'\n"
6688 if !$devinfo->{$devname};
6690 if (defined($options->{storage
})) {
6691 $storeid = $options->{storage
} || 'local';
6692 } elsif (!$storeid) {
6695 $format = 'raw' if !$format;
6696 $devinfo->{$devname}->{devname
} = $devname;
6697 $devinfo->{$devname}->{virtdev
} = $virtdev;
6698 $devinfo->{$devname}->{format
} = $format;
6699 $devinfo->{$devname}->{storeid
} = $storeid;
6701 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6702 $check_storage->($storeid, $scfg); # permission and content type check
6704 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6705 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6707 my $drive = parse_drive
($virtdev, $2);
6709 if (drive_is_cloudinit
($drive)) {
6710 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6711 $storeid = $options->{storage
} if defined ($options->{storage
});
6712 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6713 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
6715 $check_storage->($storeid, $scfg); # permission and content type check
6717 $virtdev_hash->{$virtdev} = {
6719 storeid
=> $storeid,
6720 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6727 return $virtdev_hash;
6730 # Helper to allocate and activate all volumes required for a restore
6732 # $storecfg: Storage configuration
6733 # $virtdev_hash: as returned by parse_backup_hints()
6735 # Returns: { $virtdev => $volid }
6736 my $restore_allocate_devices = sub {
6737 my ($storecfg, $virtdev_hash, $vmid) = @_;
6740 foreach my $virtdev (sort keys %$virtdev_hash) {
6741 my $d = $virtdev_hash->{$virtdev};
6742 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6743 my $storeid = $d->{storeid
};
6744 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6746 # test if requested format is supported
6747 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6748 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6749 $d->{format
} = $defFormat if !$supported;
6752 if ($d->{is_cloudinit
}) {
6753 $name = "vm-$vmid-cloudinit";
6754 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6755 if ($scfg->{path
}) {
6756 $name .= ".$d->{format}";
6760 my $volid = PVE
::Storage
::vdisk_alloc
(
6761 $storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6763 print STDERR
"new volume ID is '$volid'\n";
6764 $d->{volid
} = $volid;
6766 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6768 $map->{$virtdev} = $volid;
6774 sub restore_update_config_line
{
6775 my ($cookie, $map, $line, $unique) = @_;
6777 return '' if $line =~ m/^\#qmdump\#/;
6778 return '' if $line =~ m/^\#vzdump\#/;
6779 return '' if $line =~ m/^lock:/;
6780 return '' if $line =~ m/^unused\d+:/;
6781 return '' if $line =~ m/^parent:/;
6785 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
6786 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6787 # try to convert old 1.X settings
6788 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6789 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
6790 my ($model, $macaddr) = split(/\=/, $devconfig);
6791 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
6794 bridge
=> "vmbr$ind",
6795 macaddr
=> $macaddr,
6797 my $netstr = print_net
($net);
6799 $res .= "net$cookie->{netcount}: $netstr\n";
6800 $cookie->{netcount
}++;
6802 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6803 my ($id, $netstr) = ($1, $2);
6804 my $net = parse_net
($netstr);
6805 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
6806 $netstr = print_net
($net);
6807 $res .= "$id: $netstr\n";
6808 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
6811 my $di = parse_drive
($virtdev, $value);
6812 if (defined($di->{backup
}) && !$di->{backup
}) {
6814 } elsif ($map->{$virtdev}) {
6815 delete $di->{format
}; # format can change on restore
6816 $di->{file
} = $map->{$virtdev};
6817 $value = print_drive
($di);
6818 $res .= "$virtdev: $value\n";
6822 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6824 if ($vmgenid ne '0') {
6825 # always generate a new vmgenid if there was a valid one setup
6826 $vmgenid = generate_uuid
();
6828 $res .= "vmgenid: $vmgenid\n";
6829 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6830 my ($uuid, $uuid_str);
6831 UUID
::generate
($uuid);
6832 UUID
::unparse
($uuid, $uuid_str);
6833 my $smbios1 = parse_smbios1
($2);
6834 $smbios1->{uuid
} = $uuid_str;
6835 $res .= $1.print_smbios1
($smbios1)."\n";
6843 my $restore_deactivate_volumes = sub {
6844 my ($storecfg, $virtdev_hash) = @_;
6847 for my $dev (values $virtdev_hash->%*) {
6848 push $vollist->@*, $dev->{volid
} if $dev->{volid
};
6851 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
6852 print STDERR
$@ if $@;
6855 my $restore_destroy_volumes = sub {
6856 my ($storecfg, $virtdev_hash) = @_;
6858 for my $dev (values $virtdev_hash->%*) {
6859 my $volid = $dev->{volid
} or next;
6861 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6862 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6864 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6868 my $restore_merge_config = sub {
6869 my ($filename, $backup_conf_raw, $override_conf) = @_;
6871 my $backup_conf = parse_vm_config
($filename, $backup_conf_raw);
6872 for my $key (keys $override_conf->%*) {
6873 $backup_conf->{$key} = $override_conf->{$key};
6876 return $backup_conf;
6880 my ($cfg, $vmid) = @_;
6882 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid, undef, 'images');
6884 my $volid_hash = {};
6885 foreach my $storeid (keys %$info) {
6886 foreach my $item (@{$info->{$storeid}}) {
6887 next if !($item->{volid
} && $item->{size
});
6888 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6889 $volid_hash->{$item->{volid
}} = $item;
6896 sub update_disk_config
{
6897 my ($vmid, $conf, $volid_hash) = @_;
6900 my $prefix = "VM $vmid";
6902 # used and unused disks
6903 my $referenced = {};
6905 # Note: it is allowed to define multiple storages with same path (alias), so
6906 # we need to check both 'volid' and real 'path' (two different volid can point
6907 # to the same path).
6909 my $referencedpath = {};
6912 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6913 my ($opt, $drive) = @_;
6915 my $volid = $drive->{file
};
6917 my $volume = $volid_hash->{$volid};
6919 # mark volid as "in-use" for next step
6920 $referenced->{$volid} = 1;
6921 if ($volume && (my $path = $volume->{path
})) {
6922 $referencedpath->{$path} = 1;
6925 return if drive_is_cdrom
($drive);
6928 my ($updated, $msg) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volume->{size
});
6929 if (defined($updated)) {
6931 $conf->{$opt} = print_drive
($updated);
6932 print "$prefix ($opt): $msg\n";
6936 # remove 'unusedX' entry if volume is used
6937 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
6938 my ($opt, $drive) = @_;
6940 my $volid = $drive->{file
};
6944 $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6945 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6946 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
6948 delete $conf->{$opt};
6951 $referenced->{$volid} = 1;
6952 $referencedpath->{$path} = 1 if $path;
6955 foreach my $volid (sort keys %$volid_hash) {
6956 next if $volid =~ m/vm-$vmid-state-/;
6957 next if $referenced->{$volid};
6958 my $path = $volid_hash->{$volid}->{path
};
6959 next if !$path; # just to be sure
6960 next if $referencedpath->{$path};
6962 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6963 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
6964 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6971 my ($vmid, $nolock, $dryrun) = @_;
6973 my $cfg = PVE
::Storage
::config
();
6975 print "rescan volumes...\n";
6976 my $volid_hash = scan_volids
($cfg, $vmid);
6978 my $updatefn = sub {
6981 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6983 PVE
::QemuConfig-
>check_lock($conf);
6986 foreach my $volid (keys %$volid_hash) {
6987 my $info = $volid_hash->{$volid};
6988 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6991 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
6993 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6996 if (defined($vmid)) {
7000 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
7003 my $vmlist = config_list
();
7004 foreach my $vmid (keys %$vmlist) {
7008 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
7014 sub restore_proxmox_backup_archive
{
7015 my ($archive, $vmid, $user, $options) = @_;
7017 my $storecfg = PVE
::Storage
::config
();
7019 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
7020 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7022 my $fingerprint = $scfg->{fingerprint
};
7023 my $keyfile = PVE
::Storage
::PBSPlugin
::pbs_encryption_key_file_name
($storecfg, $storeid);
7025 my $repo = PVE
::PBSClient
::get_repository
($scfg);
7026 my $namespace = $scfg->{namespace
};
7028 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
7029 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
7030 local $ENV{PBS_PASSWORD
} = $password;
7031 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
7033 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
7034 PVE
::Storage
::parse_volname
($storecfg, $archive);
7036 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
7038 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
7040 my $tmpdir = "/var/tmp/vzdumptmp$$";
7044 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
7045 # disable interrupts (always do cleanups)
7049 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
7051 # Note: $oldconf is undef if VM does not exists
7052 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
7053 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
7054 my $new_conf_raw = '';
7056 my $rpcenv = PVE
::RPCEnvironment
::get
();
7057 my $devinfo = {}; # info about drives included in backup
7058 my $virtdev_hash = {}; # info about allocated drives
7066 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
7068 my $cfgfn = "$tmpdir/qemu-server.conf";
7069 my $firewall_config_fn = "$tmpdir/fw.conf";
7070 my $index_fn = "$tmpdir/index.json";
7072 my $cmd = "restore";
7074 my $param = [$pbs_backup_name, "index.json", $index_fn];
7075 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
7076 my $index = PVE
::Tools
::file_get_contents
($index_fn);
7077 $index = decode_json
($index);
7079 foreach my $info (@{$index->{files
}}) {
7080 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
7082 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
7083 $devinfo->{$devname}->{size
} = $1;
7085 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
7090 my $is_qemu_server_backup = scalar(
7091 grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}}
7093 if (!$is_qemu_server_backup) {
7094 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
7096 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
7098 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
7099 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
7101 if ($has_firewall_config) {
7102 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
7103 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
7105 my $pve_firewall_dir = '/etc/pve/firewall';
7106 mkdir $pve_firewall_dir; # make sure the dir exists
7107 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
7110 my $fh = IO
::File-
>new($cfgfn, "r") ||
7111 die "unable to read qemu-server.conf - $!\n";
7113 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
7115 # fixme: rate limit?
7117 # create empty/temp config
7118 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
7120 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
7123 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
7125 foreach my $virtdev (sort keys %$virtdev_hash) {
7126 my $d = $virtdev_hash->{$virtdev};
7127 next if $d->{is_cloudinit
}; # no need to restore cloudinit
7129 # this fails if storage is unavailable
7130 my $volid = $d->{volid
};
7131 my $path = PVE
::Storage
::path
($storecfg, $volid);
7133 # for live-restore we only want to preload the efidisk and TPM state
7134 next if $options->{live
} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
7137 if (defined(my $ns = $scfg->{namespace
})) {
7138 @ns_arg = ('--ns', $ns);
7141 my $pbs_restore_cmd = [
7142 '/usr/bin/pbs-restore',
7143 '--repository', $repo,
7146 "$d->{devname}.img.fidx",
7151 push @$pbs_restore_cmd, '--format', $d->{format
} if $d->{format
};
7152 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e
$keyfile;
7154 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
7155 push @$pbs_restore_cmd, '--skip-zero';
7158 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
7159 print "restore proxmox backup image: $dbg_cmdstring\n";
7160 run_command
($pbs_restore_cmd);
7163 $fh->seek(0, 0) || die "seek failed - $!\n";
7165 my $cookie = { netcount
=> 0 };
7166 while (defined(my $line = <$fh>)) {
7167 $new_conf_raw .= restore_update_config_line
(
7179 if ($err || !$options->{live
}) {
7180 $restore_deactivate_volumes->($storecfg, $virtdev_hash);
7186 $restore_destroy_volumes->($storecfg, $virtdev_hash);
7190 if ($options->{live
}) {
7191 # keep lock during live-restore
7192 $new_conf_raw .= "\nlock: create";
7195 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $options->{override_conf
});
7196 check_restore_permissions
($rpcenv, $user, $new_conf);
7197 PVE
::QemuConfig-
>write_config($vmid, $new_conf);
7199 eval { rescan
($vmid, 1); };
7202 PVE
::AccessControl
::add_vm_to_pool
($vmid, $options->{pool
}) if $options->{pool
};
7204 if ($options->{live
}) {
7210 local $SIG{PIPE
} = sub { die "got signal ($!) - abort\n"; };
7212 my $conf = PVE
::QemuConfig-
>load_config($vmid);
7213 die "cannot do live-restore for template\n" if PVE
::QemuConfig-
>is_template($conf);
7215 # these special drives are already restored before start
7216 delete $devinfo->{'drive-efidisk0'};
7217 delete $devinfo->{'drive-tpmstate0-backup'};
7221 keyfile
=> $keyfile,
7222 snapshot
=> $pbs_backup_name,
7223 namespace
=> $namespace,
7225 pbs_live_restore
($vmid, $conf, $storecfg, $devinfo, $pbs_opts);
7227 PVE
::QemuConfig-
>remove_lock($vmid, "create");
7231 sub pbs_live_restore
{
7232 my ($vmid, $conf, $storecfg, $restored_disks, $opts) = @_;
7234 print "starting VM for live-restore\n";
7235 print "repository: '$opts->{repo}', snapshot: '$opts->{snapshot}'\n";
7237 my $pbs_backing = {};
7238 for my $ds (keys %$restored_disks) {
7239 $ds =~ m/^drive-(.*)$/;
7241 $pbs_backing->{$confname} = {
7242 repository
=> $opts->{repo
},
7243 snapshot
=> $opts->{snapshot
},
7244 archive
=> "$ds.img.fidx",
7246 $pbs_backing->{$confname}->{keyfile
} = $opts->{keyfile
} if -e
$opts->{keyfile
};
7247 $pbs_backing->{$confname}->{namespace
} = $opts->{namespace
} if defined($opts->{namespace
});
7249 my $drive = parse_drive
($confname, $conf->{$confname});
7250 print "restoring '$ds' to '$drive->{file}'\n";
7253 my $drives_streamed = 0;
7255 # make sure HA doesn't interrupt our restore by stopping the VM
7256 if (PVE
::HA
::Config
::vm_is_ha_managed
($vmid)) {
7257 run_command
(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
7260 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
7261 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
7262 vm_start_nolock
($storecfg, $vmid, $conf, {paused
=> 1, 'pbs-backing' => $pbs_backing}, {});
7264 my $qmeventd_fd = register_qmeventd_handle
($vmid);
7266 # begin streaming, i.e. data copy from PBS to target disk for every vol,
7267 # this will effectively collapse the backing image chain consisting of
7268 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
7269 # removes itself once all backing images vanish with 'auto-remove=on')
7271 for my $ds (sort keys %$restored_disks) {
7272 my $job_id = "restore-$ds";
7273 mon_cmd
($vmid, 'block-stream',
7274 'job-id' => $job_id,
7277 $jobs->{$job_id} = {};
7280 mon_cmd
($vmid, 'cont');
7281 qemu_drive_mirror_monitor
($vmid, undef, $jobs, 'auto', 0, 'stream');
7283 print "restore-drive jobs finished successfully, removing all tracking block devices"
7284 ." to disconnect from Proxmox Backup Server\n";
7286 for my $ds (sort keys %$restored_disks) {
7287 mon_cmd
($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
7290 close($qmeventd_fd);
7296 warn "An error occurred during live-restore: $err\n";
7297 _do_vm_stop
($storecfg, $vmid, 1, 1, 10, 0, 1);
7298 die "live-restore failed\n";
7302 sub restore_vma_archive
{
7303 my ($archive, $vmid, $user, $opts, $comp) = @_;
7305 my $readfrom = $archive;
7307 my $cfg = PVE
::Storage
::config
();
7309 my $bwlimit = $opts->{bwlimit
};
7311 my $dbg_cmdstring = '';
7312 my $add_pipe = sub {
7314 push @$commands, $cmd;
7315 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
7316 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
7321 if ($archive eq '-') {
7324 # If we use a backup from a PVE defined storage we also consider that
7325 # storage's rate limit:
7326 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
7327 if (defined($volid)) {
7328 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
7329 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
7331 print STDERR
"applying read rate limit: $readlimit\n";
7332 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7333 $add_pipe->($cstream);
7339 my $info = PVE
::Storage
::decompressor_info
('vma', $comp);
7340 my $cmd = $info->{decompressor
};
7341 push @$cmd, $readfrom;
7345 my $tmpdir = "/var/tmp/vzdumptmp$$";
7348 # disable interrupts (always do cleanups)
7352 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
7354 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
7355 POSIX
::mkfifo
($mapfifo, 0600);
7357 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
7359 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
7364 my $devinfo = {}; # info about drives included in backup
7365 my $virtdev_hash = {}; # info about allocated drives
7367 my $rpcenv = PVE
::RPCEnvironment
::get
();
7369 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
7371 # Note: $oldconf is undef if VM does not exist
7372 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
7373 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
7374 my $new_conf_raw = '';
7378 my $print_devmap = sub {
7379 my $cfgfn = "$tmpdir/qemu-server.conf";
7381 # we can read the config - that is already extracted
7382 my $fh = IO
::File-
>new($cfgfn, "r") ||
7383 die "unable to read qemu-server.conf - $!\n";
7385 my $fwcfgfn = "$tmpdir/qemu-server.fw";
7387 my $pve_firewall_dir = '/etc/pve/firewall';
7388 mkdir $pve_firewall_dir; # make sure the dir exists
7389 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
7392 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
7394 foreach my $info (values %{$virtdev_hash}) {
7395 my $storeid = $info->{storeid
};
7396 next if defined($storage_limits{$storeid});
7398 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$storeid], $bwlimit) // 0;
7399 print STDERR
"rate limit for storage $storeid: $limit KiB/s\n" if $limit;
7400 $storage_limits{$storeid} = $limit * 1024;
7403 foreach my $devname (keys %$devinfo) {
7404 die "found no device mapping information for device '$devname'\n"
7405 if !$devinfo->{$devname}->{virtdev
};
7408 # create empty/temp config
7410 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
7411 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
7415 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
7417 # print restore information to $fifofh
7418 foreach my $virtdev (sort keys %$virtdev_hash) {
7419 my $d = $virtdev_hash->{$virtdev};
7420 next if $d->{is_cloudinit
}; # no need to restore cloudinit
7422 my $storeid = $d->{storeid
};
7423 my $volid = $d->{volid
};
7426 if (my $limit = $storage_limits{$storeid}) {
7427 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
7430 my $write_zeros = 1;
7431 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
7435 my $path = PVE
::Storage
::path
($cfg, $volid);
7437 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
7439 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
7442 $fh->seek(0, 0) || die "seek failed - $!\n";
7444 my $cookie = { netcount
=> 0 };
7445 while (defined(my $line = <$fh>)) {
7446 $new_conf_raw .= restore_update_config_line
(
7463 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
7464 local $SIG{ALRM
} = sub { die "got timeout\n"; };
7466 $oldtimeout = alarm($timeout);
7473 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
7474 my ($dev_id, $size, $devname) = ($1, $2, $3);
7475 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
7476 } elsif ($line =~ m/^CTIME: /) {
7477 # we correctly received the vma config, so we can disable
7478 # the timeout now for disk allocation (set to 10 minutes, so
7479 # that we always timeout if something goes wrong)
7482 print $fifofh "done\n";
7483 my $tmp = $oldtimeout || 0;
7484 $oldtimeout = undef;
7491 print "restore vma archive: $dbg_cmdstring\n";
7492 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
7496 alarm($oldtimeout) if $oldtimeout;
7498 $restore_deactivate_volumes->($cfg, $virtdev_hash);
7500 close($fifofh) if $fifofh;
7505 $restore_destroy_volumes->($cfg, $virtdev_hash);
7509 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $opts->{override_conf
});
7510 check_restore_permissions
($rpcenv, $user, $new_conf);
7511 PVE
::QemuConfig-
>write_config($vmid, $new_conf);
7513 eval { rescan
($vmid, 1); };
7516 PVE
::AccessControl
::add_vm_to_pool
($vmid, $opts->{pool
}) if $opts->{pool
};
7519 sub restore_tar_archive
{
7520 my ($archive, $vmid, $user, $opts) = @_;
7522 if (scalar(keys $opts->{override_conf
}->%*) > 0) {
7523 my $keystring = join(' ', keys $opts->{override_conf
}->%*);
7524 die "cannot pass along options ($keystring) when restoring from tar archive\n";
7527 if ($archive ne '-') {
7528 my $firstfile = tar_archive_read_firstfile
($archive);
7529 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
7530 if $firstfile ne 'qemu-server.conf';
7533 my $storecfg = PVE
::Storage
::config
();
7535 # avoid zombie disks when restoring over an existing VM -> cleanup first
7536 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
7537 # skiplock=1 because qmrestore has set the 'create' lock itself already
7538 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
7539 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
7541 my $tocmd = "/usr/lib/qemu-server/qmextract";
7543 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
7544 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
7545 $tocmd .= ' --prealloc' if $opts->{prealloc
};
7546 $tocmd .= ' --info' if $opts->{info
};
7548 # tar option "xf" does not autodetect compression when read from STDIN,
7549 # so we pipe to zcat
7550 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
7551 PVE
::Tools
::shellquote
("--to-command=$tocmd");
7553 my $tmpdir = "/var/tmp/vzdumptmp$$";
7556 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
7557 local $ENV{VZDUMP_VMID
} = $vmid;
7558 local $ENV{VZDUMP_USER
} = $user;
7560 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
7561 my $new_conf_raw = '';
7563 # disable interrupts (always do cleanups)
7567 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
7575 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
7577 if ($archive eq '-') {
7578 print "extracting archive from STDIN\n";
7579 run_command
($cmd, input
=> "<&STDIN");
7581 print "extracting archive '$archive'\n";
7585 return if $opts->{info
};
7589 my $statfile = "$tmpdir/qmrestore.stat";
7590 if (my $fd = IO
::File-
>new($statfile, "r")) {
7591 while (defined (my $line = <$fd>)) {
7592 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
7593 $map->{$1} = $2 if $1;
7595 print STDERR
"unable to parse line in statfile - $line\n";
7601 my $confsrc = "$tmpdir/qemu-server.conf";
7603 my $srcfd = IO
::File-
>new($confsrc, "r") || die "unable to open file '$confsrc'\n";
7605 my $cookie = { netcount
=> 0 };
7606 while (defined (my $line = <$srcfd>)) {
7607 $new_conf_raw .= restore_update_config_line
(
7618 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
7624 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
7626 PVE
::Cluster
::cfs_update
(); # make sure we read new file
7628 eval { rescan
($vmid, 1); };
7632 sub foreach_storage_used_by_vm
{
7633 my ($conf, $func) = @_;
7637 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7638 my ($ds, $drive) = @_;
7639 return if drive_is_cdrom
($drive);
7641 my $volid = $drive->{file
};
7643 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
7644 $sidhash->{$sid} = $sid if $sid;
7647 foreach my $sid (sort keys %$sidhash) {
7652 my $qemu_snap_storage = {
7655 sub do_snapshots_with_qemu
{
7656 my ($storecfg, $volid, $deviceid) = @_;
7658 return if $deviceid =~ m/tpmstate0/;
7660 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
7661 my $scfg = $storecfg->{ids
}->{$storage_name};
7662 die "could not find storage '$storage_name'\n" if !defined($scfg);
7664 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
7668 if ($volid =~ m/\.(qcow2|qed)$/){
7675 sub qga_check_running
{
7676 my ($vmid, $nowarn) = @_;
7678 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
7680 warn "QEMU Guest Agent is not running - $@" if !$nowarn;
7686 sub template_create
{
7687 my ($vmid, $conf, $disk) = @_;
7689 my $storecfg = PVE
::Storage
::config
();
7691 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7692 my ($ds, $drive) = @_;
7694 return if drive_is_cdrom
($drive);
7695 return if $disk && $ds ne $disk;
7697 my $volid = $drive->{file
};
7698 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
7700 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
7701 $drive->{file
} = $voliddst;
7702 $conf->{$ds} = print_drive
($drive);
7703 PVE
::QemuConfig-
>write_config($vmid, $conf);
7707 sub convert_iscsi_path
{
7710 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
7715 my $initiator_name = get_initiator_name
();
7717 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7718 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7721 die "cannot convert iscsi path '$path', unkown format\n";
7724 sub qemu_img_convert
{
7725 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized, $bwlimit) = @_;
7727 my $storecfg = PVE
::Storage
::config
();
7728 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
7729 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
7731 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
7735 my $src_is_iscsi = 0;
7739 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
7740 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
7741 $src_format = qemu_img_format
($src_scfg, $src_volname);
7742 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
7743 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
7744 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
7745 } elsif (-f
$src_volid || -b
$src_volid) {
7746 $src_path = $src_volid;
7747 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7752 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
7754 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7755 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
7756 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7757 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
7760 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
7761 push @$cmd, '-l', "snapshot.name=$snapname"
7762 if $snapname && $src_format && $src_format eq "qcow2";
7763 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
7764 push @$cmd, '-T', $cachemode if defined($cachemode);
7765 push @$cmd, '-r', "${bwlimit}K" if defined($bwlimit);
7767 if ($src_is_iscsi) {
7768 push @$cmd, '--image-opts';
7769 $src_path = convert_iscsi_path
($src_path);
7770 } elsif ($src_format) {
7771 push @$cmd, '-f', $src_format;
7774 if ($dst_is_iscsi) {
7775 push @$cmd, '--target-image-opts';
7776 $dst_path = convert_iscsi_path
($dst_path);
7778 push @$cmd, '-O', $dst_format;
7781 push @$cmd, $src_path;
7783 if (!$dst_is_iscsi && $is_zero_initialized) {
7784 push @$cmd, "zeroinit:$dst_path";
7786 push @$cmd, $dst_path;
7791 if($line =~ m/\((\S+)\/100\
%\)/){
7793 my $transferred = int($size * $percent / 100);
7794 my $total_h = render_bytes
($size, 1);
7795 my $transferred_h = render_bytes
($transferred, 1);
7797 print "transferred $transferred_h of $total_h ($percent%)\n";
7802 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
7804 die "copy failed: $err" if $err;
7807 sub qemu_img_format
{
7808 my ($scfg, $volname) = @_;
7810 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7817 sub qemu_drive_mirror
{
7818 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
7820 $jobs = {} if !$jobs;
7824 $jobs->{"drive-$drive"} = {};
7826 if ($dst_volid =~ /^nbd:/) {
7827 $qemu_target = $dst_volid;
7830 my $storecfg = PVE
::Storage
::config
();
7831 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
7833 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7835 $format = qemu_img_format
($dst_scfg, $dst_volname);
7837 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7839 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
7842 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
7843 $opts->{format
} = $format if $format;
7845 if (defined($src_bitmap)) {
7846 $opts->{sync
} = 'incremental';
7847 $opts->{bitmap
} = $src_bitmap;
7848 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7851 if (defined($bwlimit)) {
7852 $opts->{speed
} = $bwlimit * 1024;
7853 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
7855 print "drive mirror is starting for drive-$drive\n";
7858 # if a job already runs for this device we get an error, catch it for cleanup
7859 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
7861 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7863 die "mirroring error: $err\n";
7866 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
7869 # $completion can be either
7870 # 'complete': wait until all jobs are ready, block-job-complete them (default)
7871 # 'cancel': wait until all jobs are ready, block-job-cancel them
7872 # 'skip': wait until all jobs are ready, return with block jobs in ready state
7873 # 'auto': wait until all jobs disappear, only use for jobs which complete automatically
7874 sub qemu_drive_mirror_monitor
{
7875 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
7877 $completion //= 'complete';
7881 my $err_complete = 0;
7883 my $starttime = time ();
7885 die "block job ('$op') timed out\n" if $err_complete > 300;
7887 my $stats = mon_cmd
($vmid, "query-block-jobs");
7890 my $running_jobs = {};
7891 for my $stat (@$stats) {
7892 next if $stat->{type
} ne $op;
7893 $running_jobs->{$stat->{device
}} = $stat;
7896 my $readycounter = 0;
7898 for my $job_id (sort keys %$jobs) {
7899 my $job = $running_jobs->{$job_id};
7901 my $vanished = !defined($job);
7902 my $complete = defined($jobs->{$job_id}->{complete
}) && $vanished;
7903 if($complete || ($vanished && $completion eq 'auto')) {
7904 print "$job_id: $op-job finished\n";
7905 delete $jobs->{$job_id};
7909 die "$job_id: '$op' has been cancelled\n" if !defined($job);
7911 my $busy = $job->{busy
};
7912 my $ready = $job->{ready
};
7913 if (my $total = $job->{len
}) {
7914 my $transferred = $job->{offset
} || 0;
7915 my $remaining = $total - $transferred;
7916 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
7918 my $duration = $ctime - $starttime;
7919 my $total_h = render_bytes
($total, 1);
7920 my $transferred_h = render_bytes
($transferred, 1);
7922 my $status = sprintf(
7923 "transferred $transferred_h of $total_h ($percent%%) in %s",
7924 render_duration
($duration),
7929 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7931 $status .= ", ready";
7934 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready
};
7935 $jobs->{$job_id}->{ready
} = $ready;
7938 $readycounter++ if $job->{ready
};
7941 last if scalar(keys %$jobs) == 0;
7943 if ($readycounter == scalar(keys %$jobs)) {
7944 print "all '$op' jobs are ready\n";
7946 # do the complete later (or has already been done)
7947 last if $completion eq 'skip' || $completion eq 'auto';
7949 if ($vmiddst && $vmiddst != $vmid) {
7950 my $agent_running = $qga && qga_check_running
($vmid);
7951 if ($agent_running) {
7952 print "freeze filesystem\n";
7953 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
7956 print "suspend vm\n";
7957 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
7961 # if we clone a disk for a new target vm, we don't switch the disk
7962 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
7964 if ($agent_running) {
7965 print "unfreeze filesystem\n";
7966 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
7969 print "resume vm\n";
7970 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
7977 for my $job_id (sort keys %$jobs) {
7978 # try to switch the disk if source and destination are on the same guest
7979 print "$job_id: Completing block job_id...\n";
7982 if ($completion eq 'complete') {
7983 $op = 'block-job-complete';
7984 } elsif ($completion eq 'cancel') {
7985 $op = 'block-job-cancel';
7987 die "invalid completion value: $completion\n";
7989 eval { mon_cmd
($vmid, $op, device
=> $job_id) };
7990 if ($@ =~ m/cannot be completed/) {
7991 print "$job_id: block job cannot be completed, trying again.\n";
7994 print "$job_id: Completed successfully.\n";
7995 $jobs->{$job_id}->{complete
} = 1;
8006 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
8007 die "block job ($op) error: $err";
8011 sub qemu_blockjobs_cancel
{
8012 my ($vmid, $jobs) = @_;
8014 foreach my $job (keys %$jobs) {
8015 print "$job: Cancelling block job\n";
8016 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
8017 $jobs->{$job}->{cancel
} = 1;
8021 my $stats = mon_cmd
($vmid, "query-block-jobs");
8023 my $running_jobs = {};
8024 foreach my $stat (@$stats) {
8025 $running_jobs->{$stat->{device
}} = $stat;
8028 foreach my $job (keys %$jobs) {
8030 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
8031 print "$job: Done.\n";
8032 delete $jobs->{$job};
8036 last if scalar(keys %$jobs) == 0;
8042 # Check for bug #4525: drive-mirror will open the target drive with the same aio setting as the
8043 # source, but some storages have problems with io_uring, sometimes even leading to crashes.
8044 my sub clone_disk_check_io_uring
{
8045 my ($src_drive, $storecfg, $src_storeid, $dst_storeid, $use_drive_mirror) = @_;
8047 return if !$use_drive_mirror;
8049 # Don't complain when not changing storage.
8050 # Assume if it works for the source, it'll work for the target too.
8051 return if $src_storeid eq $dst_storeid;
8053 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
8054 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
8056 my $cache_direct = drive_uses_cache_direct
($src_drive);
8058 my $src_uses_io_uring;
8059 if ($src_drive->{aio
}) {
8060 $src_uses_io_uring = $src_drive->{aio
} eq 'io_uring';
8062 $src_uses_io_uring = storage_allows_io_uring_default
($src_scfg, $cache_direct);
8065 die "target storage is known to cause issues with aio=io_uring (used by current drive)\n"
8066 if $src_uses_io_uring && !storage_allows_io_uring_default
($dst_scfg, $cache_direct);
8070 my ($storecfg, $source, $dest, $full, $newvollist, $jobs, $completion, $qga, $bwlimit) = @_;
8072 my ($vmid, $running) = $source->@{qw(vmid running)};
8073 my ($src_drivename, $drive, $snapname) = $source->@{qw(drivename drive snapname)};
8075 my ($newvmid, $dst_drivename, $efisize) = $dest->@{qw(vmid drivename efisize)};
8076 my ($storage, $format) = $dest->@{qw(storage format)};
8078 my $use_drive_mirror = $full && $running && $src_drivename && !$snapname;
8080 if ($src_drivename && $dst_drivename && $src_drivename ne $dst_drivename) {
8081 die "cloning from/to EFI disk requires EFI disk\n"
8082 if $src_drivename eq 'efidisk0' || $dst_drivename eq 'efidisk0';
8083 die "cloning from/to TPM state requires TPM state\n"
8084 if $src_drivename eq 'tpmstate0' || $dst_drivename eq 'tpmstate0';
8086 # This would lead to two device nodes in QEMU pointing to the same backing image!
8087 die "cannot change drive name when cloning disk from/to the same VM\n"
8088 if $use_drive_mirror && $vmid == $newvmid;
8091 die "cannot move TPM state while VM is running\n"
8092 if $use_drive_mirror && $src_drivename eq 'tpmstate0';
8096 print "create " . ($full ?
'full' : 'linked') . " clone of drive ";
8097 print "$src_drivename " if $src_drivename;
8098 print "($drive->{file})\n";
8101 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
8102 push @$newvollist, $newvolid;
8104 my ($src_storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
8105 my $storeid = $storage || $src_storeid;
8107 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
8111 if (drive_is_cloudinit
($drive)) {
8112 $name = "vm-$newvmid-cloudinit";
8113 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
8114 if ($scfg->{path
}) {
8115 $name .= ".$dst_format";
8118 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
8119 } elsif ($dst_drivename eq 'efidisk0') {
8120 $size = $efisize or die "internal error - need to specify EFI disk size\n";
8121 } elsif ($dst_drivename eq 'tpmstate0') {
8122 $dst_format = 'raw';
8123 $size = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
8125 clone_disk_check_io_uring
($drive, $storecfg, $src_storeid, $storeid, $use_drive_mirror);
8127 $size = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 10);
8129 $newvolid = PVE
::Storage
::vdisk_alloc
(
8130 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
8132 push @$newvollist, $newvolid;
8134 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
8136 if (drive_is_cloudinit
($drive)) {
8137 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
8138 # if this is the case, we have to complete any block-jobs still there from
8139 # previous drive-mirrors
8140 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
8141 qemu_drive_mirror_monitor
($vmid, $newvmid, $jobs, $completion, $qga);
8146 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
8147 if ($use_drive_mirror) {
8148 qemu_drive_mirror
($vmid, $src_drivename, $newvolid, $newvmid, $sparseinit, $jobs,
8149 $completion, $qga, $bwlimit);
8151 if ($dst_drivename eq 'efidisk0') {
8152 # the relevant data on the efidisk may be smaller than the source
8153 # e.g. on RBD/ZFS, so we use dd to copy only the amount
8154 # that is given by the OVMF_VARS.fd
8155 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
8156 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
8158 my $src_format = (PVE
::Storage
::parse_volname
($storecfg, $drive->{file
}))[6];
8160 # better for Ceph if block size is not too small, see bug #3324
8163 my $cmd = ['qemu-img', 'dd', '-n', '-O', $dst_format];
8165 if ($src_format eq 'qcow2' && $snapname) {
8166 die "cannot clone qcow2 EFI disk snapshot - requires QEMU >= 6.2\n"
8167 if !min_version
(kvm_user_version
(), 6, 2);
8168 push $cmd->@*, '-l', $snapname;
8170 push $cmd->@*, "bs=$bs", "osize=$size", "if=$src_path", "of=$dst_path";
8173 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit, $bwlimit);
8179 my $size = eval { PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 10) };
8181 my $disk = dclone
($drive);
8182 delete $disk->{format
};
8183 $disk->{file
} = $newvolid;
8184 $disk->{size
} = $size if defined($size);
8189 sub get_running_qemu_version
{
8191 my $res = mon_cmd
($vmid, "query-version");
8192 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
8195 sub qemu_use_old_bios_files
{
8196 my ($machine_type) = @_;
8198 return if !$machine_type;
8200 my $use_old_bios_files = undef;
8202 if ($machine_type =~ m/^(\S+)\.pxe$/) {
8204 $use_old_bios_files = 1;
8206 my $version = extract_version
($machine_type, kvm_user_version
());
8207 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
8208 # load new efi bios files on migration. So this hack is required to allow
8209 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
8210 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
8211 $use_old_bios_files = !min_version
($version, 2, 4);
8214 return ($use_old_bios_files, $machine_type);
8217 sub get_efivars_size
{
8218 my ($conf, $efidisk) = @_;
8220 my $arch = get_vm_arch
($conf);
8221 $efidisk //= $conf->{efidisk0
} ? parse_drive
('efidisk0', $conf->{efidisk0
}) : undef;
8222 my $smm = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
8223 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk, $smm);
8224 return -s
$ovmf_vars;
8227 sub update_efidisk_size
{
8230 return if !defined($conf->{efidisk0
});
8232 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
8233 $disk->{size
} = get_efivars_size
($conf);
8234 $conf->{efidisk0
} = print_drive
($disk);
8239 sub update_tpmstate_size
{
8242 my $disk = PVE
::QemuServer
::parse_drive
('tpmstate0', $conf->{tpmstate0
});
8243 $disk->{size
} = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
8244 $conf->{tpmstate0
} = print_drive
($disk);
8247 sub create_efidisk
($$$$$$$) {
8248 my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk, $smm) = @_;
8250 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk, $smm);
8252 my $vars_size_b = -s
$ovmf_vars;
8253 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
8254 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
8255 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
8257 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
8258 my $size = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
8260 return ($volid, $size/1024);
8263 sub vm_iothreads_list
{
8266 my $res = mon_cmd
($vmid, 'query-iothreads');
8269 foreach my $iothread (@$res) {
8270 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
8277 my ($conf, $drive) = @_;
8281 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
8283 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
8289 my $controller = int($drive->{index} / $maxdev);
8290 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single')
8294 return ($maxdev, $controller, $controller_prefix);
8297 sub resolve_dst_disk_format
{
8298 my ($storecfg, $storeid, $src_volname, $format) = @_;
8299 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
8302 # if no target format is specified, use the source disk format as hint
8304 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
8305 $format = qemu_img_format
($scfg, $src_volname);
8311 # test if requested format is supported - else use default
8312 my $supported = grep { $_ eq $format } @$validFormats;
8313 $format = $defFormat if !$supported;
8317 # NOTE: if this logic changes, please update docs & possibly gui logic
8318 sub find_vmstate_storage
{
8319 my ($conf, $storecfg) = @_;
8321 # first, return storage from conf if set
8322 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
8324 my ($target, $shared, $local);
8326 foreach_storage_used_by_vm
($conf, sub {
8328 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
8329 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
8330 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
8333 # second, use shared storage where VM has at least one disk
8334 # third, use local storage where VM has at least one disk
8335 # fall back to local storage
8336 $target = $shared // $local // 'local';
8342 my ($uuid, $uuid_str);
8343 UUID
::generate
($uuid);
8344 UUID
::unparse
($uuid, $uuid_str);
8348 sub generate_smbios1_uuid
{
8349 return "uuid=".generate_uuid
();
8355 mon_cmd
($vmid, 'nbd-server-stop');
8358 sub create_reboot_request
{
8360 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
8361 or die "failed to create reboot trigger file: $!\n";
8365 sub clear_reboot_request
{
8367 my $path = "/run/qemu-server/$vmid.reboot";
8370 $res = unlink($path);
8371 die "could not remove reboot request for $vmid: $!"
8372 if !$res && $! != POSIX
::ENOENT
;
8377 sub bootorder_from_legacy
{
8378 my ($conf, $bootcfg) = @_;
8380 my $boot = $bootcfg->{legacy
} || $boot_fmt->{legacy
}->{default};
8381 my $bootindex_hash = {};
8383 foreach my $o (split(//, $boot)) {
8384 $bootindex_hash->{$o} = $i*100;
8390 PVE
::QemuConfig-
>foreach_volume($conf, sub {
8391 my ($ds, $drive) = @_;
8393 if (drive_is_cdrom
($drive, 1)) {
8394 if ($bootindex_hash->{d
}) {
8395 $bootorder->{$ds} = $bootindex_hash->{d
};
8396 $bootindex_hash->{d
} += 1;
8398 } elsif ($bootindex_hash->{c
}) {
8399 $bootorder->{$ds} = $bootindex_hash->{c
}
8400 if $conf->{bootdisk
} && $conf->{bootdisk
} eq $ds;
8401 $bootindex_hash->{c
} += 1;
8405 if ($bootindex_hash->{n
}) {
8406 for (my $i = 0; $i < $MAX_NETS; $i++) {
8407 my $netname = "net$i";
8408 next if !$conf->{$netname};
8409 $bootorder->{$netname} = $bootindex_hash->{n
};
8410 $bootindex_hash->{n
} += 1;
8417 # Generate default device list for 'boot: order=' property. Matches legacy
8418 # default boot order, but with explicit device names. This is important, since
8419 # the fallback for when neither 'order' nor the old format is specified relies
8420 # on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
8421 sub get_default_bootdevices
{
8427 my $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 0);
8428 push @ret, $first if $first;
8431 $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 1);
8432 push @ret, $first if $first;
8435 for (my $i = 0; $i < $MAX_NETS; $i++) {
8436 my $netname = "net$i";
8437 next if !$conf->{$netname};
8438 push @ret, $netname;
8445 sub device_bootorder
{
8448 return bootorder_from_legacy
($conf) if !defined($conf->{boot
});
8450 my $boot = parse_property_string
($boot_fmt, $conf->{boot
});
8453 if (!defined($boot) || $boot->{legacy
}) {
8454 $bootorder = bootorder_from_legacy
($conf, $boot);
8455 } elsif ($boot->{order
}) {
8456 my $i = 100; # start at 100 to allow user to insert devices before us with -args
8457 for my $dev (PVE
::Tools
::split_list
($boot->{order
})) {
8458 $bootorder->{$dev} = $i++;
8465 sub register_qmeventd_handle
{
8469 my $peer = "/var/run/qmeventd.sock";
8474 $fh = IO
::Socket
::UNIX-
>new(Peer
=> $peer, Blocking
=> 0, Timeout
=> 1);
8476 if ($! != EINTR
&& $! != EAGAIN
) {
8477 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
8480 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
8481 . "after $count retries\n";
8486 # send handshake to mark VM as backing up
8487 print $fh to_json
({vzdump
=> {vmid
=> "$vmid"}});
8489 # return handle to be closed later when inhibit is no longer required
8493 # bash completion helper
8495 sub complete_backup_archives
{
8496 my ($cmdname, $pname, $cvalue) = @_;
8498 my $cfg = PVE
::Storage
::config
();
8502 if ($cvalue =~ m/^([^:]+):/) {
8506 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
8509 foreach my $id (keys %$data) {
8510 foreach my $item (@{$data->{$id}}) {
8511 next if $item->{format
} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
8512 push @$res, $item->{volid
} if defined($item->{volid
});
8519 my $complete_vmid_full = sub {
8522 my $idlist = vmstatus
();
8526 foreach my $id (keys %$idlist) {
8527 my $d = $idlist->{$id};
8528 if (defined($running)) {
8529 next if $d->{template
};
8530 next if $running && $d->{status
} ne 'running';
8531 next if !$running && $d->{status
} eq 'running';
8540 return &$complete_vmid_full();
8543 sub complete_vmid_stopped
{
8544 return &$complete_vmid_full(0);
8547 sub complete_vmid_running
{
8548 return &$complete_vmid_full(1);
8551 sub complete_storage
{
8553 my $cfg = PVE
::Storage
::config
();
8554 my $ids = $cfg->{ids
};
8557 foreach my $sid (keys %$ids) {
8558 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
8559 next if !$ids->{$sid}->{content
}->{images
};
8566 sub complete_migration_storage
{
8567 my ($cmd, $param, $current_value, $all_args) = @_;
8569 my $targetnode = @$all_args[1];
8571 my $cfg = PVE
::Storage
::config
();
8572 my $ids = $cfg->{ids
};
8575 foreach my $sid (keys %$ids) {
8576 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
8577 next if !$ids->{$sid}->{content
}->{images
};
8586 my $qmpstatus = eval {
8587 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid);
8588 mon_cmd
($vmid, "query-status");
8591 return $qmpstatus && $qmpstatus->{status
} eq "paused";
8594 sub check_volume_storage_type
{
8595 my ($storecfg, $vol) = @_;
8597 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($vol);
8598 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
8599 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $vol);
8601 die "storage '$storeid' does not support content-type '$vtype'\n"
8602 if !$scfg->{content
}->{$vtype};
8607 sub add_nets_bridge_fdb
{
8608 my ($conf, $vmid) = @_;
8610 for my $opt (keys %$conf) {
8611 next if $opt !~ m/^net(\d+)$/;
8612 my $iface = "tap${vmid}i$1";
8613 # NOTE: expect setups with learning off to *not* use auto-random-generation of MAC on start
8614 my $net = parse_net
($conf->{$opt}, 1) or next;
8616 my $mac = $net->{macaddr
};
8618 log_warn
("MAC learning disabled, but vNIC '$iface' has no static MAC to add to forwarding DB!")
8619 if !file_read_firstline
("/sys/class/net/$iface/brport/learning");
8623 my $bridge = $net->{bridge
};
8625 log_warn
("Interface '$iface' not attached to any bridge.");
8629 PVE
::Network
::SDN
::Zones
::add_bridge_fdb
($iface, $mac, $bridge, $net->{firewall
});
8630 } elsif (-d
"/sys/class/net/$bridge/bridge") { # avoid fdb management with OVS for now
8631 PVE
::Network
::add_bridge_fdb
($iface, $mac, $net->{firewall
});
8636 sub del_nets_bridge_fdb
{
8637 my ($conf, $vmid) = @_;
8639 for my $opt (keys %$conf) {
8640 next if $opt !~ m/^net(\d+)$/;
8641 my $iface = "tap${vmid}i$1";
8643 my $net = parse_net
($conf->{$opt}) or next;
8644 my $mac = $net->{macaddr
} or next;
8646 my $bridge = $net->{bridge
};
8648 PVE
::Network
::SDN
::Zones
::del_bridge_fdb
($iface, $mac, $bridge, $net->{firewall
});
8649 } elsif (-d
"/sys/class/net/$bridge/bridge") { # avoid fdb management with OVS for now
8650 PVE
::Network
::del_bridge_fdb
($iface, $mac, $net->{firewall
});