1 package PVE
::QemuServer
;
11 use File
::Copy
qw(copy);
24 use Storable
qw(dclone);
25 use Time
::HiRes
qw(gettimeofday usleep);
29 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file);
31 use PVE
::DataCenterConfig
;
32 use PVE
::Exception
qw(raise raise_param_exc);
33 use PVE
::Format
qw(render_duration render_bytes);
34 use PVE
::GuestHelpers
qw(safe_string_ne safe_num_ne safe_boolean_ne);
36 use PVE
::JSONSchema
qw(get_standard_option parse_property_string);
39 use PVE
::RPCEnvironment
;
43 use PVE
::Tools
qw(run_command file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
47 use PVE
::QemuServer
::Helpers
qw(min_version config_aware_timeout);
48 use PVE
::QemuServer
::Cloudinit
;
49 use PVE
::QemuServer
::CGroup
;
50 use PVE
::QemuServer
::CPUConfig
qw(print_cpu_device get_cpu_options);
51 use PVE
::QemuServer
::Drive
qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom drive_is_read_only parse_drive print_drive);
52 use PVE
::QemuServer
::Machine
;
53 use PVE
::QemuServer
::Memory
;
54 use PVE
::QemuServer
::Monitor
qw(mon_cmd);
55 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
56 use PVE
::QemuServer
::USB
qw(parse_usb_device);
60 require PVE
::Network
::SDN
::Zones
;
64 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
68 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
69 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
72 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
73 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
76 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
77 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
80 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
81 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
84 "$EDK2_FW_BASE/OVMF_CODE.fd",
85 "$EDK2_FW_BASE/OVMF_VARS.fd",
90 "$EDK2_FW_BASE/AAVMF_CODE.fd",
91 "$EDK2_FW_BASE/AAVMF_VARS.fd",
96 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
98 # Note about locking: we use flock on the config file protect against concurent actions.
99 # Aditionaly, we have a 'lock' setting in the config file. This can be set to 'migrate',
100 # 'backup', 'snapshot' or 'rollback'. Most actions are not allowed when such lock is set.
101 # But you can ignore this kind of lock with the --skiplock flag.
103 cfs_register_file
('/qemu-server/',
107 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
108 description
=> "Some command save/restore state from this location.",
114 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
115 description
=> "Specifies the Qemu machine type.",
117 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
122 PVE
::JSONSchema
::register_standard_option
('pve-targetstorage', {
123 description
=> "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
125 format
=> 'storage-pair-list',
129 #no warnings 'redefine';
133 $nodename_cache //= PVE
::INotify
::nodename
();
134 return $nodename_cache;
141 enum
=> [qw(i6300esb ib700)],
142 description
=> "Watchdog type to emulate.",
143 default => 'i6300esb',
148 enum
=> [qw(reset shutdown poweroff pause debug none)],
149 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
153 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
157 description
=> "Enable/disable communication with a Qemu Guest Agent (QGA) running in the VM.",
162 fstrim_cloned_disks
=> {
163 description
=> "Run fstrim after moving a disk or migrating the VM.",
169 description
=> "Select the agent type",
173 enum
=> [qw(virtio isa)],
179 description
=> "Select the VGA type.",
184 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio virtio-gl vmware)],
187 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
199 description
=> "The size of the file in MB.",
203 pattern
=> '[a-zA-Z0-9\-]+',
205 format_description
=> 'string',
206 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
213 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
214 description
=> "Configure an audio device."
218 enum
=> ['spice', 'none'],
221 description
=> "Driver backend for the audio device."
225 my $spice_enhancements_fmt = {
230 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
234 enum
=> ['off', 'all', 'filter'],
237 description
=> "Enable video streaming. Uses compression for detected video streams."
244 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
246 description
=> "The file on the host to gather entropy from. In most cases '/dev/urandom'"
247 ." should be preferred over '/dev/random' to avoid entropy-starvation issues on the"
248 ." host. Using urandom does *not* decrease security in any meaningful way, as it's"
249 ." still seeded from real entropy, and the bytes provided will most likely be mixed"
250 ." with real entropy on the guest as well. '/dev/hwrng' can be used to pass through"
251 ." a hardware RNG from the host.",
255 description
=> "Maximum bytes of entropy allowed to get injected into the guest every"
256 ." 'period' milliseconds. Prefer a lower value when using '/dev/random' as source. Use"
257 ." `0` to disable limiting (potentially dangerous!).",
260 # default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
261 # (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
262 # reading from /dev/urandom
267 description
=> "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
268 ." the guest to retrieve another 'max_bytes' of entropy.",
274 my $meta_info_fmt = {
277 description
=> "The guest creation timestamp as UNIX epoch time",
283 description
=> "The QEMU (machine) version from the time this VM was created.",
284 pattern
=> '\d+(\.\d+)+',
293 description
=> "Specifies whether a VM will be started during system bootup.",
299 description
=> "Automatic restart after crash (currently ignored).",
304 type
=> 'string', format
=> 'pve-hotplug-features',
305 description
=> "Selectively enable hotplug features. This is a comma separated list of"
306 ." hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable"
307 ." hotplug completely. Using '1' as value is an alias for the default `network,disk,usb`.",
308 default => 'network,disk,usb',
313 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
319 description
=> "Lock/unlock the VM.",
320 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
325 description
=> "Limit of CPU usage.",
326 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has"
327 ." total of '2' CPU time. Value '0' indicates no CPU limit.",
335 description
=> "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
336 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler."
337 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
338 ." weights of all the other running VMs.",
341 default => 'cgroup v1: 1024, cgroup v2: 100',
346 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when"
347 ." you use the balloon device.",
354 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
360 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the"
361 ." more memory this VM gets. Number is relative to weights of all other running VMs."
362 ." Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
370 description
=> "Keyboard layout for VNC server. This option is generally not required and"
371 ." is often better handled from within the guest OS.",
372 enum
=> PVE
::Tools
::kvmkeymaplist
(),
377 type
=> 'string', format
=> 'dns-name',
378 description
=> "Set a name for the VM. Only used on the configuration web interface.",
383 description
=> "SCSI controller model",
384 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
390 description
=> "Description for the VM. Shown in the web-interface VM's summary."
391 ." This is saved as comment inside the configuration file.",
392 maxLength
=> 1024 * 8,
397 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
398 description
=> "Specify guest operating system.",
399 verbose_description
=> <<EODESC,
400 Specify guest operating system. This is used to enable special
401 optimization/features for specific operating systems:
404 other;; unspecified OS
405 wxp;; Microsoft Windows XP
406 w2k;; Microsoft Windows 2000
407 w2k3;; Microsoft Windows 2003
408 w2k8;; Microsoft Windows 2008
409 wvista;; Microsoft Windows Vista
410 win7;; Microsoft Windows 7
411 win8;; Microsoft Windows 8/2012/2012r2
412 win10;; Microsoft Windows 10/2016/2019
413 win11;; Microsoft Windows 11/2022
414 l24;; Linux 2.4 Kernel
415 l26;; Linux 2.6 - 5.X Kernel
416 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
421 type
=> 'string', format
=> 'pve-qm-boot',
422 description
=> "Specify guest boot order. Use the 'order=' sub-property as usage with no"
423 ." key or 'legacy=' is deprecated.",
427 type
=> 'string', format
=> 'pve-qm-bootdisk',
428 description
=> "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
429 pattern
=> '(ide|sata|scsi|virtio)\d+',
434 description
=> "The number of CPUs. Please use option -sockets instead.",
441 description
=> "The number of CPU sockets.",
448 description
=> "The number of cores per socket.",
455 description
=> "Enable/disable NUMA.",
461 description
=> "Enable/disable hugepages memory.",
462 enum
=> [qw(any 2 1024)],
468 description
=> "Use together with hugepages. If enabled, hugepages will not not be deleted"
469 ." after VM shutdown and can be used for subsequent starts.",
474 description
=> "Number of hotplugged vcpus.",
481 description
=> "Enable/disable ACPI.",
486 description
=> "Enable/disable communication with the Qemu Guest Agent and its properties.",
488 format
=> $agent_fmt,
493 description
=> "Enable/disable KVM hardware virtualization.",
499 description
=> "Enable/disable time drift fix.",
505 description
=> "Set the real time clock (RTC) to local time. This is enabled by default if"
506 ." the `ostype` indicates a Microsoft Windows OS.",
511 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
515 type
=> 'string', format
=> $vga_fmt,
516 description
=> "Configure the VGA hardware.",
517 verbose_description
=> "Configure the VGA Hardware. If you want to use high resolution"
518 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
519 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
520 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
521 ." display server. For win* OS you can select how many independent displays you want,"
522 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
523 ." using a serial device as terminal.",
527 type
=> 'string', format
=> 'pve-qm-watchdog',
528 description
=> "Create a virtual hardware watchdog device.",
529 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled (by a guest"
530 ." action), the watchdog must be periodically polled by an agent inside the guest or"
531 ." else the watchdog will reset the guest (or execute the respective action specified)",
536 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
537 description
=> "Set the initial date of the real time clock. Valid format for date are:"
538 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
539 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
542 startup
=> get_standard_option
('pve-startup-order'),
546 description
=> "Enable/disable Template.",
552 description
=> "Arbitrary arguments passed to kvm.",
553 verbose_description
=> <<EODESCR,
554 Arbitrary arguments passed to kvm, for example:
556 args: -no-reboot -no-hpet
558 NOTE: this option is for experts only.
565 description
=> "Enable/disable the USB tablet device.",
566 verbose_description
=> "Enable/disable the USB tablet device. This device is usually needed"
567 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
568 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
569 ." may consider disabling this to save some context switches. This is turned off by"
570 ." default if you use spice (`qm set <vmid> --vga qxl`).",
575 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
579 migrate_downtime
=> {
582 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
588 type
=> 'string', format
=> 'pve-qm-ide',
589 typetext
=> '<volume>',
590 description
=> "This is an alias for option -ide2",
594 description
=> "Emulated CPU type.",
596 format
=> 'pve-vm-cpu-conf',
598 parent
=> get_standard_option
('pve-snapshot-name', {
600 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
604 description
=> "Timestamp for snapshots.",
610 type
=> 'string', format
=> 'pve-volume-id',
611 description
=> "Reference to a volume which stores the VM state. This is used internally"
614 vmstatestorage
=> get_standard_option
('pve-storage-id', {
615 description
=> "Default storage for VM state volumes/files.",
618 runningmachine
=> get_standard_option
('pve-qemu-machine', {
619 description
=> "Specifies the QEMU machine type of the running vm. This is used internally"
623 description
=> "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
624 ." internally for snapshots.",
627 pattern
=> $PVE::QemuServer
::CPUConfig
::qemu_cmdline_cpu_re
,
628 format_description
=> 'QEMU -cpu parameter'
630 machine
=> get_standard_option
('pve-qemu-machine'),
632 description
=> "Virtual processor architecture. Defaults to the host.",
635 enum
=> [qw(x86_64 aarch64)],
638 description
=> "Specify SMBIOS type 1 fields.",
639 type
=> 'string', format
=> 'pve-qm-smbios1',
646 description
=> "Sets the protection flag of the VM. This will disable the remove VM and"
647 ." remove disk operations.",
653 enum
=> [ qw(seabios ovmf) ],
654 description
=> "Select BIOS implementation.",
655 default => 'seabios',
659 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
660 format_description
=> 'UUID',
661 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
662 ." to disable explicitly.",
663 verbose_description
=> "The VM generation ID (vmgenid) device exposes a 128-bit integer"
664 ." value identifier to the guest OS. This allows to notify the guest operating system"
665 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
666 ." execution or creation from a template). The guest operating system notices the"
667 ." change, and is then able to react as appropriate by marking its copies of"
668 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
669 ."Note that auto-creation only works when done through API/CLI create or update methods"
670 .", but not when manually editing the config file.",
671 default => "1 (autogenerated)",
676 format
=> 'pve-volume-id',
678 description
=> "Script that will be executed during various steps in the vms lifetime.",
682 format
=> $ivshmem_fmt,
683 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to"
689 format
=> $audio_fmt,
690 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
693 spice_enhancements
=> {
695 format
=> $spice_enhancements_fmt,
696 description
=> "Configure additional enhancements for SPICE.",
700 type
=> 'string', format
=> 'pve-tag-list',
701 description
=> 'Tags of the VM. This is only meta information.',
707 description
=> "Configure a VirtIO-based Random Number Generator.",
712 format
=> $meta_info_fmt,
713 description
=> "Some (read-only) meta-information about this guest.",
722 description
=> 'Specify a custom file containing all meta data passed to the VM via"
723 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
724 format
=> 'pve-volume-id',
725 format_description
=> 'volume',
730 description
=> 'Specify a custom file containing all network data passed to the VM via'
732 format
=> 'pve-volume-id',
733 format_description
=> 'volume',
738 description
=> 'Specify a custom file containing all user data passed to the VM via'
740 format
=> 'pve-volume-id',
741 format_description
=> 'volume',
746 description
=> 'Specify a custom file containing all vendor data passed to the VM via'
748 format
=> 'pve-volume-id',
749 format_description
=> 'volume',
752 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
754 my $confdesc_cloudinit = {
758 description
=> 'Specifies the cloud-init configuration format. The default depends on the'
759 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
760 .' and `configdrive2` for windows.',
761 enum
=> ['configdrive2', 'nocloud', 'opennebula'],
766 description
=> "cloud-init: User name to change ssh keys and password for instead of the"
767 ." image's configured default user.",
772 description
=> 'cloud-init: Password to assign the user. Using this is generally not'
773 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
774 .' support hashed passwords.',
779 description
=> 'cloud-init: Specify custom files to replace the automatically generated'
781 format
=> 'pve-qm-cicustom',
786 description
=> "cloud-init: Sets DNS search domains for a container. Create will'
787 .' automatically use the setting from the host if neither searchdomain nor nameserver'
792 type
=> 'string', format
=> 'address-list',
793 description
=> "cloud-init: Sets DNS server IP address for a container. Create will'
794 .' automatically use the setting from the host if neither searchdomain nor nameserver'
800 format
=> 'urlencoded',
801 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
805 # what about other qemu settings ?
807 #machine => 'string',
820 ##soundhw => 'string',
822 while (my ($k, $v) = each %$confdesc) {
823 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
826 my $MAX_USB_DEVICES = 5;
828 my $MAX_SERIAL_PORTS = 4;
829 my $MAX_PARALLEL_PORTS = 3;
835 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
836 description
=> "CPUs accessing this NUMA node.",
837 format_description
=> "id[-id];...",
841 description
=> "Amount of memory this NUMA node provides.",
846 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
847 description
=> "Host NUMA nodes to use.",
848 format_description
=> "id[-id];...",
853 enum
=> [qw(preferred bind interleave)],
854 description
=> "NUMA allocation policy.",
858 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
861 type
=> 'string', format
=> $numa_fmt,
862 description
=> "NUMA topology.",
864 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
866 for (my $i = 0; $i < $MAX_NUMA; $i++) {
867 $confdesc->{"numa$i"} = $numadesc;
870 my $nic_model_list = [
886 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
888 my $net_fmt_bridge_descr = <<__EOD__;
889 Bridge to attach the network device to. The Proxmox VE standard bridge
892 If you do not specify a bridge, we create a kvm user (NATed) network
893 device, which provides DHCP and DNS services. The following addresses
900 The DHCP server assign addresses to the guest starting from 10.0.2.15.
904 macaddr
=> get_standard_option
('mac-addr', {
905 description
=> "MAC address. That address must be unique withing your network. This is"
906 ." automatically generated if not specified.",
910 description
=> "Network Card Model. The 'virtio' model provides the best performance with"
911 ." very low CPU overhead. If your guest does not support this driver, it is usually"
912 ." best to use 'e1000'.",
913 enum
=> $nic_model_list,
916 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
917 bridge
=> get_standard_option
('pve-bridge-id', {
918 description
=> $net_fmt_bridge_descr,
923 minimum
=> 0, maximum
=> 16,
924 description
=> 'Number of packet queues to be used on the device.',
930 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
935 minimum
=> 1, maximum
=> 4094,
936 description
=> 'VLAN tag to apply to packets on this interface.',
941 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
942 description
=> 'VLAN trunks to pass through this interface.',
943 format_description
=> 'vlanid[;vlanid...]',
948 description
=> 'Whether this interface should be protected by the firewall.',
953 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
958 minimum
=> 1, maximum
=> 65520,
959 description
=> "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
966 type
=> 'string', format
=> $net_fmt,
967 description
=> "Specify network devices.",
970 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
975 format
=> 'pve-ipv4-config',
976 format_description
=> 'IPv4Format/CIDR',
977 description
=> 'IPv4 address in CIDR format.',
984 format_description
=> 'GatewayIPv4',
985 description
=> 'Default gateway for IPv4 traffic.',
991 format
=> 'pve-ipv6-config',
992 format_description
=> 'IPv6Format/CIDR',
993 description
=> 'IPv6 address in CIDR format.',
1000 format_description
=> 'GatewayIPv6',
1001 description
=> 'Default gateway for IPv6 traffic.',
1006 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
1007 my $ipconfigdesc = {
1009 type
=> 'string', format
=> 'pve-qm-ipconfig',
1010 description
=> <<'EODESCR',
1011 cloud-init: Specify IP addresses and gateways for the corresponding interface.
1013 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
1015 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
1016 gateway should be provided.
1017 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
1018 cloud-init 19.4 or newer.
1020 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
1024 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
1026 for (my $i = 0; $i < $MAX_NETS; $i++) {
1027 $confdesc->{"net$i"} = $netdesc;
1028 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
1031 foreach my $key (keys %$confdesc_cloudinit) {
1032 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1035 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
1036 sub verify_volume_id_or_qm_path
{
1037 my ($volid, $noerr) = @_;
1039 return $volid if $volid eq 'none' || $volid eq 'cdrom';
1041 return verify_volume_id_or_absolute_path
($volid, $noerr);
1044 PVE
::JSONSchema
::register_format
('pve-volume-id-or-absolute-path', \
&verify_volume_id_or_absolute_path
);
1045 sub verify_volume_id_or_absolute_path
{
1046 my ($volid, $noerr) = @_;
1048 return $volid if $volid =~ m
|^/|;
1050 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
1061 type
=> 'string', format
=> 'pve-qm-usb-device',
1062 format_description
=> 'HOSTUSBDEVICE|spice',
1063 description
=> <<EODESCR,
1064 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1066 'bus-port(.port)*' (decimal numbers) or
1067 'vendor_id:product_id' (hexadeciaml numbers) or
1070 You can use the 'lsusb -t' command to list existing usb devices.
1072 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1073 machines - use with special care.
1075 The value 'spice' can be used to add a usb redirection devices for spice.
1081 description
=> "Specifies whether if given host option is a USB3 device or port.",
1088 type
=> 'string', format
=> $usb_fmt,
1089 description
=> "Configure an USB device (n is 0 to 4).",
1091 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1096 pattern
=> '(/dev/.+|socket)',
1097 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1098 verbose_description
=> <<EODESCR,
1099 Create a serial device inside the VM (n is 0 to 3), and pass through a
1100 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1101 host side (use 'qm terminal' to open a terminal connection).
1103 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1104 use with special care.
1106 CAUTION: Experimental! User reported problems with this option.
1113 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1114 description
=> "Map host parallel devices (n is 0 to 2).",
1115 verbose_description
=> <<EODESCR,
1116 Map host parallel devices (n is 0 to 2).
1118 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1119 machines - use with special care.
1121 CAUTION: Experimental! User reported problems with this option.
1125 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1126 $confdesc->{"parallel$i"} = $paralleldesc;
1129 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1130 $confdesc->{"serial$i"} = $serialdesc;
1133 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
1134 $confdesc->{"hostpci$i"} = $PVE::QemuServer
::PCI
::hostpcidesc
;
1137 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1138 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1141 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1142 $confdesc->{"usb$i"} = $usbdesc;
1150 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1151 . " Deprecated, use 'order=' instead.",
1152 pattern
=> '[acdn]{1,4}',
1153 format_description
=> "[acdn]{1,4}",
1155 # note: this is also the fallback if boot: is not given at all
1161 format
=> 'pve-qm-bootdev-list',
1162 format_description
=> "device[;device...]",
1163 description
=> <<EODESC,
1164 The guest will attempt to boot from devices in the order they appear here.
1166 Disks, optical drives and passed-through storage USB devices will be directly
1167 booted from, NICs will load PXE, and PCIe devices will either behave like disks
1168 (e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1170 Note that only devices in this list will be marked as bootable and thus loaded
1171 by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1172 (e.g. software-raid), you need to specify all of them here.
1174 Overrides the deprecated 'legacy=[acdn]*' value when given.
1178 PVE
::JSONSchema
::register_format
('pve-qm-boot', $boot_fmt);
1180 PVE
::JSONSchema
::register_format
('pve-qm-bootdev', \
&verify_bootdev
);
1181 sub verify_bootdev
{
1182 my ($dev, $noerr) = @_;
1184 my $special = $dev =~ m/^efidisk/ || $dev =~ m/^tpmstate/;
1185 return $dev if PVE
::QemuServer
::Drive
::is_valid_drivename
($dev) && !$special;
1189 return 0 if $dev !~ m/^$base\d+$/;
1190 return 0 if !$confdesc->{$dev};
1194 return $dev if $check->("net");
1195 return $dev if $check->("usb");
1196 return $dev if $check->("hostpci");
1199 die "invalid boot device '$dev'\n";
1202 sub print_bootorder
{
1204 return "" if !@$devs;
1205 my $data = { order
=> join(';', @$devs) };
1206 return PVE
::JSONSchema
::print_property_string
($data, $boot_fmt);
1209 my $kvm_api_version = 0;
1212 return $kvm_api_version if $kvm_api_version;
1214 open my $fh, '<', '/dev/kvm' or return;
1216 # 0xae00 => KVM_GET_API_VERSION
1217 $kvm_api_version = ioctl($fh, 0xae00, 0);
1220 return $kvm_api_version;
1223 my $kvm_user_version = {};
1226 sub kvm_user_version
{
1229 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1230 my $st = stat($binary);
1232 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1233 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1234 $cachedmtime == $st->mtime;
1236 $kvm_user_version->{$binary} = 'unknown';
1237 $kvm_mtime->{$binary} = $st->mtime;
1241 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1242 $kvm_user_version->{$binary} = $2;
1246 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1249 return $kvm_user_version->{$binary};
1252 my sub extract_version
{
1253 my ($machine_type, $version) = @_;
1254 $version = kvm_user_version
() if !defined($version);
1255 return PVE
::QemuServer
::Machine
::extract_version
($machine_type, $version)
1258 sub kernel_has_vhost_net
{
1259 return -c
'/dev/vhost-net';
1264 return defined($confdesc->{$key});
1268 sub get_cdrom_path
{
1270 return $cdrom_path if $cdrom_path;
1272 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1273 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1274 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1278 my ($storecfg, $vmid, $cdrom) = @_;
1280 if ($cdrom eq 'cdrom') {
1281 return get_cdrom_path
();
1282 } elsif ($cdrom eq 'none') {
1284 } elsif ($cdrom =~ m
|^/|) {
1287 return PVE
::Storage
::path
($storecfg, $cdrom);
1291 # try to convert old style file names to volume IDs
1292 sub filename_to_volume_id
{
1293 my ($vmid, $file, $media) = @_;
1295 if (!($file eq 'none' || $file eq 'cdrom' ||
1296 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1298 return if $file =~ m
|/|;
1300 if ($media && $media eq 'cdrom') {
1301 $file = "local:iso/$file";
1303 $file = "local:$vmid/$file";
1310 sub verify_media_type
{
1311 my ($opt, $vtype, $media) = @_;
1316 if ($media eq 'disk') {
1318 } elsif ($media eq 'cdrom') {
1321 die "internal error";
1324 return if ($vtype eq $etype);
1326 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1329 sub cleanup_drive_path
{
1330 my ($opt, $storecfg, $drive) = @_;
1332 # try to convert filesystem paths to volume IDs
1334 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1335 ($drive->{file
} !~ m
|^/dev/.+|) &&
1336 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1337 ($drive->{file
} !~ m/^\d+$/)) {
1338 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1339 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1341 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1342 verify_media_type
($opt, $vtype, $drive->{media
});
1343 $drive->{file
} = $volid;
1346 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1349 sub parse_hotplug_features
{
1354 return $res if $data eq '0';
1356 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1358 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1359 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1362 die "invalid hotplug feature '$feature'\n";
1368 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1369 sub pve_verify_hotplug_features
{
1370 my ($value, $noerr) = @_;
1372 return $value if parse_hotplug_features
($value);
1376 die "unable to parse hotplug option\n";
1380 my($fh, $noerr) = @_;
1383 my $SG_GET_VERSION_NUM = 0x2282;
1385 my $versionbuf = "\x00" x
8;
1386 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1388 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1391 my $version = unpack("I", $versionbuf);
1392 if ($version < 30000) {
1393 die "scsi generic interface too old\n" if !$noerr;
1397 my $buf = "\x00" x
36;
1398 my $sensebuf = "\x00" x
8;
1399 my $cmd = pack("C x3 C x1", 0x12, 36);
1401 # see /usr/include/scsi/sg.h
1402 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";
1405 $sg_io_hdr_t, ord('S'), -3, length($cmd), length($sensebuf), 0, length($buf), $buf, $cmd, $sensebuf, 6000
1408 $ret = ioctl($fh, $SG_IO, $packet);
1410 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1414 my @res = unpack($sg_io_hdr_t, $packet);
1415 if ($res[17] || $res[18]) {
1416 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1421 $res->@{qw(type removable vendor product revision)} = unpack("C C x6 A8 A16 A4", $buf);
1423 $res->{removable
} = $res->{removable
} & 128 ?
1 : 0;
1424 $res->{type
} &= 0x1F;
1432 my $fh = IO
::File-
>new("+<$path") || return;
1433 my $res = scsi_inquiry
($fh, 1);
1439 sub print_tabletdevice_full
{
1440 my ($conf, $arch) = @_;
1442 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1444 # we use uhci for old VMs because tablet driver was buggy in older qemu
1446 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1452 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1455 sub print_keyboarddevice_full
{
1456 my ($conf, $arch) = @_;
1458 return if $arch ne 'aarch64';
1460 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1463 my sub get_drive_id
{
1465 return "$drive->{interface}$drive->{index}";
1468 sub print_drivedevice_full
{
1469 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1474 my $drive_id = get_drive_id
($drive);
1475 if ($drive->{interface
} eq 'virtio') {
1476 my $pciaddr = print_pci_addr
("$drive_id", $bridges, $arch, $machine_type);
1477 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1478 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread
};
1479 } elsif ($drive->{interface
} eq 'scsi') {
1481 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1482 my $unit = $drive->{index} % $maxdev;
1483 my $devicetype = 'hd';
1485 if (drive_is_cdrom
($drive)) {
1488 if ($drive->{file
} =~ m
|^/|) {
1489 $path = $drive->{file
};
1490 if (my $info = path_is_scsi
($path)) {
1491 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1492 $devicetype = 'block';
1493 } elsif ($info->{type
} == 1) { # tape
1494 $devicetype = 'generic';
1498 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1501 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1502 my $version = extract_version
($machine_type, kvm_user_version
());
1503 if ($path =~ m/^iscsi\:\/\
// &&
1504 !min_version
($version, 4, 1)) {
1505 $devicetype = 'generic';
1509 if (!$conf->{scsihw
} || $conf->{scsihw
} =~ m/^lsi/ || $conf->{scsihw
} eq 'pvscsi') {
1510 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
1512 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1513 .",lun=$drive->{index}";
1515 $device .= ",drive=drive-$drive_id,id=$drive_id";
1517 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1518 $device .= ",rotation_rate=1";
1520 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1522 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1523 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1524 my $controller = int($drive->{index} / $maxdev);
1525 my $unit = $drive->{index} % $maxdev;
1526 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1528 $device = "ide-$devicetype";
1529 if ($drive->{interface
} eq 'ide') {
1530 $device .= ",bus=ide.$controller,unit=$unit";
1532 $device .= ",bus=ahci$controller.$unit";
1534 $device .= ",drive=drive-$drive_id,id=$drive_id";
1536 if ($devicetype eq 'hd') {
1537 if (my $model = $drive->{model
}) {
1538 $model = URI
::Escape
::uri_unescape
($model);
1539 $device .= ",model=$model";
1541 if ($drive->{ssd
}) {
1542 $device .= ",rotation_rate=1";
1545 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1546 } elsif ($drive->{interface
} eq 'usb') {
1548 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1550 die "unsupported interface type";
1553 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1555 if (my $serial = $drive->{serial
}) {
1556 $serial = URI
::Escape
::uri_unescape
($serial);
1557 $device .= ",serial=$serial";
1564 sub get_initiator_name
{
1567 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return;
1568 while (defined(my $line = <$fh>)) {
1569 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1578 sub print_drive_commandline_full
{
1579 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1582 my $volid = $drive->{file
};
1583 my $format = $drive->{format
};
1584 my $drive_id = get_drive_id
($drive);
1586 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1587 my $scfg = $storeid ? PVE
::Storage
::storage_config
($storecfg, $storeid) : undef;
1589 if (drive_is_cdrom
($drive)) {
1590 $path = get_iso_path
($storecfg, $vmid, $volid);
1591 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
1594 $path = PVE
::Storage
::path
($storecfg, $volid);
1595 $format //= qemu_img_format
($scfg, $volname);
1602 my $is_rbd = $path =~ m/^rbd:/;
1605 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1606 foreach my $o (@qemu_drive_options) {
1607 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1610 # snapshot only accepts on|off
1611 if (defined($drive->{snapshot
})) {
1612 my $v = $drive->{snapshot
} ?
'on' : 'off';
1613 $opts .= ",snapshot=$v";
1616 if (defined($drive->{ro
})) { # ro maps to QEMUs `readonly`, which accepts `on` or `off` only
1617 $opts .= ",readonly=" . ($drive->{ro
} ?
'on' : 'off');
1620 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1621 my ($dir, $qmpname) = @$type;
1622 if (my $v = $drive->{"mbps$dir"}) {
1623 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1625 if (my $v = $drive->{"mbps${dir}_max"}) {
1626 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1628 if (my $v = $drive->{"bps${dir}_max_length"}) {
1629 $opts .= ",throttling.bps$qmpname-max-length=$v";
1631 if (my $v = $drive->{"iops${dir}"}) {
1632 $opts .= ",throttling.iops$qmpname=$v";
1634 if (my $v = $drive->{"iops${dir}_max"}) {
1635 $opts .= ",throttling.iops$qmpname-max=$v";
1637 if (my $v = $drive->{"iops${dir}_max_length"}) {
1638 $opts .= ",throttling.iops$qmpname-max-length=$v";
1643 $format = "rbd" if $is_rbd;
1644 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1646 $opts .= ",format=alloc-track,file.driver=$format";
1648 $opts .= ",format=$format";
1651 my $cache_direct = 0;
1653 if (my $cache = $drive->{cache
}) {
1654 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1655 } elsif (!drive_is_cdrom
($drive) && !($scfg && $scfg->{type
} eq 'btrfs' && !$scfg->{nocow
})) {
1656 $opts .= ",cache=none";
1660 # io_uring with cache mode writeback or writethrough on krbd will hang...
1661 my $rbd_no_io_uring = $scfg && $scfg->{type
} eq 'rbd' && $scfg->{krbd
} && !$cache_direct;
1663 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1664 # sometimes, just plain disable...
1665 my $lvm_no_io_uring = $scfg && $scfg->{type
} eq 'lvm';
1667 if (!$drive->{aio
}) {
1668 if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring) {
1669 # io_uring supports all cache modes
1670 $opts .= ",aio=io_uring";
1672 # aio native works only with O_DIRECT
1674 $opts .= ",aio=native";
1676 $opts .= ",aio=threads";
1681 if (!drive_is_cdrom
($drive)) {
1683 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1684 $detectzeroes = 'off';
1685 } elsif ($drive->{discard
}) {
1686 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1688 # This used to be our default with discard not being specified:
1689 $detectzeroes = 'on';
1692 # note: 'detect-zeroes' works per blockdev and we want it to persist
1693 # after the alloc-track is removed, so put it on 'file' directly
1694 my $dz_param = $pbs_name ?
"file.detect-zeroes" : "detect-zeroes";
1695 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
1699 $opts .= ",backing=$pbs_name";
1700 $opts .= ",auto-remove=on";
1703 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1704 my $file_param = "file";
1706 # non-rbd drivers require the underlying file to be a seperate block
1707 # node, so add a second .file indirection
1708 $file_param .= ".file" if !$is_rbd;
1709 $file_param .= ".filename";
1711 my $pathinfo = $path ?
"$file_param=$path," : '';
1713 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1716 sub print_pbs_blockdev
{
1717 my ($pbs_conf, $pbs_name) = @_;
1718 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1719 $blockdev .= ",repository=$pbs_conf->{repository}";
1720 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1721 $blockdev .= ",archive=$pbs_conf->{archive}";
1722 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile
};
1726 sub print_netdevice_full
{
1727 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1729 my $device = $net->{model
};
1730 if ($net->{model
} eq 'virtio') {
1731 $device = 'virtio-net-pci';
1734 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1735 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1736 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1737 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1738 # and out of each queue plus one config interrupt and control vector queue
1739 my $vectors = $net->{queues
} * 2 + 2;
1740 $tmpstr .= ",vectors=$vectors,mq=on";
1742 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1744 if (my $mtu = $net->{mtu
}) {
1745 if ($net->{model
} eq 'virtio' && $net->{bridge
}) {
1746 my $bridge_mtu = PVE
::Network
::read_bridge_mtu
($net->{bridge
});
1749 } elsif ($mtu < 576) {
1750 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1751 } elsif ($mtu > $bridge_mtu) {
1752 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1754 $tmpstr .= ",host_mtu=$mtu";
1756 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
1760 if ($use_old_bios_files) {
1762 if ($device eq 'virtio-net-pci') {
1763 $romfile = 'pxe-virtio.rom';
1764 } elsif ($device eq 'e1000') {
1765 $romfile = 'pxe-e1000.rom';
1766 } elsif ($device eq 'e1000e') {
1767 $romfile = 'pxe-e1000e.rom';
1768 } elsif ($device eq 'ne2k') {
1769 $romfile = 'pxe-ne2k_pci.rom';
1770 } elsif ($device eq 'pcnet') {
1771 $romfile = 'pxe-pcnet.rom';
1772 } elsif ($device eq 'rtl8139') {
1773 $romfile = 'pxe-rtl8139.rom';
1775 $tmpstr .= ",romfile=$romfile" if $romfile;
1781 sub print_netdev_full
{
1782 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1785 if ($netid =~ m/^net(\d+)$/) {
1789 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1791 my $ifname = "tap${vmid}i$i";
1793 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1794 die "interface name '$ifname' is too long (max 15 character)\n"
1795 if length($ifname) >= 16;
1797 my $vhostparam = '';
1798 if (is_native
($arch)) {
1799 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1802 my $vmname = $conf->{name
} || "vm$vmid";
1805 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1807 if ($net->{bridge
}) {
1808 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1809 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1811 $netdev = "type=user,id=$netid,hostname=$vmname";
1814 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1820 'cirrus' => 'cirrus-vga',
1822 'vmware' => 'vmware-svga',
1823 'virtio' => 'virtio-vga',
1824 'virtio-gl' => 'virtio-vga-gl',
1827 sub print_vga_device
{
1828 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1830 my $type = $vga_map->{$vga->{type
}};
1831 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1832 $type = 'virtio-gpu';
1834 my $vgamem_mb = $vga->{memory
};
1836 my $max_outputs = '';
1838 $type = $id ?
'qxl' : 'qxl-vga';
1840 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1841 # set max outputs so linux can have up to 4 qxl displays with one device
1842 if (min_version
($machine_version, 4, 1)) {
1843 $max_outputs = ",max_outputs=4";
1848 die "no devicetype for $vga->{type}\n" if !$type;
1852 if ($vga->{type
} =~ /^virtio/) {
1853 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1854 $memory = ",max_hostmem=$bytes";
1856 # from https://www.spice-space.org/multiple-monitors.html
1857 $memory = ",vgamem_mb=$vga->{memory}";
1858 my $ram = $vgamem_mb * 4;
1859 my $vram = $vgamem_mb * 2;
1860 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1862 $memory = ",vgamem_mb=$vga->{memory}";
1864 } elsif ($qxlnum && $id) {
1865 $memory = ",ram_size=67108864,vram_size=33554432";
1869 if ($type eq 'VGA' && windows_version
($conf->{ostype
})) {
1870 $edidoff=",edid=off" if (!defined($conf->{bios
}) || $conf->{bios
} ne 'ovmf');
1873 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1874 my $vgaid = "vga" . ($id // '');
1876 if ($q35 && $vgaid eq 'vga') {
1877 # the first display uses pcie.0 bus on q35 machines
1878 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1880 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1883 if ($vga->{type
} eq 'virtio-gl') {
1884 my $base = '/usr/lib/x86_64-linux-gnu/lib';
1885 die "missing libraries for '$vga->{type}' detected! Please install 'libgl1' and 'libegl1'\n"
1886 if !-e
"${base}EGL.so.1" || !-e
"${base}GL.so.1";
1888 die "no DRM render node detected (/dev/dri/renderD*), no GPU? - needed for '$vga->{type}' display\n"
1889 if !PVE
::Tools
::dir_glob_regex
('/dev/dri/', "renderD.*");
1892 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
1895 sub parse_number_sets
{
1898 foreach my $part (split(/;/, $set)) {
1899 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1900 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1901 push @$res, [ $1, $2 ];
1903 die "invalid range: $part\n";
1912 my $res = parse_property_string
($numa_fmt, $data);
1913 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1914 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1918 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1922 my $res = eval { parse_property_string
($net_fmt, $data) };
1927 if (!defined($res->{macaddr
})) {
1928 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1929 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1934 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1935 sub parse_ipconfig
{
1938 my $res = eval { parse_property_string
($ipconfig_fmt, $data) };
1944 if ($res->{gw
} && !$res->{ip
}) {
1945 warn 'gateway specified without specifying an IP address';
1948 if ($res->{gw6
} && !$res->{ip6
}) {
1949 warn 'IPv6 gateway specified without specifying an IPv6 address';
1952 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1953 warn 'gateway specified together with DHCP';
1956 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1958 warn "IPv6 gateway specified together with $res->{ip6} address";
1962 if (!$res->{ip
} && !$res->{ip6
}) {
1963 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1972 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1975 sub add_random_macs
{
1976 my ($settings) = @_;
1978 foreach my $opt (keys %$settings) {
1979 next if $opt !~ m/^net(\d+)$/;
1980 my $net = parse_net
($settings->{$opt});
1982 $settings->{$opt} = print_net
($net);
1986 sub vm_is_volid_owner
{
1987 my ($storecfg, $vmid, $volid) = @_;
1989 if ($volid !~ m
|^/|) {
1991 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1992 if ($owner && ($owner == $vmid)) {
2000 sub vmconfig_register_unused_drive
{
2001 my ($storecfg, $vmid, $conf, $drive) = @_;
2003 if (drive_is_cloudinit
($drive)) {
2004 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2006 } elsif (!drive_is_cdrom
($drive)) {
2007 my $volid = $drive->{file
};
2008 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2009 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2014 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
2018 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2019 format_description
=> 'UUID',
2020 description
=> "Set SMBIOS1 UUID.",
2025 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2026 format_description
=> 'Base64 encoded string',
2027 description
=> "Set SMBIOS1 version.",
2032 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2033 format_description
=> 'Base64 encoded string',
2034 description
=> "Set SMBIOS1 serial number.",
2039 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2040 format_description
=> 'Base64 encoded string',
2041 description
=> "Set SMBIOS1 manufacturer.",
2046 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2047 format_description
=> 'Base64 encoded string',
2048 description
=> "Set SMBIOS1 product ID.",
2053 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2054 format_description
=> 'Base64 encoded string',
2055 description
=> "Set SMBIOS1 SKU string.",
2060 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2061 format_description
=> 'Base64 encoded string',
2062 description
=> "Set SMBIOS1 family string.",
2067 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
2075 my $res = eval { parse_property_string
($smbios1_fmt, $data) };
2082 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2085 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2087 sub parse_watchdog
{
2092 my $res = eval { parse_property_string
($watchdog_fmt, $value) };
2097 sub parse_guest_agent
{
2100 return {} if !defined($conf->{agent
});
2102 my $res = eval { parse_property_string
($agent_fmt, $conf->{agent
}) };
2105 # if the agent is disabled ignore the other potentially set properties
2106 return {} if !$res->{enabled
};
2111 my ($conf, $key) = @_;
2112 return undef if !defined($conf->{agent
});
2114 my $agent = parse_guest_agent
($conf);
2115 return $agent->{$key};
2121 return {} if !$value;
2122 my $res = eval { parse_property_string
($vga_fmt, $value) };
2132 my $res = eval { parse_property_string
($rng_fmt, $value) };
2137 sub parse_meta_info
{
2142 my $res = eval { parse_property_string
($meta_info_fmt, $value) };
2147 sub new_meta_info_string
{
2148 my () = @_; # for now do not allow to override any value
2150 return PVE
::JSONSchema
::print_property_string
(
2152 'creation-qemu' => kvm_user_version
(),
2153 ctime
=> "". int(time()),
2159 sub qemu_created_version_fixups
{
2160 my ($conf, $forcemachine, $kvmver) = @_;
2162 my $meta = parse_meta_info
($conf->{meta
}) // {};
2163 my $forced_vers = PVE
::QemuServer
::Machine
::extract_version
($forcemachine);
2165 # check if we need to apply some handling for VMs that always use the latest machine version but
2166 # had a machine version transition happen that affected HW such that, e.g., an OS config change
2167 # would be required (we do not want to pin machine version for non-windows OS type)
2169 (!defined($conf->{machine
}) || $conf->{machine
} =~ m/^(?:pc|q35|virt)$/) # non-versioned machine
2170 && (!defined($meta->{'creation-qemu'}) || !min_version
($meta->{'creation-qemu'}, 6, 1)) # created before 6.1
2171 && (!$forced_vers || min_version
($forced_vers, 6, 1)) # handle snapshot-rollback/migrations
2172 && min_version
($kvmver, 6, 1) # only need to apply the change since 6.1
2174 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
2175 if ($q35 && $conf->{ostype
} && $conf->{ostype
} eq 'l26') {
2176 # this changed to default-on in Q 6.1 for q35 machines, it will mess with PCI slot view
2177 # and thus with the predictable interface naming of systemd
2178 return ['-global', 'ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off'];
2184 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2185 sub verify_usb_device
{
2186 my ($value, $noerr) = @_;
2188 return $value if parse_usb_device
($value);
2192 die "unable to parse usb device\n";
2195 # add JSON properties for create and set function
2196 sub json_config_properties
{
2197 my ($prop, $with_disk_alloc) = @_;
2199 my $skip_json_config_opts = {
2203 runningmachine
=> 1,
2208 foreach my $opt (keys %$confdesc) {
2209 next if $skip_json_config_opts->{$opt};
2211 if ($with_disk_alloc && is_valid_drivename
($opt)) {
2212 $prop->{$opt} = $PVE::QemuServer
::Drive
::drivedesc_hash_with_alloc-
>{$opt};
2214 $prop->{$opt} = $confdesc->{$opt};
2221 # Properties that we can read from an OVF file
2222 sub json_ovf_properties
{
2225 for my $device (PVE
::QemuServer
::Drive
::valid_drive_names
()) {
2226 $prop->{$device} = {
2228 format
=> 'pve-volume-id-or-absolute-path',
2229 description
=> "Disk image that gets imported to $device",
2236 description
=> "The number of CPU cores.",
2241 description
=> "Amount of RAM for the VM in MB.",
2246 description
=> "Name of the VM.",
2253 # return copy of $confdesc_cloudinit to generate documentation
2254 sub cloudinit_config_properties
{
2256 return dclone
($confdesc_cloudinit);
2260 my ($key, $value) = @_;
2262 die "unknown setting '$key'\n" if !$confdesc->{$key};
2264 my $type = $confdesc->{$key}->{type
};
2266 if (!defined($value)) {
2267 die "got undefined value\n";
2270 if ($value =~ m/[\n\r]/) {
2271 die "property contains a line feed\n";
2274 if ($type eq 'boolean') {
2275 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2276 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2277 die "type check ('boolean') failed - got '$value'\n";
2278 } elsif ($type eq 'integer') {
2279 return int($1) if $value =~ m/^(\d+)$/;
2280 die "type check ('integer') failed - got '$value'\n";
2281 } elsif ($type eq 'number') {
2282 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2283 die "type check ('number') failed - got '$value'\n";
2284 } elsif ($type eq 'string') {
2285 if (my $fmt = $confdesc->{$key}->{format
}) {
2286 PVE
::JSONSchema
::check_format
($fmt, $value);
2289 $value =~ s/^\"(.*)\"$/$1/;
2292 die "internal error"
2297 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
2299 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2301 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2303 if ($conf->{template
}) {
2304 # check if any base image is still used by a linked clone
2305 PVE
::QemuConfig-
>foreach_volume_full($conf, { include_unused
=> 1 }, sub {
2306 my ($ds, $drive) = @_;
2307 return if drive_is_cdrom
($drive);
2309 my $volid = $drive->{file
};
2310 return if !$volid || $volid =~ m
|^/|;
2312 die "base volume '$volid' is still in use by linked cloned\n"
2313 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2319 my $remove_owned_drive = sub {
2320 my ($ds, $drive) = @_;
2321 return if drive_is_cdrom
($drive, 1);
2323 my $volid = $drive->{file
};
2324 return if !$volid || $volid =~ m
|^/|;
2325 return if $volids->{$volid};
2327 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2328 return if !$path || !$owner || ($owner != $vmid);
2330 $volids->{$volid} = 1;
2331 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2332 warn "Could not remove disk '$volid', check manually: $@" if $@;
2335 # only remove disks owned by this VM (referenced in the config)
2336 my $include_opts = {
2337 include_unused
=> 1,
2338 extra_keys
=> ['vmstate'],
2340 PVE
::QemuConfig-
>foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2342 for my $snap (values %{$conf->{snapshots
}}) {
2343 next if !defined($snap->{vmstate
});
2344 my $drive = PVE
::QemuConfig-
>parse_volume('vmstate', $snap->{vmstate
}, 1);
2345 next if !defined($drive);
2346 $remove_owned_drive->('vmstate', $drive);
2349 PVE
::QemuConfig-
>foreach_volume_full($conf->{pending
}, $include_opts, $remove_owned_drive);
2351 if ($purge_unreferenced) { # also remove unreferenced disk
2352 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid, undef, 'images');
2353 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2354 my ($volid, $sid, $volname, $d) = @_;
2355 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2360 if (defined $replacement_conf) {
2361 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2363 PVE
::QemuConfig-
>destroy_config($vmid);
2367 sub parse_vm_config
{
2368 my ($filename, $raw, $strict) = @_;
2370 return if !defined($raw);
2373 digest
=> Digest
::SHA
::sha1_hex
($raw),
2378 my $handle_error = sub {
2388 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2389 || die "got strange filename '$filename'";
2397 my @lines = split(/\n/, $raw);
2398 foreach my $line (@lines) {
2399 next if $line =~ m/^\s*$/;
2401 if ($line =~ m/^\[PENDING\]\s*$/i) {
2402 $section = 'pending';
2403 if (defined($descr)) {
2405 $conf->{description
} = $descr;
2408 $conf = $res->{$section} = {};
2411 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2413 if (defined($descr)) {
2415 $conf->{description
} = $descr;
2418 $conf = $res->{snapshots
}->{$section} = {};
2422 if ($line =~ m/^\#(.*)$/) {
2423 $descr = '' if !defined($descr);
2424 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2428 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2429 $descr = '' if !defined($descr);
2430 $descr .= PVE
::Tools
::decode_text
($2);
2431 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2432 $conf->{snapstate
} = $1;
2433 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2436 $conf->{$key} = $value;
2437 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2439 if ($section eq 'pending') {
2440 $conf->{delete} = $value; # we parse this later
2442 $handle_error->("vm $vmid - property 'delete' is only allowed in [PENDING]\n");
2444 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2447 eval { $value = check_type
($key, $value); };
2449 $handle_error->("vm $vmid - unable to parse value of '$key' - $@");
2451 $key = 'ide2' if $key eq 'cdrom';
2452 my $fmt = $confdesc->{$key}->{format
};
2453 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2454 my $v = parse_drive
($key, $value);
2455 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2456 $v->{file
} = $volid;
2457 $value = print_drive
($v);
2459 $handle_error->("vm $vmid - unable to parse value of '$key'\n");
2464 $conf->{$key} = $value;
2467 $handle_error->("vm $vmid - unable to parse config: $line\n");
2471 if (defined($descr)) {
2473 $conf->{description
} = $descr;
2475 delete $res->{snapstate
}; # just to be sure
2480 sub write_vm_config
{
2481 my ($filename, $conf) = @_;
2483 delete $conf->{snapstate
}; # just to be sure
2485 if ($conf->{cdrom
}) {
2486 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2487 $conf->{ide2
} = $conf->{cdrom
};
2488 delete $conf->{cdrom
};
2491 # we do not use 'smp' any longer
2492 if ($conf->{sockets
}) {
2493 delete $conf->{smp
};
2494 } elsif ($conf->{smp
}) {
2495 $conf->{sockets
} = $conf->{smp
};
2496 delete $conf->{cores
};
2497 delete $conf->{smp
};
2500 my $used_volids = {};
2502 my $cleanup_config = sub {
2503 my ($cref, $pending, $snapname) = @_;
2505 foreach my $key (keys %$cref) {
2506 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2507 $key eq 'snapstate' || $key eq 'pending';
2508 my $value = $cref->{$key};
2509 if ($key eq 'delete') {
2510 die "propertry 'delete' is only allowed in [PENDING]\n"
2512 # fixme: check syntax?
2515 eval { $value = check_type
($key, $value); };
2516 die "unable to parse value of '$key' - $@" if $@;
2518 $cref->{$key} = $value;
2520 if (!$snapname && is_valid_drivename
($key)) {
2521 my $drive = parse_drive
($key, $value);
2522 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2527 &$cleanup_config($conf);
2529 &$cleanup_config($conf->{pending
}, 1);
2531 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2532 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2533 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2536 # remove 'unusedX' settings if we re-add a volume
2537 foreach my $key (keys %$conf) {
2538 my $value = $conf->{$key};
2539 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2540 delete $conf->{$key};
2544 my $generate_raw_config = sub {
2545 my ($conf, $pending) = @_;
2549 # add description as comment to top of file
2550 if (defined(my $descr = $conf->{description
})) {
2552 foreach my $cl (split(/\n/, $descr)) {
2553 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2556 $raw .= "#\n" if $pending;
2560 foreach my $key (sort keys %$conf) {
2561 next if $key =~ /^(digest|description|pending|snapshots)$/;
2562 $raw .= "$key: $conf->{$key}\n";
2567 my $raw = &$generate_raw_config($conf);
2569 if (scalar(keys %{$conf->{pending
}})){
2570 $raw .= "\n[PENDING]\n";
2571 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2574 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2575 $raw .= "\n[$snapname]\n";
2576 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2586 # we use static defaults from our JSON schema configuration
2587 foreach my $key (keys %$confdesc) {
2588 if (defined(my $default = $confdesc->{$key}->{default})) {
2589 $res->{$key} = $default;
2597 my $vmlist = PVE
::Cluster
::get_vmlist
();
2599 return $res if !$vmlist || !$vmlist->{ids
};
2600 my $ids = $vmlist->{ids
};
2601 my $nodename = nodename
();
2603 foreach my $vmid (keys %$ids) {
2604 my $d = $ids->{$vmid};
2605 next if !$d->{node
} || $d->{node
} ne $nodename;
2606 next if !$d->{type
} || $d->{type
} ne 'qemu';
2607 $res->{$vmid}->{exists} = 1;
2612 # test if VM uses local resources (to prevent migration)
2613 sub check_local_resources
{
2614 my ($conf, $noerr) = @_;
2618 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2619 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2621 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2623 foreach my $k (keys %$conf) {
2624 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2625 # sockets are safe: they will recreated be on the target side post-migrate
2626 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2627 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2630 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2635 # check if used storages are available on all nodes (use by migrate)
2636 sub check_storage_availability
{
2637 my ($storecfg, $conf, $node) = @_;
2639 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2640 my ($ds, $drive) = @_;
2642 my $volid = $drive->{file
};
2645 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2648 # check if storage is available on both nodes
2649 my $scfg = PVE
::Storage
::storage_check_enabled
($storecfg, $sid);
2650 PVE
::Storage
::storage_check_enabled
($storecfg, $sid, $node);
2652 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $volid);
2654 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2655 if !$scfg->{content
}->{$vtype};
2659 # list nodes where all VM images are available (used by has_feature API)
2661 my ($conf, $storecfg) = @_;
2663 my $nodelist = PVE
::Cluster
::get_nodelist
();
2664 my $nodehash = { map { $_ => 1 } @$nodelist };
2665 my $nodename = nodename
();
2667 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2668 my ($ds, $drive) = @_;
2670 my $volid = $drive->{file
};
2673 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2675 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2676 if ($scfg->{disable
}) {
2678 } elsif (my $avail = $scfg->{nodes
}) {
2679 foreach my $node (keys %$nodehash) {
2680 delete $nodehash->{$node} if !$avail->{$node};
2682 } elsif (!$scfg->{shared
}) {
2683 foreach my $node (keys %$nodehash) {
2684 delete $nodehash->{$node} if $node ne $nodename
2693 sub check_local_storage_availability
{
2694 my ($conf, $storecfg) = @_;
2696 my $nodelist = PVE
::Cluster
::get_nodelist
();
2697 my $nodehash = { map { $_ => {} } @$nodelist };
2699 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2700 my ($ds, $drive) = @_;
2702 my $volid = $drive->{file
};
2705 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2707 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2709 if ($scfg->{disable
}) {
2710 foreach my $node (keys %$nodehash) {
2711 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2713 } elsif (my $avail = $scfg->{nodes
}) {
2714 foreach my $node (keys %$nodehash) {
2715 if (!$avail->{$node}) {
2716 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2723 foreach my $node (values %$nodehash) {
2724 if (my $unavail = $node->{unavailable_storages
}) {
2725 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2732 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2734 my ($vmid, $nocheck, $node) = @_;
2736 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2737 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2742 my $vzlist = config_list
();
2744 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2746 while (defined(my $de = $fd->read)) {
2747 next if $de !~ m/^(\d+)\.pid$/;
2749 next if !defined($vzlist->{$vmid});
2750 if (my $pid = check_running
($vmid)) {
2751 $vzlist->{$vmid}->{pid
} = $pid;
2758 our $vmstatus_return_properties = {
2759 vmid
=> get_standard_option
('pve-vmid'),
2761 description
=> "Qemu process status.",
2763 enum
=> ['stopped', 'running'],
2766 description
=> "Maximum memory in bytes.",
2769 renderer
=> 'bytes',
2772 description
=> "Root disk size in bytes.",
2775 renderer
=> 'bytes',
2778 description
=> "VM name.",
2783 description
=> "Qemu QMP agent status.",
2788 description
=> "PID of running qemu process.",
2793 description
=> "Uptime.",
2796 renderer
=> 'duration',
2799 description
=> "Maximum usable CPUs.",
2804 description
=> "The current config lock, if any.",
2809 description
=> "The current configured tags, if any",
2813 'running-machine' => {
2814 description
=> "The currently running machine type (if running).",
2819 description
=> "The currently running QEMU version (if running).",
2825 my $last_proc_pid_stat;
2827 # get VM status information
2828 # This must be fast and should not block ($full == false)
2829 # We only query KVM using QMP if $full == true (this can be slow)
2831 my ($opt_vmid, $full) = @_;
2835 my $storecfg = PVE
::Storage
::config
();
2837 my $list = vzlist
();
2838 my $defaults = load_defaults
();
2840 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2842 my $cpucount = $cpuinfo->{cpus
} || 1;
2844 foreach my $vmid (keys %$list) {
2845 next if $opt_vmid && ($vmid ne $opt_vmid);
2847 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2849 my $d = { vmid
=> int($vmid) };
2850 $d->{pid
} = int($list->{$vmid}->{pid
}) if $list->{$vmid}->{pid
};
2852 # fixme: better status?
2853 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2855 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2856 if (defined($size)) {
2857 $d->{disk
} = 0; # no info available
2858 $d->{maxdisk
} = $size;
2864 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2865 * ($conf->{cores
} || $defaults->{cores
});
2866 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2867 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2869 $d->{name
} = $conf->{name
} || "VM $vmid";
2870 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2871 : $defaults->{memory
}*(1024*1024);
2873 if ($conf->{balloon
}) {
2874 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2875 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2876 : $defaults->{shares
};
2887 $d->{diskwrite
} = 0;
2889 $d->{template
} = 1 if PVE
::QemuConfig-
>is_template($conf);
2891 $d->{serial
} = 1 if conf_has_serial
($conf);
2892 $d->{lock} = $conf->{lock} if $conf->{lock};
2893 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2898 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2899 foreach my $dev (keys %$netdev) {
2900 next if $dev !~ m/^tap([1-9]\d*)i/;
2902 my $d = $res->{$vmid};
2905 $d->{netout
} += $netdev->{$dev}->{receive
};
2906 $d->{netin
} += $netdev->{$dev}->{transmit
};
2909 $d->{nics
}->{$dev}->{netout
} = int($netdev->{$dev}->{receive
});
2910 $d->{nics
}->{$dev}->{netin
} = int($netdev->{$dev}->{transmit
});
2915 my $ctime = gettimeofday
;
2917 foreach my $vmid (keys %$list) {
2919 my $d = $res->{$vmid};
2920 my $pid = $d->{pid
};
2923 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2924 next if !$pstat; # not running
2926 my $used = $pstat->{utime} + $pstat->{stime
};
2928 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2930 if ($pstat->{vsize
}) {
2931 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2934 my $old = $last_proc_pid_stat->{$pid};
2936 $last_proc_pid_stat->{$pid} = {
2944 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2946 if ($dtime > 1000) {
2947 my $dutime = $used - $old->{used
};
2949 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2950 $last_proc_pid_stat->{$pid} = {
2956 $d->{cpu
} = $old->{cpu
};
2960 return $res if !$full;
2962 my $qmpclient = PVE
::QMPClient-
>new();
2964 my $ballooncb = sub {
2965 my ($vmid, $resp) = @_;
2967 my $info = $resp->{'return'};
2968 return if !$info->{max_mem
};
2970 my $d = $res->{$vmid};
2972 # use memory assigned to VM
2973 $d->{maxmem
} = $info->{max_mem
};
2974 $d->{balloon
} = $info->{actual
};
2976 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2977 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2978 $d->{freemem
} = $info->{free_mem
};
2981 $d->{ballooninfo
} = $info;
2984 my $blockstatscb = sub {
2985 my ($vmid, $resp) = @_;
2986 my $data = $resp->{'return'} || [];
2987 my $totalrdbytes = 0;
2988 my $totalwrbytes = 0;
2990 for my $blockstat (@$data) {
2991 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2992 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2994 $blockstat->{device
} =~ s/drive-//;
2995 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2997 $res->{$vmid}->{diskread
} = $totalrdbytes;
2998 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3001 my $machinecb = sub {
3002 my ($vmid, $resp) = @_;
3003 my $data = $resp->{'return'} || [];
3005 $res->{$vmid}->{'running-machine'} =
3006 PVE
::QemuServer
::Machine
::current_from_query_machines
($data);
3009 my $versioncb = sub {
3010 my ($vmid, $resp) = @_;
3011 my $data = $resp->{'return'} // {};
3012 my $version = 'unknown';
3014 if (my $v = $data->{qemu
}) {
3015 $version = $v->{major
} . "." . $v->{minor
} . "." . $v->{micro
};
3018 $res->{$vmid}->{'running-qemu'} = $version;
3021 my $statuscb = sub {
3022 my ($vmid, $resp) = @_;
3024 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3025 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
3026 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
3027 # this fails if ballon driver is not loaded, so this must be
3028 # the last commnand (following command are aborted if this fails).
3029 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3031 my $status = 'unknown';
3032 if (!defined($status = $resp->{'return'}->{status
})) {
3033 warn "unable to get VM status\n";
3037 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3040 foreach my $vmid (keys %$list) {
3041 next if $opt_vmid && ($vmid ne $opt_vmid);
3042 next if !$res->{$vmid}->{pid
}; # not running
3043 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3046 $qmpclient->queue_execute(undef, 2);
3048 foreach my $vmid (keys %$list) {
3049 next if $opt_vmid && ($vmid ne $opt_vmid);
3050 next if !$res->{$vmid}->{pid
}; #not running
3052 # we can't use the $qmpclient since it might have already aborted on
3053 # 'query-balloon', but this might also fail for older versions...
3054 my $qemu_support = eval { mon_cmd
($vmid, "query-proxmox-support") };
3055 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
3058 foreach my $vmid (keys %$list) {
3059 next if $opt_vmid && ($vmid ne $opt_vmid);
3060 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3066 sub conf_has_serial
{
3069 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3070 if ($conf->{"serial$i"}) {
3078 sub conf_has_audio
{
3079 my ($conf, $id) = @_;
3082 my $audio = $conf->{"audio$id"};
3083 return if !defined($audio);
3085 my $audioproperties = parse_property_string
($audio_fmt, $audio);
3086 my $audiodriver = $audioproperties->{driver
} // 'spice';
3089 dev
=> $audioproperties->{device
},
3090 dev_id
=> "audiodev$id",
3091 backend
=> $audiodriver,
3092 backend_id
=> "$audiodriver-backend${id}",
3097 my ($audio, $audiopciaddr, $machine_version) = @_;
3101 my $id = $audio->{dev_id
};
3103 if (min_version
($machine_version, 4, 2)) {
3104 $audiodev = ",audiodev=$audio->{backend_id}";
3107 if ($audio->{dev
} eq 'AC97') {
3108 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
3109 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
3110 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3111 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
3112 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
3114 die "unkown audio device '$audio->{dev}', implement me!";
3117 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3125 socket => "/var/run/qemu-server/$vmid.swtpm",
3126 pid
=> "/var/run/qemu-server/$vmid.swtpm.pid",
3130 sub add_tpm_device
{
3131 my ($vmid, $devices, $conf) = @_;
3133 return if !$conf->{tpmstate0
};
3135 my $paths = get_tpm_paths
($vmid);
3137 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
3138 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
3139 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
3143 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
3145 return if !$tpmdrive;
3148 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
3149 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
3151 $state = PVE
::Storage
::map_volume
($storecfg, $tpm->{file
});
3153 $state = $tpm->{file
};
3156 my $paths = get_tpm_paths
($vmid);
3158 # during migration, we will get state from remote
3161 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3168 "--create-platform-cert",
3171 "/etc/swtpm_setup.conf", # do not use XDG configs
3173 "0", # force creation as root, error if not possible
3174 "--not-overwrite", # ignore existing state, do not modify
3177 push @$setup_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3178 # TPM 2.0 supports ECC crypto, use if possible
3179 push @$setup_cmd, "--ecc" if $tpm->{version
} eq 'v2.0';
3181 run_command
($setup_cmd, outfunc
=> sub {
3182 print "swtpm_setup: $1\n";
3186 my $emulator_cmd = [
3190 "backend-uri=file://$state,mode=0600",
3192 "type=unixio,path=$paths->{socket},mode=0600",
3194 "file=$paths->{pid}",
3195 "--terminate", # terminate on QEMU disconnect
3198 push @$emulator_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3199 run_command
($emulator_cmd, outfunc
=> sub { print $1; });
3201 my $tries = 100; # swtpm may take a bit to start before daemonizing, wait up to 5s for pid
3202 while (! -e
$paths->{pid
}) {
3203 die "failed to start swtpm: pid file '$paths->{pid}' wasn't created.\n" if --$tries == 0;
3207 # return untainted PID of swtpm daemon so it can be killed on error
3208 file_read_firstline
($paths->{pid
}) =~ m/(\d+)/;
3212 sub vga_conf_has_spice
{
3215 my $vgaconf = parse_vga
($vga);
3216 my $vgatype = $vgaconf->{type
};
3217 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3224 return get_host_arch
() eq $arch;
3229 return $conf->{arch
} // get_host_arch
();
3232 my $default_machines = {
3237 sub get_installed_machine_version
{
3238 my ($kvmversion) = @_;
3239 $kvmversion = kvm_user_version
() if !defined($kvmversion);
3240 $kvmversion =~ m/^(\d+\.\d+)/;
3244 sub windows_get_pinned_machine_version
{
3245 my ($machine, $base_version, $kvmversion) = @_;
3247 my $pin_version = $base_version;
3248 if (!defined($base_version) ||
3249 !PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($base_version, $kvmversion)
3251 $pin_version = get_installed_machine_version
($kvmversion);
3253 if (!$machine || $machine eq 'pc') {
3254 $machine = "pc-i440fx-$pin_version";
3255 } elsif ($machine eq 'q35') {
3256 $machine = "pc-q35-$pin_version";
3257 } elsif ($machine eq 'virt') {
3258 $machine = "virt-$pin_version";
3260 warn "unknown machine type '$machine', not touching that!\n";
3266 sub get_vm_machine
{
3267 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
3269 my $machine = $forcemachine || $conf->{machine
};
3271 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
3272 $kvmversion //= kvm_user_version
();
3273 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3274 # layout which confuses windows quite a bit and may result in various regressions..
3275 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3276 if (windows_version
($conf->{ostype
})) {
3277 $machine = windows_get_pinned_machine_version
($machine, '5.1', $kvmversion);
3280 $machine ||= $default_machines->{$arch};
3281 if ($add_pve_version) {
3282 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
3283 $machine .= "+pve$pvever";
3287 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3288 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3289 $machine = $1 if $is_pxe;
3291 # for version-pinned machines that do not include a pve-version (e.g.
3292 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3293 $machine .= '+pve0';
3295 $machine .= '.pxe' if $is_pxe;
3301 sub get_ovmf_files
($$$) {
3302 my ($arch, $efidisk, $smm) = @_;
3304 my $types = $OVMF->{$arch}
3305 or die "no OVMF images known for architecture '$arch'\n";
3307 my $type = 'default';
3308 if (defined($efidisk->{efitype
}) && $efidisk->{efitype
} eq '4m') {
3309 $type = $smm ?
"4m" : "4m-no-smm";
3310 $type .= '-ms' if $efidisk->{'pre-enrolled-keys'};
3313 return $types->{$type}->@*;
3317 aarch64
=> '/usr/bin/qemu-system-aarch64',
3318 x86_64
=> '/usr/bin/qemu-system-x86_64',
3320 sub get_command_for_arch
($) {
3322 return '/usr/bin/kvm' if is_native
($arch);
3324 my $cmd = $Arch2Qemu->{$arch}
3325 or die "don't know how to emulate architecture '$arch'\n";
3329 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3330 # to use in a QEMU command line (-cpu element), first array_intersect the result
3331 # of query_supported_ with query_understood_. This is necessary because:
3333 # a) query_understood_ returns flags the host cannot use and
3334 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
3335 # flags, but CPU settings - with most of them being flags. Those settings
3336 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
3338 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3339 # expensive. If you need the value returned from this, you can get it much
3340 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3341 # $accel being 'kvm' or 'tcg'.
3343 # pvestatd calls this function on startup and whenever the QEMU/KVM version
3344 # changes, automatically populating pmxcfs.
3346 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3347 # since kvm and tcg machines support different flags
3349 sub query_supported_cpu_flags
{
3352 $arch //= get_host_arch
();
3353 my $default_machine = $default_machines->{$arch};
3357 # FIXME: Once this is merged, the code below should work for ARM as well:
3358 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3359 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3362 my $kvm_supported = defined(kvm_version
());
3363 my $qemu_cmd = get_command_for_arch
($arch);
3365 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
3367 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3368 my $query_supported_run_qemu = sub {
3374 '-machine', $default_machine,
3376 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
3377 '-mon', 'chardev=qmp,mode=control',
3378 '-pidfile', $pidfile,
3383 push @$cmd, '-accel', 'tcg';
3386 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
3387 die "QEMU flag querying VM exited with code " . $rc if $rc;
3390 my $cmd_result = mon_cmd
(
3392 'query-cpu-model-expansion',
3394 model
=> { name
=> 'host' }
3397 my $props = $cmd_result->{model
}->{props
};
3398 foreach my $prop (keys %$props) {
3399 next if $props->{$prop} ne '1';
3400 # QEMU returns some flags multiple times, with '_', '.' or '-'
3401 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3402 # We only keep those with underscores, to match /proc/cpuinfo
3403 $prop =~ s/\.|-/_/g;
3404 $flags->{$prop} = 1;
3409 # force stop with 10 sec timeout and 'nocheck', always stop, even if QMP failed
3410 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
3414 return [ sort keys %$flags ];
3417 # We need to query QEMU twice, since KVM and TCG have different supported flags
3418 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
3419 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
3420 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3422 if ($kvm_supported) {
3423 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
3424 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3431 # Understood CPU flags are written to a file at 'pve-qemu' compile time
3432 my $understood_cpu_flag_dir = "/usr/share/kvm";
3433 sub query_understood_cpu_flags
{
3434 my $arch = get_host_arch
();
3435 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3437 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3440 my $raw = file_get_contents
($filepath);
3441 $raw =~ s/^\s+|\s+$//g;
3442 my @flags = split(/\s+/, $raw);
3447 my sub get_cpuunits
{
3449 my $is_cgroupv2 = PVE
::CGroup
::cgroup_mode
() == 2;
3451 my $cpuunits = $conf->{cpuunits
};
3452 return $is_cgroupv2 ?
100 : 1024 if !defined($cpuunits);
3455 $cpuunits = 10000 if $cpuunits >= 10000; # v1 can be higher, so clamp v2 there
3457 $cpuunits = 2 if $cpuunits < 2; # v2 can be lower, so clamp v1 there
3462 # Since commit 277d33454f77ec1d1e0bc04e37621e4dd2424b67 in pve-qemu, smm is not off by default
3463 # anymore. But smm=off seems to be required when using SeaBIOS and serial display.
3464 my sub should_disable_smm
{
3465 my ($conf, $vga) = @_;
3467 return (!defined($conf->{bios
}) || $conf->{bios
} eq 'seabios') &&
3468 $vga->{type
} && $vga->{type
} =~ m/^(serial\d+|none)$/;
3471 sub config_to_command
{
3472 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3476 my ($globalFlags, $machineFlags, $rtcFlags) = ([], [], []);
3479 my $ostype = $conf->{ostype
};
3480 my $winversion = windows_version
($ostype);
3481 my $kvm = $conf->{kvm
};
3482 my $nodename = nodename
();
3484 my $arch = get_vm_arch
($conf);
3485 my $kvm_binary = get_command_for_arch
($arch);
3486 my $kvmver = kvm_user_version
($kvm_binary);
3488 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3489 $kvmver //= "undefined";
3490 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3493 my $add_pve_version = min_version
($kvmver, 4, 1);
3495 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
3496 my $machine_version = extract_version
($machine_type, $kvmver);
3497 $kvm //= 1 if is_native
($arch);
3499 $machine_version =~ m/(\d+)\.(\d+)/;
3500 my ($machine_major, $machine_minor) = ($1, $2);
3502 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3503 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3504 } elsif (!min_version
($kvmver, $machine_major, $machine_minor)) {
3505 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3506 ." please upgrade node '$nodename'\n"
3507 } elsif (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
3508 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
3509 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3510 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3511 ." node '$nodename'\n";
3514 # if a specific +pve version is required for a feature, use $version_guard
3515 # instead of min_version to allow machines to be run with the minimum
3517 my $required_pve_version = 0;
3518 my $version_guard = sub {
3519 my ($major, $minor, $pve) = @_;
3520 return 0 if !min_version
($machine_version, $major, $minor, $pve);
3521 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
3522 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
3523 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3527 if ($kvm && !defined kvm_version
()) {
3528 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3529 ." or enable in BIOS.\n";
3532 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3533 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3534 my $use_old_bios_files = undef;
3535 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3537 push @$cmd, $kvm_binary;
3539 push @$cmd, '-id', $vmid;
3541 my $vmname = $conf->{name
} || "vm$vmid";
3543 push @$cmd, '-name', $vmname;
3545 push @$cmd, '-no-shutdown';
3549 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3550 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
3551 push @$cmd, '-mon', "chardev=qmp,mode=control";
3553 if (min_version
($machine_version, 2, 12)) {
3554 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3555 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3558 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3560 push @$cmd, '-daemonize';
3562 if ($conf->{smbios1
}) {
3563 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3564 if ($smbios_conf->{base64
}) {
3565 # Do not pass base64 flag to qemu
3566 delete $smbios_conf->{base64
};
3567 my $smbios_string = "";
3568 foreach my $key (keys %$smbios_conf) {
3570 if ($key eq "uuid") {
3571 $value = $smbios_conf->{uuid
}
3573 $value = decode_base64
($smbios_conf->{$key});
3575 # qemu accepts any binary data, only commas need escaping by double comma
3577 $smbios_string .= "," . $key . "=" . $value if $value;
3579 push @$cmd, '-smbios', "type=1" . $smbios_string;
3581 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3585 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3587 if (my $efidisk = $conf->{efidisk0
}) {
3588 $d = parse_drive
('efidisk0', $efidisk);
3591 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch, $d, $q35);
3592 die "uefi base image '$ovmf_code' not found\n" if ! -f
$ovmf_code;
3594 my ($path, $format);
3595 my $read_only_str = '';
3597 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3598 $format = $d->{format
};
3600 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3601 if (!defined($format)) {
3602 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3603 $format = qemu_img_format
($scfg, $volname);
3607 die "efidisk format must be specified\n"
3608 if !defined($format);
3611 $read_only_str = ',readonly=on' if drive_is_read_only
($conf, $d);
3613 warn "no efidisk configured! Using temporary efivars disk.\n";
3614 $path = "/tmp/$vmid-ovmf.fd";
3615 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3621 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3622 $size_str = ",size=" . (-s
$ovmf_vars);
3625 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3627 if ($path =~ m/^rbd:/) {
3628 $cache = ',cache=writeback';
3629 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3632 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
3633 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
3636 if ($q35) { # tell QEMU to load q35 config early
3637 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3638 if (min_version
($machine_version, 4, 0)) {
3639 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3641 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3645 if (defined(my $fixups = qemu_created_version_fixups
($conf, $forcemachine, $kvmver))) {
3646 push @$cmd, $fixups->@*;
3649 if ($conf->{vmgenid
}) {
3650 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3653 # add usb controllers
3654 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
(
3655 $conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3656 push @$devices, @usbcontrollers if @usbcontrollers;
3657 my $vga = parse_vga
($conf->{vga
});
3659 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3660 $vga->{type
} = 'qxl' if $qxlnum;
3662 if (!$vga->{type
}) {
3663 if ($arch eq 'aarch64') {
3664 $vga->{type
} = 'virtio';
3665 } elsif (min_version
($machine_version, 2, 9)) {
3666 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3668 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3672 # enable absolute mouse coordinates (needed by vnc)
3673 my $tablet = $conf->{tablet
};
3674 if (!defined($tablet)) {
3675 $tablet = $defaults->{tablet
};
3676 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3677 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3681 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3682 my $kbd = print_keyboarddevice_full
($conf, $arch);
3683 push @$devices, '-device', $kbd if defined($kbd);
3686 my $bootorder = device_bootorder
($conf);
3688 # host pci device passthrough
3689 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE
::QemuServer
::PCI
::print_hostpci_devices
(
3690 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
3693 my $usb_dev_features = {};
3694 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3696 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
(
3697 $conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
3698 push @$devices, @usbdevices if @usbdevices;
3701 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3702 my $path = $conf->{"serial$i"} or next;
3703 if ($path eq 'socket') {
3704 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3705 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3706 # On aarch64, serial0 is the UART device. Qemu only allows
3707 # connecting UART devices via the '-serial' command line, as
3708 # the device has a fixed slot on the hardware...
3709 if ($arch eq 'aarch64' && $i == 0) {
3710 push @$devices, '-serial', "chardev:serial$i";
3712 push @$devices, '-device', "isa-serial,chardev=serial$i";
3715 die "no such serial device\n" if ! -c
$path;
3716 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3717 push @$devices, '-device', "isa-serial,chardev=serial$i";
3722 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3723 if (my $path = $conf->{"parallel$i"}) {
3724 die "no such parallel device\n" if ! -c
$path;
3725 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3726 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3727 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3731 if (min_version
($machine_version, 4, 0) && (my $audio = conf_has_audio
($conf))) {
3732 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3733 my $audio_devs = audio_devs
($audio, $audiopciaddr, $machine_version);
3734 push @$devices, @$audio_devs;
3737 add_tpm_device
($vmid, $devices, $conf);
3740 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3741 $sockets = $conf->{sockets
} if $conf->{sockets
};
3743 my $cores = $conf->{cores
} || 1;
3745 my $maxcpus = $sockets * $cores;
3747 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3749 my $allowed_vcpus = $cpuinfo->{cpus
};
3751 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n" if ($allowed_vcpus < $maxcpus);
3753 if ($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3754 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3755 for (my $i = 2; $i <= $vcpus; $i++) {
3756 my $cpustr = print_cpu_device
($conf,$i);
3757 push @$cmd, '-device', $cpustr;
3762 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3764 push @$cmd, '-nodefaults';
3766 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3768 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3770 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3772 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3773 push @$devices, '-device', print_vga_device
(
3774 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3776 push @$cmd, '-display', 'egl-headless,gl=core' if $vga->{type
} eq 'virtio-gl'; # VIRGL
3778 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3779 push @$cmd, '-vnc', "unix:$socket,password=on";
3781 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3782 push @$cmd, '-nographic';
3786 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3787 my $useLocaltime = $conf->{localtime};
3789 if ($winversion >= 5) { # windows
3790 $useLocaltime = 1 if !defined($conf->{localtime});
3792 # use time drift fix when acpi is enabled
3793 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3794 $tdf = 1 if !defined($conf->{tdf
});
3798 if ($winversion >= 6) {
3799 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3800 push @$cmd, '-no-hpet';
3803 push @$rtcFlags, 'driftfix=slew' if $tdf;
3805 if ($conf->{startdate
} && $conf->{startdate
} ne 'now') {
3806 push @$rtcFlags, "base=$conf->{startdate}";
3807 } elsif ($useLocaltime) {
3808 push @$rtcFlags, 'base=localtime';
3812 push @$cmd, '-cpu', $forcecpu;
3814 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3817 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3819 push @$cmd, '-S' if $conf->{freeze
};
3821 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3823 my $guest_agent = parse_guest_agent
($conf);
3825 if ($guest_agent->{enabled
}) {
3826 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3827 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
3829 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3830 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3831 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3832 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3833 } elsif ($guest_agent->{type
} eq 'isa') {
3834 push @$devices, '-device', "isa-serial,chardev=qga0";
3838 my $rng = $conf->{rng0
} ? parse_rng
($conf->{rng0
}) : undef;
3839 if ($rng && $version_guard->(4, 1, 2)) {
3840 check_rng_source
($rng->{source
});
3842 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3843 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3844 my $limiter_str = "";
3846 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3849 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3850 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3851 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3856 if ($qxlnum || $vga->{type
} =~ /^virtio/) {
3859 for (my $i = 1; $i < $qxlnum; $i++){
3860 push @$devices, '-device', print_vga_device
(
3861 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3864 # assume other OS works like Linux
3865 my ($ram, $vram) = ("134217728", "67108864");
3866 if ($vga->{memory
}) {
3867 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3868 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3870 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3871 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3875 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3877 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3878 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3879 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3881 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3882 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3883 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3885 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3886 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3888 my $spice_enhancement_str = $conf->{spice_enhancements
} // '';
3889 my $spice_enhancement = parse_property_string
($spice_enhancements_fmt, $spice_enhancement_str);
3890 if ($spice_enhancement->{foldersharing
}) {
3891 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3892 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3895 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3896 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3897 if $spice_enhancement->{videostreaming
};
3899 push @$devices, '-spice', "$spice_opts";
3902 # enable balloon by default, unless explicitly disabled
3903 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3904 my $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3905 my $ballooncmd = "virtio-balloon-pci,id=balloon0$pciaddr";
3906 $ballooncmd .= ",free-page-reporting=on" if min_version
($machine_version, 6, 2);
3907 push @$devices, '-device', $ballooncmd;
3910 if ($conf->{watchdog
}) {
3911 my $wdopts = parse_watchdog
($conf->{watchdog
});
3912 my $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3913 my $watchdog = $wdopts->{model
} || 'i6300esb';
3914 push @$devices, '-device', "$watchdog$pciaddr";
3915 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3919 my $scsicontroller = {};
3920 my $ahcicontroller = {};
3921 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3923 # Add iscsi initiator name if available
3924 if (my $initiator = get_initiator_name
()) {
3925 push @$devices, '-iscsi', "initiator-name=$initiator";
3928 PVE
::QemuConfig-
>foreach_volume($conf, sub {
3929 my ($ds, $drive) = @_;
3931 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3932 check_volume_storage_type
($storecfg, $drive->{file
});
3933 push @$vollist, $drive->{file
};
3936 # ignore efidisk here, already added in bios/fw handling code above
3937 return if $drive->{interface
} eq 'efidisk';
3939 return if $drive->{interface
} eq 'tpmstate';
3941 $use_virtio = 1 if $ds =~ m/^virtio/;
3943 $drive->{bootindex
} = $bootorder->{$ds} if $bootorder->{$ds};
3945 if ($drive->{interface
} eq 'virtio'){
3946 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3949 if ($drive->{interface
} eq 'scsi') {
3951 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3953 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3954 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3956 my $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3957 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3960 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3961 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3962 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3963 } elsif ($drive->{iothread
}) {
3964 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3968 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3969 $queues = ",num_queues=$drive->{queues}";
3972 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
3973 if !$scsicontroller->{$controller};
3974 $scsicontroller->{$controller}=1;
3977 if ($drive->{interface
} eq 'sata') {
3978 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3979 my $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3980 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
3981 if !$ahcicontroller->{$controller};
3982 $ahcicontroller->{$controller}=1;
3985 my $pbs_conf = $pbs_backing->{$ds};
3986 my $pbs_name = undef;
3988 $pbs_name = "drive-$ds-pbs";
3989 push @$devices, '-blockdev', print_pbs_blockdev
($pbs_conf, $pbs_name);
3992 my $drive_cmd = print_drive_commandline_full
(
3993 $storecfg, $vmid, $drive, $pbs_name, min_version
($kvmver, 6, 0));
3995 # extra protection for templates, but SATA and IDE don't support it..
3996 $drive_cmd .= ',readonly=on' if drive_is_read_only
($conf, $drive);
3998 push @$devices, '-drive',$drive_cmd;
3999 push @$devices, '-device', print_drivedevice_full
(
4000 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
4003 for (my $i = 0; $i < $MAX_NETS; $i++) {
4004 my $netname = "net$i";
4006 next if !$conf->{$netname};
4007 my $d = parse_net
($conf->{$netname});
4010 $use_virtio = 1 if $d->{model
} eq 'virtio';
4012 $d->{bootindex
} = $bootorder->{$netname} if $bootorder->{$netname};
4014 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, $netname);
4015 push @$devices, '-netdev', $netdevfull;
4017 my $netdevicefull = print_netdevice_full
(
4018 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
4020 push @$devices, '-device', $netdevicefull;
4023 if ($conf->{ivshmem
}) {
4024 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
4028 $bus = print_pcie_addr
("ivshmem");
4030 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
4033 my $ivshmem_name = $ivshmem->{name
} // $vmid;
4034 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4036 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4037 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
4038 .",size=$ivshmem->{size}M";
4041 # pci.4 is nested in pci.1
4042 $bridges->{1} = 1 if $bridges->{4};
4044 if (!$q35) { # add pci bridges
4045 if (min_version
($machine_version, 2, 3)) {
4049 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
4052 for my $k (sort {$b cmp $a} keys %$bridges) {
4053 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
4056 if ($k == 2 && $legacy_igd) {
4059 my $pciaddr = print_pci_addr
("pci.$k_name", undef, $arch, $machine_type);
4060 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
4062 if ($q35) { # add after -readconfig pve-q35.cfg
4063 splice @$devices, 2, 0, '-device', $devstr;
4065 unshift @$devices, '-device', $devstr if $k > 0;
4070 push @$machineFlags, 'accel=tcg';
4073 push @$machineFlags, 'smm=off' if should_disable_smm
($conf, $vga);
4075 my $machine_type_min = $machine_type;
4076 if ($add_pve_version) {
4077 $machine_type_min =~ s/\+pve\d+$//;
4078 $machine_type_min .= "+pve$required_pve_version";
4080 push @$machineFlags, "type=${machine_type_min}";
4082 push @$cmd, @$devices;
4083 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
4084 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
4085 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
4087 if (my $vmstate = $conf->{vmstate
}) {
4088 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
4089 push @$vollist, $vmstate;
4090 push @$cmd, '-loadstate', $statepath;
4091 print "activating and using '$vmstate' as vmstate\n";
4094 if (PVE
::QemuConfig-
>is_template($conf)) {
4095 # needed to workaround base volumes being read-only
4096 push @$cmd, '-snapshot';
4100 if ($conf->{args
}) {
4101 my $aa = PVE
::Tools
::split_args
($conf->{args
});
4105 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
4108 sub check_rng_source
{
4111 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
4112 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
4115 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
4116 if ($source eq '/dev/hwrng' && file_read_firstline
($rng_current) eq 'none') {
4117 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
4118 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
4119 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
4120 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
4128 my $res = mon_cmd
($vmid, 'query-spice');
4130 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
4133 sub vm_devices_list
{
4136 my $res = mon_cmd
($vmid, 'query-pci');
4137 my $devices_to_check = [];
4139 foreach my $pcibus (@$res) {
4140 push @$devices_to_check, @{$pcibus->{devices
}},
4143 while (@$devices_to_check) {
4145 for my $d (@$devices_to_check) {
4146 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4147 next if !$d->{'pci_bridge'};
4149 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
4150 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
4152 $devices_to_check = $to_check;
4155 my $resblock = mon_cmd
($vmid, 'query-block');
4156 foreach my $block (@$resblock) {
4157 if($block->{device
} =~ m/^drive-(\S+)/){
4162 my $resmice = mon_cmd
($vmid, 'query-mice');
4163 foreach my $mice (@$resmice) {
4164 if ($mice->{name
} eq 'QEMU HID Tablet') {
4165 $devices->{tablet
} = 1;
4170 # for usb devices there is no query-usb
4171 # but we can iterate over the entries in
4172 # qom-list path=/machine/peripheral
4173 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4174 foreach my $per (@$resperipheral) {
4175 if ($per->{name
} =~ m/^usb\d+$/) {
4176 $devices->{$per->{name
}} = 1;
4184 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4186 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
4188 my $devices_list = vm_devices_list
($vmid);
4189 return 1 if defined($devices_list->{$deviceid});
4191 # add PCI bridge if we need it for the device
4192 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
4194 if ($deviceid eq 'tablet') {
4195 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4196 } elsif ($deviceid eq 'keyboard') {
4197 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4198 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4199 die "usb hotplug currently not reliable\n";
4200 # since we can't reliably hot unplug all added usb devices and usb
4201 # passthrough breaks live migration we disable usb hotplugging for now
4202 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
4203 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4204 qemu_iothread_add
($vmid, $deviceid, $device);
4206 qemu_driveadd
($storecfg, $vmid, $device);
4207 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4209 qemu_deviceadd
($vmid, $devicefull);
4210 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4212 eval { qemu_drivedel
($vmid, $deviceid); };
4216 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4217 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4218 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4219 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4221 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4223 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4224 qemu_iothread_add
($vmid, $deviceid, $device);
4225 $devicefull .= ",iothread=iothread-$deviceid";
4228 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4229 $devicefull .= ",num_queues=$device->{queues}";
4232 qemu_deviceadd
($vmid, $devicefull);
4233 qemu_deviceaddverify
($vmid, $deviceid);
4234 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4235 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4236 qemu_driveadd
($storecfg, $vmid, $device);
4238 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4239 eval { qemu_deviceadd
($vmid, $devicefull); };
4241 eval { qemu_drivedel
($vmid, $deviceid); };
4245 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4246 return if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4248 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
4249 my $use_old_bios_files = undef;
4250 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4252 my $netdevicefull = print_netdevice_full
(
4253 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4254 qemu_deviceadd
($vmid, $netdevicefull);
4256 qemu_deviceaddverify
($vmid, $deviceid);
4257 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4260 eval { qemu_netdevdel
($vmid, $deviceid); };
4264 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4266 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4267 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4269 qemu_deviceadd
($vmid, $devicefull);
4270 qemu_deviceaddverify
($vmid, $deviceid);
4272 die "can't hotplug device '$deviceid'\n";
4278 # fixme: this should raise exceptions on error!
4279 sub vm_deviceunplug
{
4280 my ($vmid, $conf, $deviceid) = @_;
4282 my $devices_list = vm_devices_list
($vmid);
4283 return 1 if !defined($devices_list->{$deviceid});
4285 my $bootdisks = PVE
::QemuServer
::Drive
::get_bootdisks
($conf);
4286 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
4288 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4289 qemu_devicedel
($vmid, $deviceid);
4290 } elsif ($deviceid =~ m/^usb\d+$/) {
4291 die "usb hotplug currently not reliable\n";
4292 # when unplugging usb devices this way, there may be remaining usb
4293 # controllers/hubs so we disable it for now
4294 #qemu_devicedel($vmid, $deviceid);
4295 #qemu_devicedelverify($vmid, $deviceid);
4296 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4297 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4299 qemu_devicedel
($vmid, $deviceid);
4300 qemu_devicedelverify
($vmid, $deviceid);
4301 qemu_drivedel
($vmid, $deviceid);
4302 qemu_iothread_del
($vmid, $deviceid, $device);
4303 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4304 qemu_devicedel
($vmid, $deviceid);
4305 qemu_devicedelverify
($vmid, $deviceid);
4306 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4307 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4309 qemu_devicedel
($vmid, $deviceid);
4310 qemu_devicedelverify
($vmid, $deviceid);
4311 qemu_drivedel
($vmid, $deviceid);
4312 qemu_deletescsihw
($conf, $vmid, $deviceid);
4314 qemu_iothread_del
($vmid, "virtioscsi$device->{index}", $device)
4315 if $conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single');
4316 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4317 qemu_devicedel
($vmid, $deviceid);
4318 qemu_devicedelverify
($vmid, $deviceid);
4319 qemu_netdevdel
($vmid, $deviceid);
4321 die "can't unplug device '$deviceid'\n";
4327 sub qemu_deviceadd
{
4328 my ($vmid, $devicefull) = @_;
4330 $devicefull = "driver=".$devicefull;
4331 my %options = split(/[=,]/, $devicefull);
4333 mon_cmd
($vmid, "device_add" , %options);
4336 sub qemu_devicedel
{
4337 my ($vmid, $deviceid) = @_;
4339 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
4342 sub qemu_iothread_add
{
4343 my ($vmid, $deviceid, $device) = @_;
4345 if ($device->{iothread
}) {
4346 my $iothreads = vm_iothreads_list
($vmid);
4347 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4351 sub qemu_iothread_del
{
4352 my ($vmid, $deviceid, $device) = @_;
4354 if ($device->{iothread
}) {
4355 my $iothreads = vm_iothreads_list
($vmid);
4356 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4360 sub qemu_objectadd
{
4361 my ($vmid, $objectid, $qomtype) = @_;
4363 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4368 sub qemu_objectdel
{
4369 my ($vmid, $objectid) = @_;
4371 mon_cmd
($vmid, "object-del", id
=> $objectid);
4377 my ($storecfg, $vmid, $device) = @_;
4379 my $kvmver = get_running_qemu_version
($vmid);
4380 my $io_uring = min_version
($kvmver, 6, 0);
4381 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device, undef, $io_uring);
4382 $drive =~ s/\\/\\\\/g;
4383 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
4385 # If the command succeeds qemu prints: "OK
"
4386 return 1 if $ret =~ m/OK/s;
4388 die "adding drive failed
: $ret\n";
4392 my ($vmid, $deviceid) = @_;
4394 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
4397 return 1 if $ret eq "";
4399 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4400 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4402 die "deleting drive
$deviceid failed
: $ret\n";
4405 sub qemu_deviceaddverify {
4406 my ($vmid, $deviceid) = @_;
4408 for (my $i = 0; $i <= 5; $i++) {
4409 my $devices_list = vm_devices_list($vmid);
4410 return 1 if defined($devices_list->{$deviceid});
4414 die "error on hotplug device
'$deviceid'\n";
4418 sub qemu_devicedelverify {
4419 my ($vmid, $deviceid) = @_;
4421 # need to verify that the device is correctly removed as device_del
4422 # is async and empty return is not reliable
4424 for (my $i = 0; $i <= 5; $i++) {
4425 my $devices_list = vm_devices_list($vmid);
4426 return 1 if !defined($devices_list->{$deviceid});
4430 die "error on hot-unplugging device
'$deviceid'\n";
4433 sub qemu_findorcreatescsihw {
4434 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4436 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4438 my $scsihwid="$controller_prefix$controller";
4439 my $devices_list = vm_devices_list($vmid);
4441 if (!defined($devices_list->{$scsihwid})) {
4442 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4448 sub qemu_deletescsihw {
4449 my ($conf, $vmid, $opt) = @_;
4451 my $device = parse_drive($opt, $conf->{$opt});
4453 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4454 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4458 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4460 my $devices_list = vm_devices_list($vmid);
4461 foreach my $opt (keys %{$devices_list}) {
4462 if (is_valid_drivename($opt)) {
4463 my $drive = parse_drive($opt, $conf->{$opt});
4464 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4470 my $scsihwid="scsihw
$controller";
4472 vm_deviceunplug($vmid, $conf, $scsihwid);
4477 sub qemu_add_pci_bridge {
4478 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4484 print_pci_addr($device, $bridges, $arch, $machine_type);
4486 while (my ($k, $v) = each %$bridges) {
4489 return 1 if !defined($bridgeid) || $bridgeid < 1;
4491 my $bridge = "pci
.$bridgeid";
4492 my $devices_list = vm_devices_list($vmid);
4494 if (!defined($devices_list->{$bridge})) {
4495 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4501 sub qemu_set_link_status {
4502 my ($vmid, $device, $up) = @_;
4504 mon_cmd($vmid, "set_link
", name => $device,
4505 up => $up ? JSON::true : JSON::false);
4508 sub qemu_netdevadd {
4509 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4511 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4512 my %options = split(/[=,]/, $netdev);
4514 if (defined(my $vhost = $options{vhost})) {
4515 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4518 if (defined(my $queues = $options{queues})) {
4519 $options{queues} = $queues + 0;
4522 mon_cmd($vmid, "netdev_add
", %options);
4526 sub qemu_netdevdel {
4527 my ($vmid, $deviceid) = @_;
4529 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4532 sub qemu_usb_hotplug {
4533 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4537 # remove the old one first
4538 vm_deviceunplug($vmid, $conf, $deviceid);
4540 # check if xhci controller is necessary and available
4541 if ($device->{usb3}) {
4543 my $devicelist = vm_devices_list($vmid);
4545 if (!$devicelist->{xhci}) {
4546 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4547 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4550 my $d = parse_usb_device($device->{host});
4551 $d->{usb3} = $device->{usb3};
4554 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4557 sub qemu_cpu_hotplug {
4558 my ($vmid, $conf, $vcpus) = @_;
4560 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4563 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4564 $sockets = $conf->{sockets} if $conf->{sockets};
4565 my $cores = $conf->{cores} || 1;
4566 my $maxcpus = $sockets * $cores;
4568 $vcpus = $maxcpus if !$vcpus;
4570 die "you can
't add more vcpus than maxcpus\n"
4571 if $vcpus > $maxcpus;
4573 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4575 if ($vcpus < $currentvcpus) {
4577 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4579 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4580 qemu_devicedel($vmid, "cpu$i");
4582 my $currentrunningvcpus = undef;
4584 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4585 last if scalar(@{$currentrunningvcpus}) == $i-1;
4586 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4590 #update conf after each succesfull cpu unplug
4591 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4592 PVE::QemuConfig->write_config($vmid, $conf);
4595 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4601 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4602 die "vcpus in running vm does not match its configuration\n"
4603 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4605 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4607 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4608 my $cpustr = print_cpu_device($conf, $i);
4609 qemu_deviceadd($vmid, $cpustr);
4612 my $currentrunningvcpus = undef;
4614 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4615 last if scalar(@{$currentrunningvcpus}) == $i;
4616 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4620 #update conf after each succesfull cpu hotplug
4621 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4622 PVE::QemuConfig->write_config($vmid, $conf);
4626 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4627 mon_cmd($vmid, "cpu-add", id => int($i));
4632 sub qemu_block_set_io_throttle {
4633 my ($vmid, $deviceid,
4634 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4635 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4636 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4637 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4639 return if !check_running($vmid) ;
4641 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4643 bps_rd => int($bps_rd),
4644 bps_wr => int($bps_wr),
4646 iops_rd => int($iops_rd),
4647 iops_wr => int($iops_wr),
4648 bps_max => int($bps_max),
4649 bps_rd_max => int($bps_rd_max),
4650 bps_wr_max => int($bps_wr_max),
4651 iops_max => int($iops_max),
4652 iops_rd_max => int($iops_rd_max),
4653 iops_wr_max => int($iops_wr_max),
4654 bps_max_length => int($bps_max_length),
4655 bps_rd_max_length => int($bps_rd_max_length),
4656 bps_wr_max_length => int($bps_wr_max_length),
4657 iops_max_length => int($iops_max_length),
4658 iops_rd_max_length => int($iops_rd_max_length),
4659 iops_wr_max_length => int($iops_wr_max_length),
4664 sub qemu_block_resize {
4665 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4667 my $running = check_running($vmid);
4669 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4671 return if !$running;
4673 my $padding = (1024 - $size % 1024) % 1024;
4674 $size = $size + $padding;
4679 device => $deviceid,
4685 sub qemu_volume_snapshot {
4686 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4688 my $running = check_running($vmid);
4690 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4691 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4693 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4697 sub qemu_volume_snapshot_delete {
4698 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4700 my $running = check_running($vmid);
4705 my $conf = PVE::QemuConfig->load_config($vmid);
4706 PVE::QemuConfig->foreach_volume($conf, sub {
4707 my ($ds, $drive) = @_;
4708 $running = 1 if $drive->{file} eq $volid;
4712 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4713 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4715 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4719 sub set_migration_caps {
4720 my ($vmid, $savevm) = @_;
4722 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4724 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm
' : 'pbs-dirty-bitmap-migration
';
4725 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4730 "auto-converge" => 1,
4732 "x-rdma-pin-all" => 0,
4735 "dirty-bitmaps" => $dirty_bitmaps,
4738 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4740 for my $supported_capability (@$supported_capabilities) {
4742 capability => $supported_capability->{capability},
4743 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4747 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4751 my ($conf, $func, @param) = @_;
4755 my $test_volid = sub {
4756 my ($key, $drive, $snapname) = @_;
4758 my $volid = $drive->{file};
4761 $volhash->{$volid}->{cdrom} //= 1;
4762 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
4764 my $replicate = $drive->{replicate} // 1;
4765 $volhash->{$volid}->{replicate} //= 0;
4766 $volhash->{$volid}->{replicate} = 1 if $replicate;
4768 $volhash->{$volid}->{shared} //= 0;
4769 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
4771 $volhash->{$volid}->{referenced_in_config} //= 0;
4772 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4774 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4775 if defined($snapname);
4777 my $size = $drive->{size};
4778 $volhash->{$volid}->{size} //= $size if $size;
4780 $volhash->{$volid}->{is_vmstate} //= 0;
4781 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate
';
4783 $volhash->{$volid}->{is_tpmstate} //= 0;
4784 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0
';
4786 $volhash->{$volid}->{is_unused} //= 0;
4787 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
4789 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
4792 my $include_opts = {
4793 extra_keys => ['vmstate
'],
4794 include_unused => 1,
4797 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
4798 foreach my $snapname (keys %{$conf->{snapshots}}) {
4799 my $snap = $conf->{snapshots}->{$snapname};
4800 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
4803 foreach my $volid (keys %$volhash) {
4804 &$func($volid, $volhash->{$volid}, @param);
4808 my $fast_plug_option = {
4816 'vmstatestorage
' => 1,
4821 # hotplug changes in [PENDING]
4822 # $selection hash can be used to only apply specified options, for
4823 # example: { cores => 1 } (only apply changed 'cores
')
4824 # $errors ref is used to return error messages
4825 sub vmconfig_hotplug_pending {
4826 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4828 my $defaults = load_defaults();
4829 my $arch = get_vm_arch($conf);
4830 my $machine_type = get_vm_machine($conf, undef, $arch);
4832 # commit values which do not have any impact on running VM first
4833 # Note: those option cannot raise errors, we we do not care about
4834 # $selection and always apply them.
4836 my $add_error = sub {
4837 my ($opt, $msg) = @_;
4838 $errors->{$opt} = "hotplug problem - $msg";
4842 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4843 if ($fast_plug_option->{$opt}) {
4844 $conf->{$opt} = $conf->{pending}->{$opt};
4845 delete $conf->{pending}->{$opt};
4851 PVE::QemuConfig->write_config($vmid, $conf);
4854 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4856 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
4857 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4858 foreach my $opt (sort keys %$pending_delete_hash) {
4859 next if $selection && !$selection->{$opt};
4860 my $force = $pending_delete_hash->{$opt}->{force};
4862 if ($opt eq 'hotplug
') {
4863 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4864 } elsif ($opt eq 'tablet
') {
4865 die "skip\n" if !$hotplug_features->{usb};
4866 if ($defaults->{tablet}) {
4867 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4868 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4869 if $arch eq 'aarch64
';
4871 vm_deviceunplug($vmid, $conf, 'tablet
');
4872 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4874 } elsif ($opt =~ m/^usb\d+/) {
4876 # since we cannot reliably hot unplug usb devices we are disabling it
4877 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4878 #vm_deviceunplug($vmid, $conf, $opt);
4879 } elsif ($opt eq 'vcpus
') {
4880 die "skip\n" if !$hotplug_features->{cpu};
4881 qemu_cpu_hotplug($vmid, $conf, undef);
4882 } elsif ($opt eq 'balloon
') {
4883 # enable balloon device is not hotpluggable
4884 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4885 # here we reset the ballooning value to memory
4886 my $balloon = $conf->{memory} || $defaults->{memory};
4887 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4888 } elsif ($fast_plug_option->{$opt}) {
4890 } elsif ($opt =~ m/^net(\d+)$/) {
4891 die "skip\n" if !$hotplug_features->{network};
4892 vm_deviceunplug($vmid, $conf, $opt);
4893 } elsif (is_valid_drivename($opt)) {
4894 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4895 vm_deviceunplug($vmid, $conf, $opt);
4896 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4897 } elsif ($opt =~ m/^memory$/) {
4898 die "skip\n" if !$hotplug_features->{memory};
4899 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4900 } elsif ($opt eq 'cpuunits
') {
4901 $cgroup->change_cpu_shares(undef, 1024);
4902 } elsif ($opt eq 'cpulimit
') {
4903 $cgroup->change_cpu_quota(undef, undef); # reset, cgroup module can better decide values
4909 &$add_error($opt, $err) if $err ne "skip\n";
4911 delete $conf->{$opt};
4912 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4916 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4917 $apply_pending_cloudinit = sub {
4918 return if $apply_pending_cloudinit_done; # once is enough
4919 $apply_pending_cloudinit_done = 1; # once is enough
4921 my ($key, $value) = @_;
4923 my @cloudinit_opts = keys %$confdesc_cloudinit;
4924 foreach my $opt (keys %{$conf->{pending}}) {
4925 next if !grep { $_ eq $opt } @cloudinit_opts;
4926 $conf->{$opt} = delete $conf->{pending}->{$opt};
4929 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4930 foreach my $opt (sort keys %$pending_delete_hash) {
4931 next if !grep { $_ eq $opt } @cloudinit_opts;
4932 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4933 delete $conf->{$opt};
4936 my $new_conf = { %$conf };
4937 $new_conf->{$key} = $value;
4938 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4941 foreach my $opt (keys %{$conf->{pending}}) {
4942 next if $selection && !$selection->{$opt};
4943 my $value = $conf->{pending}->{$opt};
4945 if ($opt eq 'hotplug
') {
4946 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4947 } elsif ($opt eq 'tablet
') {
4948 die "skip\n" if !$hotplug_features->{usb};
4950 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4951 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4952 if $arch eq 'aarch64
';
4953 } elsif ($value == 0) {
4954 vm_deviceunplug($vmid, $conf, 'tablet
');
4955 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4957 } elsif ($opt =~ m/^usb\d+$/) {
4959 # since we cannot reliably hot unplug usb devices we disable it for now
4960 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4961 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4962 #die "skip\n" if !$d;
4963 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4964 } elsif ($opt eq 'vcpus
') {
4965 die "skip\n" if !$hotplug_features->{cpu};
4966 qemu_cpu_hotplug($vmid, $conf, $value);
4967 } elsif ($opt eq 'balloon
') {
4968 # enable/disable balloning device is not hotpluggable
4969 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4970 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4971 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4973 # allow manual ballooning if shares is set to zero
4974 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4975 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4976 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4978 } elsif ($opt =~ m/^net(\d+)$/) {
4979 # some changes can be done without hotplug
4980 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4981 $vmid, $opt, $value, $arch, $machine_type);
4982 } elsif (is_valid_drivename($opt)) {
4983 die "skip\n" if $opt eq 'efidisk0
' || $opt eq 'tpmstate0
';
4984 # some changes can be done without hotplug
4985 my $drive = parse_drive($opt, $value);
4986 if (drive_is_cloudinit($drive)) {
4987 &$apply_pending_cloudinit($opt, $value);
4989 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4990 $vmid, $opt, $value, $arch, $machine_type);
4991 } elsif ($opt =~ m/^memory$/) { #dimms
4992 die "skip\n" if !$hotplug_features->{memory};
4993 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4994 } elsif ($opt eq 'cpuunits
') {
4995 my $new_cpuunits = get_cpuunits({ $opt => $conf->{pending}->{$opt} }); # to clamp
4996 $cgroup->change_cpu_shares($new_cpuunits, 1024);
4997 } elsif ($opt eq 'cpulimit
') {
4998 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4999 $cgroup->change_cpu_quota($cpulimit, 100000);
5000 } elsif ($opt eq 'agent
') {
5001 vmconfig_update_agent($conf, $opt, $value);
5003 die "skip\n"; # skip non-hot-pluggable options
5007 &$add_error($opt, $err) if $err ne "skip\n";
5009 $conf->{$opt} = $value;
5010 delete $conf->{pending}->{$opt};
5014 PVE::QemuConfig->write_config($vmid, $conf);
5017 sub try_deallocate_drive {
5018 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
5020 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
5021 my $volid = $drive->{file};
5022 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
5023 my $sid = PVE::Storage::parse_volume_id($volid);
5024 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
5026 # check if the disk is really unused
5027 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
5028 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
5029 PVE::Storage::vdisk_free($storecfg, $volid);
5032 # If vm is not owner of this disk remove from config
5040 sub vmconfig_delete_or_detach_drive {
5041 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
5043 my $drive = parse_drive($opt, $conf->{$opt});
5045 my $rpcenv = PVE::RPCEnvironment::get();
5046 my $authuser = $rpcenv->get_user();
5049 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
5050 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
5052 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
5058 sub vmconfig_apply_pending {
5059 my ($vmid, $conf, $storecfg, $errors) = @_;
5061 return if !scalar(keys %{$conf->{pending}});
5063 my $add_apply_error = sub {
5064 my ($opt, $msg) = @_;
5065 my $err_msg = "unable to apply pending change $opt : $msg";
5066 $errors->{$opt} = $err_msg;
5072 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
5073 foreach my $opt (sort keys %$pending_delete_hash) {
5074 my $force = $pending_delete_hash->{$opt}->{force};
5076 if ($opt =~ m/^unused/) {
5077 die "internal error";
5078 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
5079 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
5083 $add_apply_error->($opt, $err);
5085 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
5086 delete $conf->{$opt};
5090 PVE::QemuConfig->cleanup_pending($conf);
5092 foreach my $opt (keys %{$conf->{pending}}) { # add/change
5093 next if $opt eq 'delete'; # just to be sure
5095 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
5096 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
5100 $add_apply_error->($opt, $err);
5102 $conf->{$opt} = delete $conf->{pending}->{$opt};
5106 # write all changes at once to avoid unnecessary i/o
5107 PVE::QemuConfig->write_config($vmid, $conf);
5110 sub vmconfig_update_net {
5111 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5113 my $newnet = parse_net($value);
5115 if ($conf->{$opt}) {
5116 my $oldnet = parse_net($conf->{$opt});
5118 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5119 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5120 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
5121 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5123 # for non online change, we try to hot-unplug
5124 die "skip\n" if !$hotplug;
5125 vm_deviceunplug($vmid, $conf, $opt);
5128 die "internal error" if $opt !~ m/net(\d+)/;
5129 my $iface = "tap${vmid}i$1";
5131 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5132 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
5133 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
5134 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
5135 PVE::Network::tap_unplug($iface);
5138 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5140 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5142 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
5143 # Rate can be applied on its own but any change above needs to
5144 # include the rate in tap_plug since OVS resets everything.
5145 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
5148 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5149 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5157 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5163 sub vmconfig_update_agent {
5164 my ($conf, $opt, $value) = @_;
5166 die "skip\n" if !$conf->{$opt};
5168 my $hotplug_options = { fstrim_cloned_disks => 1 };
5170 my $old_agent = parse_guest_agent($conf);
5171 my $agent = parse_guest_agent({$opt => $value});
5173 for my $option (keys %$agent) { # added/changed options
5174 next if defined($hotplug_options->{$option});
5175 die "skip\n" if safe_string_ne($agent->{$option}, $old_agent->{$option});
5178 for my $option (keys %$old_agent) { # removed options
5179 next if defined($hotplug_options->{$option});
5180 die "skip\n" if safe_string_ne($old_agent->{$option}, $agent->{$option});
5183 return; # either no actual change (e.g., format string reordered) or just hotpluggable changes
5186 sub vmconfig_update_disk {
5187 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5189 my $drive = parse_drive($opt, $value);
5191 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
5192 my $media = $drive->{media} || 'disk
';
5193 my $oldmedia = $old_drive->{media} || 'disk
';
5194 die "unable to change media type\n" if $media ne $oldmedia;
5196 if (!drive_is_cdrom($old_drive)) {
5198 if ($drive->{file} ne $old_drive->{file}) {
5200 die "skip\n" if !$hotplug;
5202 # unplug and register as unused
5203 vm_deviceunplug($vmid, $conf, $opt);
5204 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5207 # update existing disk
5209 # skip non hotpluggable value
5210 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5211 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5212 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5213 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
5214 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
5219 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5220 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5221 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5222 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5223 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5224 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5225 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5226 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5227 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5228 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5229 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5230 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5231 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5232 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5233 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5234 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5235 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5236 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5238 qemu_block_set_io_throttle(
5240 ($drive->{mbps} || 0)*1024*1024,
5241 ($drive->{mbps_rd} || 0)*1024*1024,
5242 ($drive->{mbps_wr} || 0)*1024*1024,
5243 $drive->{iops} || 0,
5244 $drive->{iops_rd} || 0,
5245 $drive->{iops_wr} || 0,
5246 ($drive->{mbps_max} || 0)*1024*1024,
5247 ($drive->{mbps_rd_max} || 0)*1024*1024,
5248 ($drive->{mbps_wr_max} || 0)*1024*1024,
5249 $drive->{iops_max} || 0,
5250 $drive->{iops_rd_max} || 0,
5251 $drive->{iops_wr_max} || 0,
5252 $drive->{bps_max_length} || 1,
5253 $drive->{bps_rd_max_length} || 1,
5254 $drive->{bps_wr_max_length} || 1,
5255 $drive->{iops_max_length} || 1,
5256 $drive->{iops_rd_max_length} || 1,
5257 $drive->{iops_wr_max_length} || 1,
5267 if ($drive->{file} eq 'none
') {
5268 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5269 if (drive_is_cloudinit($old_drive)) {
5270 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5273 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5275 # force eject if locked
5276 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5279 mon_cmd($vmid, "blockdev-change-medium",
5280 id => "$opt", filename => "$path");
5288 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5290 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5291 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5294 # called in locked context by incoming migration
5295 sub vm_migrate_get_nbd_disks {
5296 my ($storecfg, $conf, $replicated_volumes) = @_;
5298 my $local_volumes = {};
5299 PVE::QemuConfig->foreach_volume($conf, sub {
5300 my ($ds, $drive) = @_;
5302 return if drive_is_cdrom($drive);
5303 return if $ds eq 'tpmstate0
';
5305 my $volid = $drive->{file};
5309 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5311 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5312 return if $scfg->{shared};
5314 # replicated disks re-use existing state via bitmap
5315 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5316 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
5318 return $local_volumes;
5321 # called in locked context by incoming migration
5322 sub vm_migrate_alloc_nbd_disks {
5323 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
5326 foreach my $opt (sort keys %$source_volumes) {
5327 my ($volid, $storeid, $volname, $drive, $use_existing, $format) = @{$source_volumes->{$opt}};
5329 if ($use_existing) {
5330 $nbd->{$opt}->{drivestr} = print_drive($drive);
5331 $nbd->{$opt}->{volid} = $volid;
5332 $nbd->{$opt}->{replicated} = 1;
5336 # storage mapping + volname = regular migration
5337 # storage mapping + format = remote migration
5338 # order of precedence, filtered by whether storage supports it:
5339 # 1. explicit requested format
5340 # 2. format of current volume
5341 # 3. default format of storage
5342 if (!$storagemap->{identity}) {
5343 $storeid = PVE::JSONSchema::map_id($storagemap, $storeid);
5344 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5345 if (!$format || !grep { $format eq $_ } @$validFormats) {
5347 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5348 my $fileFormat = qemu_img_format($scfg, $volname);
5349 $format = $fileFormat
5350 if grep { $fileFormat eq $_ } @$validFormats;
5352 $format //= $defFormat;
5355 # can't happen
for remote migration
, so
$volname is always
defined
5356 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5357 $format = qemu_img_format
($scfg, $volname);
5360 my $size = $drive->{size
} / 1024;
5361 my $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $format, undef, $size);
5362 my $newdrive = $drive;
5363 $newdrive->{format
} = $format;
5364 $newdrive->{file
} = $newvolid;
5365 my $drivestr = print_drive
($newdrive);
5366 $nbd->{$opt}->{drivestr
} = $drivestr;
5367 $nbd->{$opt}->{volid
} = $newvolid;
5373 # see vm_start_nolock for parameters, additionally:
5375 # storagemap = parsed storage map for allocating NBD disks
5377 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5379 return PVE
::QemuConfig-
>lock_config($vmid, sub {
5380 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migrate_opts->{migratedfrom
});
5382 die "you can't start a vm if it's a template\n"
5383 if !$params->{skiptemplate
} && PVE
::QemuConfig-
>is_template($conf);
5385 my $has_suspended_lock = PVE
::QemuConfig-
>has_lock($conf, 'suspended');
5386 my $has_backup_lock = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5388 my $running = check_running
($vmid, undef, $migrate_opts->{migratedfrom
});
5390 if ($has_backup_lock && $running) {
5391 # a backup is currently running, attempt to start the guest in the
5392 # existing QEMU instance
5393 return vm_resume
($vmid);
5396 PVE
::QemuConfig-
>check_lock($conf)
5397 if !($params->{skiplock
} || $has_suspended_lock);
5399 $params->{resume
} = $has_suspended_lock || defined($conf->{vmstate
});
5401 die "VM $vmid already running\n" if $running;
5403 if (my $storagemap = $migrate_opts->{storagemap
}) {
5404 my $replicated = $migrate_opts->{replicated_volumes
};
5405 my $disks = vm_migrate_get_nbd_disks
($storecfg, $conf, $replicated);
5406 $migrate_opts->{nbd
} = vm_migrate_alloc_nbd_disks
($storecfg, $vmid, $disks, $storagemap);
5408 foreach my $opt (keys %{$migrate_opts->{nbd
}}) {
5409 $conf->{$opt} = $migrate_opts->{nbd
}->{$opt}->{drivestr
};
5413 return vm_start_nolock
($storecfg, $vmid, $conf, $params, $migrate_opts);
5419 # statefile => 'tcp', 'unix' for migration or path/volid for RAM state
5420 # skiplock => 0/1, skip checking for config lock
5421 # skiptemplate => 0/1, skip checking whether VM is template
5422 # forcemachine => to force Qemu machine (rollback/migration)
5423 # forcecpu => a QEMU '-cpu' argument string to override get_cpu_options
5424 # timeout => in seconds
5425 # paused => start VM in paused state (backup)
5426 # resume => resume from hibernation
5437 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
5438 # migratedfrom => source node
5439 # spice_ticket => used for spice migration, passed via tunnel/stdin
5440 # network => CIDR of migration network
5441 # type => secure/insecure - tunnel over encrypted connection or plain-text
5442 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
5443 # replicated_volumes => which volids should be re-used with bitmaps for nbd migration
5444 # offline_volumes => new volids of offline migrated disks like tpmstate and cloudinit, not yet
5445 # contained in config
5446 sub vm_start_nolock
{
5447 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
5449 my $statefile = $params->{statefile
};
5450 my $resume = $params->{resume
};
5452 my $migratedfrom = $migrate_opts->{migratedfrom
};
5453 my $migration_type = $migrate_opts->{type
};
5457 # clean up leftover reboot request files
5458 eval { clear_reboot_request
($vmid); };
5461 if (!$statefile && scalar(keys %{$conf->{pending
}})) {
5462 vmconfig_apply_pending
($vmid, $conf, $storecfg);
5463 $conf = PVE
::QemuConfig-
>load_config($vmid); # update/reload
5466 # don't regenerate the ISO if the VM is started as part of a live migration
5467 # this way we can reuse the old ISO with the correct config
5468 PVE
::QemuServer
::Cloudinit
::generate_cloudinitconfig
($conf, $vmid) if !$migratedfrom;
5470 # override offline migrated volumes, conf is out of date still
5471 if (my $offline_volumes = $migrate_opts->{offline_volumes
}) {
5472 for my $key (sort keys $offline_volumes->%*) {
5473 my $parsed = parse_drive
($key, $conf->{$key});
5474 $parsed->{file
} = $offline_volumes->{$key};
5475 $conf->{$key} = print_drive
($parsed);
5479 my $defaults = load_defaults
();
5481 # set environment variable useful inside network script
5482 $ENV{PVE_MIGRATED_FROM
} = $migratedfrom if $migratedfrom;
5484 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-start', 1);
5486 my $forcemachine = $params->{forcemachine
};
5487 my $forcecpu = $params->{forcecpu
};
5489 # enforce machine and CPU type on suspended vm to ensure HW compatibility
5490 $forcemachine = $conf->{runningmachine
};
5491 $forcecpu = $conf->{runningcpu
};
5492 print "Resuming suspended VM\n";
5495 my ($cmd, $vollist, $spice_port) = config_to_command
($storecfg, $vmid,
5496 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
5499 my $get_migration_ip = sub {
5500 my ($nodename) = @_;
5502 return $migration_ip if defined($migration_ip);
5504 my $cidr = $migrate_opts->{network
};
5506 if (!defined($cidr)) {
5507 my $dc_conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5508 $cidr = $dc_conf->{migration
}->{network
};
5511 if (defined($cidr)) {
5512 my $ips = PVE
::Network
::get_local_ip_from_cidr
($cidr);
5514 die "could not get IP: no address configured on local " .
5515 "node for network '$cidr'\n" if scalar(@$ips) == 0;
5517 die "could not get IP: multiple addresses configured on local " .
5518 "node for network '$cidr'\n" if scalar(@$ips) > 1;
5520 $migration_ip = @$ips[0];
5523 $migration_ip = PVE
::Cluster
::remote_node_ip
($nodename, 1)
5524 if !defined($migration_ip);
5526 return $migration_ip;
5531 if ($statefile eq 'tcp') {
5532 my $localip = "localhost";
5533 my $datacenterconf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5534 my $nodename = nodename
();
5536 if (!defined($migration_type)) {
5537 if (defined($datacenterconf->{migration
}->{type
})) {
5538 $migration_type = $datacenterconf->{migration
}->{type
};
5540 $migration_type = 'secure';
5544 if ($migration_type eq 'insecure') {
5545 $localip = $get_migration_ip->($nodename);
5546 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5549 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5550 my $migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5551 $migrate_uri = "tcp:${localip}:${migrate_port}";
5552 push @$cmd, '-incoming', $migrate_uri;
5555 } elsif ($statefile eq 'unix') {
5556 # should be default for secure migrations as a ssh TCP forward
5557 # tunnel is not deterministic reliable ready and fails regurarly
5558 # to set up in time, so use UNIX socket forwards
5559 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5560 unlink $socket_addr;
5562 $migrate_uri = "unix:$socket_addr";
5564 push @$cmd, '-incoming', $migrate_uri;
5567 } elsif (-e
$statefile) {
5568 push @$cmd, '-loadstate', $statefile;
5570 my $statepath = PVE
::Storage
::path
($storecfg, $statefile);
5571 push @$vollist, $statefile;
5572 push @$cmd, '-loadstate', $statepath;
5574 } elsif ($params->{paused
}) {
5578 my $start_timeout = $params->{timeout
} // config_aware_timeout
($conf, $resume);
5580 my $pci_devices = {}; # host pci devices
5581 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
5582 my $dev = $conf->{"hostpci$i"} or next;
5583 $pci_devices->{$i} = parse_hostpci
($dev);
5586 # do not reserve pciid for mediated devices, sysfs will error out for duplicate assignment
5587 my $real_pci_devices = [ grep { !(defined($_->{mdev
}) && scalar($_->{pciid
}->@*) == 1) } values $pci_devices->%* ];
5589 # map to a flat list of pci ids
5590 my $pci_id_list = [ map { $_->{id
} } map { $_->{pciid
}->@* } $real_pci_devices->@* ];
5592 # reserve all PCI IDs before actually doing anything with them
5593 PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_id_list, $vmid, $start_timeout);
5596 for my $id (sort keys %$pci_devices) {
5597 my $d = $pci_devices->{$id};
5598 for my $dev ($d->{pciid
}->@*) {
5599 PVE
::QemuServer
::PCI
::prepare_pci_device
($vmid, $dev->{id
}, $id, $d->{mdev
});
5604 eval { PVE
::QemuServer
::PCI
::remove_pci_reservation
($pci_id_list) };
5609 PVE
::Storage
::activate_volumes
($storecfg, $vollist);
5612 run_command
(['/bin/systemctl', 'stop', "$vmid.scope"], outfunc
=> sub{}, errfunc
=> sub{});
5614 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5615 # timeout should be more than enough here...
5616 PVE
::Systemd
::wait_for_unit_removed
("$vmid.scope", 20);
5618 my $cpuunits = get_cpuunits
($conf);
5621 timeout
=> $statefile ?
undef : $start_timeout,
5626 # when migrating, prefix QEMU output so other side can pick up any
5627 # errors that might occur and show the user
5628 if ($migratedfrom) {
5629 $run_params{quiet
} = 1;
5630 $run_params{logfunc
} = sub { print "QEMU: $_[0]\n" };
5633 my %systemd_properties = (
5634 Slice
=> 'qemu.slice',
5635 KillMode
=> 'process',
5637 TimeoutStopUSec
=> ULONG_MAX
, # infinity
5640 if (PVE
::CGroup
::cgroup_mode
() == 2) {
5641 $systemd_properties{CPUWeight
} = $cpuunits;
5643 $systemd_properties{CPUShares
} = $cpuunits;
5646 if (my $cpulimit = $conf->{cpulimit
}) {
5647 $systemd_properties{CPUQuota
} = int($cpulimit * 100);
5649 $systemd_properties{timeout
} = 10 if $statefile; # setting up the scope shoul be quick
5651 my $run_qemu = sub {
5652 PVE
::Tools
::run_fork
sub {
5653 PVE
::Systemd
::enter_systemd_scope
($vmid, "Proxmox VE VM $vmid", %systemd_properties);
5656 if (my $tpm = $conf->{tpmstate0
}) {
5657 # start the TPM emulator so QEMU can connect on start
5658 $tpmpid = start_swtpm
($storecfg, $vmid, $tpm, $migratedfrom);
5661 my $exitcode = run_command
($cmd, %run_params);
5664 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
5665 kill 'TERM', $tpmpid;
5667 die "QEMU exited with code $exitcode\n";
5672 if ($conf->{hugepages
}) {
5675 my $hugepages_topology = PVE
::QemuServer
::Memory
::hugepages_topology
($conf);
5676 my $hugepages_host_topology = PVE
::QemuServer
::Memory
::hugepages_host_topology
();
5678 PVE
::QemuServer
::Memory
::hugepages_mount
();
5679 PVE
::QemuServer
::Memory
::hugepages_allocate
($hugepages_topology, $hugepages_host_topology);
5681 eval { $run_qemu->() };
5683 PVE
::QemuServer
::Memory
::hugepages_reset
($hugepages_host_topology)
5684 if !$conf->{keephugepages
};
5688 PVE
::QemuServer
::Memory
::hugepages_pre_deallocate
($hugepages_topology)
5689 if !$conf->{keephugepages
};
5691 eval { PVE
::QemuServer
::Memory
::hugepages_update_locked
($code); };
5694 eval { $run_qemu->() };
5698 # deactivate volumes if start fails
5699 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
5700 eval { PVE
::QemuServer
::PCI
::remove_pci_reservation
($pci_id_list) };
5702 die "start failed: $err";
5705 # re-reserve all PCI IDs now that we can know the actual VM PID
5706 my $pid = PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
5707 eval { PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_id_list, $vmid, undef, $pid) };
5710 print "migration listens on $migrate_uri\n" if $migrate_uri;
5711 $res->{migrate_uri
} = $migrate_uri;
5713 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5714 eval { mon_cmd
($vmid, "cont"); };
5718 #start nbd server for storage migration
5719 if (my $nbd = $migrate_opts->{nbd
}) {
5720 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version
} // 0;
5722 my $migrate_storage_uri;
5723 # nbd_protocol_version > 0 for unix socket support
5724 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5725 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5726 mon_cmd
($vmid, "nbd-server-start", addr
=> { type
=> 'unix', data
=> { path
=> $socket_path } } );
5727 $migrate_storage_uri = "nbd:unix:$socket_path";
5729 my $nodename = nodename
();
5730 my $localip = $get_migration_ip->($nodename);
5731 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5732 my $storage_migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5734 mon_cmd
($vmid, "nbd-server-start", addr
=> {
5737 host
=> "${localip}",
5738 port
=> "${storage_migrate_port}",
5741 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5742 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5745 $res->{migrate_storage_uri
} = $migrate_storage_uri;
5747 foreach my $opt (sort keys %$nbd) {
5748 my $drivestr = $nbd->{$opt}->{drivestr
};
5749 my $volid = $nbd->{$opt}->{volid
};
5750 mon_cmd
($vmid, "nbd-server-add", device
=> "drive-$opt", writable
=> JSON
::true
);
5751 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5752 print "storage migration listens on $nbd_uri volume:$drivestr\n";
5753 print "re-using replicated volume: $opt - $volid\n"
5754 if $nbd->{$opt}->{replicated
};
5756 $res->{drives
}->{$opt} = $nbd->{$opt};
5757 $res->{drives
}->{$opt}->{nbd_uri
} = $nbd_uri;
5761 if ($migratedfrom) {
5763 set_migration_caps
($vmid);
5768 print "spice listens on port $spice_port\n";
5769 $res->{spice_port
} = $spice_port;
5770 if ($migrate_opts->{spice_ticket
}) {
5771 mon_cmd
($vmid, "set_password", protocol
=> 'spice', password
=>
5772 $migrate_opts->{spice_ticket
});
5773 mon_cmd
($vmid, "expire_password", protocol
=> 'spice', time => "+30");
5778 mon_cmd
($vmid, "balloon", value
=> $conf->{balloon
}*1024*1024)
5779 if !$statefile && $conf->{balloon
};
5781 foreach my $opt (keys %$conf) {
5782 next if $opt !~ m/^net\d+$/;
5783 my $nicconf = parse_net
($conf->{$opt});
5784 qemu_set_link_status
($vmid, $opt, 0) if $nicconf->{link_down
};
5788 mon_cmd
($vmid, 'qom-set',
5789 path
=> "machine/peripheral/balloon0",
5790 property
=> "guest-stats-polling-interval",
5791 value
=> 2) if (!defined($conf->{balloon
}) || $conf->{balloon
});
5794 print "Resumed VM, removing state\n";
5795 if (my $vmstate = $conf->{vmstate
}) {
5796 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5797 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5799 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
5800 PVE
::QemuConfig-
>write_config($vmid, $conf);
5803 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5808 sub vm_commandline
{
5809 my ($storecfg, $vmid, $snapname) = @_;
5811 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5813 my ($forcemachine, $forcecpu);
5815 my $snapshot = $conf->{snapshots
}->{$snapname};
5816 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5818 # check for machine or CPU overrides in snapshot
5819 $forcemachine = $snapshot->{runningmachine
};
5820 $forcecpu = $snapshot->{runningcpu
};
5822 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5827 my $defaults = load_defaults
();
5829 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu);
5831 return PVE
::Tools
::cmd2string
($cmd);
5835 my ($vmid, $skiplock) = @_;
5837 PVE
::QemuConfig-
>lock_config($vmid, sub {
5839 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5841 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5843 mon_cmd
($vmid, "system_reset");
5847 sub get_vm_volumes
{
5851 foreach_volid
($conf, sub {
5852 my ($volid, $attr) = @_;
5854 return if $volid =~ m
|^/|;
5856 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5859 push @$vollist, $volid;
5865 sub vm_stop_cleanup
{
5866 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5871 my $vollist = get_vm_volumes
($conf);
5872 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5874 if (my $tpmdrive = $conf->{tpmstate0
}) {
5875 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
5876 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
5878 PVE
::Storage
::unmap_volume
($storecfg, $tpm->{file
});
5883 foreach my $ext (qw(mon qmp pid vnc qga)) {
5884 unlink "/var/run/qemu-server/${vmid}.$ext";
5887 if ($conf->{ivshmem
}) {
5888 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5889 # just delete it for now, VMs which have this already open do not
5890 # are affected, but new VMs will get a separated one. If this
5891 # becomes an issue we either add some sort of ref-counting or just
5892 # add a "don't delete on stop" flag to the ivshmem format.
5893 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5897 foreach my $key (keys %$conf) {
5898 next if $key !~ m/^hostpci(\d+)$/;
5899 my $hostpciindex = $1;
5900 my $d = parse_hostpci
($conf->{$key});
5901 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5903 foreach my $pci (@{$d->{pciid
}}) {
5904 my $pciid = $pci->{id
};
5905 push @$ids, $pci->{id
};
5906 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5909 PVE
::QemuServer
::PCI
::remove_pci_reservation
($ids);
5911 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5913 warn $@ if $@; # avoid errors - just warn
5916 # call only in locked context
5918 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5920 my $pid = check_running
($vmid, $nocheck);
5925 $conf = PVE
::QemuConfig-
>load_config($vmid);
5926 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5927 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5928 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5929 $timeout = $opts->{down
} if $opts->{down
};
5931 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5936 if (defined($conf) && get_qga_key
($conf, 'enabled')) {
5937 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5939 mon_cmd
($vmid, "system_powerdown");
5942 mon_cmd
($vmid, "quit");
5948 $timeout = 60 if !defined($timeout);
5951 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5956 if ($count >= $timeout) {
5958 warn "VM still running - terminating now with SIGTERM\n";
5961 die "VM quit/powerdown failed - got timeout\n";
5964 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5968 if (!check_running
($vmid, $nocheck)) {
5969 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5973 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5976 die "VM quit/powerdown failed\n";
5984 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5989 if ($count >= $timeout) {
5990 warn "VM still running - terminating now with SIGKILL\n";
5995 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5998 # Note: use $nocheck to skip tests if VM configuration file exists.
5999 # We need that when migration VMs to other nodes (files already moved)
6000 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
6002 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
6004 $force = 1 if !defined($force) && !$shutdown;
6007 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
6008 kill 15, $pid if $pid;
6009 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
6010 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
6014 PVE
::QemuConfig-
>lock_config($vmid, sub {
6015 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
6020 my ($vmid, $timeout) = @_;
6022 PVE
::QemuConfig-
>lock_config($vmid, sub {
6025 # only reboot if running, as qmeventd starts it again on a stop event
6026 return if !check_running
($vmid);
6028 create_reboot_request
($vmid);
6030 my $storecfg = PVE
::Storage
::config
();
6031 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
6035 # avoid that the next normal shutdown will be confused for a reboot
6036 clear_reboot_request
($vmid);
6042 # note: if using the statestorage parameter, the caller has to check privileges
6044 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
6051 PVE
::QemuConfig-
>lock_config($vmid, sub {
6053 $conf = PVE
::QemuConfig-
>load_config($vmid);
6055 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
6056 PVE
::QemuConfig-
>check_lock($conf)
6057 if !($skiplock || $is_backing_up);
6059 die "cannot suspend to disk during backup\n"
6060 if $is_backing_up && $includestate;
6062 if ($includestate) {
6063 $conf->{lock} = 'suspending';
6064 my $date = strftime
("%Y-%m-%d", localtime(time()));
6065 $storecfg = PVE
::Storage
::config
();
6066 if (!$statestorage) {
6067 $statestorage = find_vmstate_storage
($conf, $storecfg);
6068 # check permissions for the storage
6069 my $rpcenv = PVE
::RPCEnvironment
::get
();
6070 if ($rpcenv->{type
} ne 'cli') {
6071 my $authuser = $rpcenv->get_user();
6072 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
6077 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate(
6078 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
6079 $path = PVE
::Storage
::path
($storecfg, $vmstate);
6080 PVE
::QemuConfig-
>write_config($vmid, $conf);
6082 mon_cmd
($vmid, "stop");
6086 if ($includestate) {
6088 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
6091 set_migration_caps
($vmid, 1);
6092 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
6094 my $state = mon_cmd
($vmid, "query-savevm");
6095 if (!$state->{status
}) {
6096 die "savevm not active\n";
6097 } elsif ($state->{status
} eq 'active') {
6100 } elsif ($state->{status
} eq 'completed') {
6101 print "State saved, quitting\n";
6103 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
6104 die "query-savevm failed with error '$state->{error}'\n"
6106 die "query-savevm returned status '$state->{status}'\n";
6112 PVE
::QemuConfig-
>lock_config($vmid, sub {
6113 $conf = PVE
::QemuConfig-
>load_config($vmid);
6115 # cleanup, but leave suspending lock, to indicate something went wrong
6117 mon_cmd
($vmid, "savevm-end");
6118 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
6119 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
6120 delete $conf->@{qw(vmstate runningmachine runningcpu)};
6121 PVE
::QemuConfig-
>write_config($vmid, $conf);
6127 die "lock changed unexpectedly\n"
6128 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
6130 mon_cmd
($vmid, "quit");
6131 $conf->{lock} = 'suspended';
6132 PVE
::QemuConfig-
>write_config($vmid, $conf);
6138 my ($vmid, $skiplock, $nocheck) = @_;
6140 PVE
::QemuConfig-
>lock_config($vmid, sub {
6141 my $res = mon_cmd
($vmid, 'query-status');
6142 my $resume_cmd = 'cont';
6145 if ($res->{status
}) {
6146 return if $res->{status
} eq 'running'; # job done, go home
6147 $resume_cmd = 'system_wakeup' if $res->{status
} eq 'suspended';
6148 $reset = 1 if $res->{status
} eq 'shutdown';
6153 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6155 PVE
::QemuConfig-
>check_lock($conf)
6156 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
6160 # required if a VM shuts down during a backup and we get a resume
6161 # request before the backup finishes for example
6162 mon_cmd
($vmid, "system_reset");
6164 mon_cmd
($vmid, $resume_cmd);
6169 my ($vmid, $skiplock, $key) = @_;
6171 PVE
::QemuConfig-
>lock_config($vmid, sub {
6173 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6175 # there is no qmp command, so we use the human monitor command
6176 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
6177 die $res if $res ne '';
6181 # vzdump restore implementaion
6183 sub tar_archive_read_firstfile
{
6184 my $archive = shift;
6186 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
6188 # try to detect archive type first
6189 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
6190 die "unable to open file '$archive'\n";
6191 my $firstfile = <$fh>;
6195 die "ERROR: archive contaions no data\n" if !$firstfile;
6201 sub tar_restore_cleanup
{
6202 my ($storecfg, $statfile) = @_;
6204 print STDERR
"starting cleanup\n";
6206 if (my $fd = IO
::File-
>new($statfile, "r")) {
6207 while (defined(my $line = <$fd>)) {
6208 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6211 if ($volid =~ m
|^/|) {
6212 unlink $volid || die 'unlink failed\n';
6214 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6216 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6218 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6220 print STDERR
"unable to parse line in statfile - $line";
6227 sub restore_file_archive
{
6228 my ($archive, $vmid, $user, $opts) = @_;
6230 return restore_vma_archive
($archive, $vmid, $user, $opts)
6233 my $info = PVE
::Storage
::archive_info
($archive);
6234 my $format = $opts->{format
} // $info->{format
};
6235 my $comp = $info->{compression
};
6237 # try to detect archive format
6238 if ($format eq 'tar') {
6239 return restore_tar_archive
($archive, $vmid, $user, $opts);
6241 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
6245 # hepler to remove disks that will not be used after restore
6246 my $restore_cleanup_oldconf = sub {
6247 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6249 my $kept_disks = {};
6251 PVE
::QemuConfig-
>foreach_volume($oldconf, sub {
6252 my ($ds, $drive) = @_;
6254 return if drive_is_cdrom
($drive, 1);
6256 my $volid = $drive->{file
};
6257 return if !$volid || $volid =~ m
|^/|;
6259 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
6260 return if !$path || !$owner || ($owner != $vmid);
6262 # Note: only delete disk we want to restore
6263 # other volumes will become unused
6264 if ($virtdev_hash->{$ds}) {
6265 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
6270 $kept_disks->{$volid} = 1;
6274 # after the restore we have no snapshots anymore
6275 for my $snapname (keys $oldconf->{snapshots
}->%*) {
6276 my $snap = $oldconf->{snapshots
}->{$snapname};
6277 if ($snap->{vmstate
}) {
6278 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
6284 for my $volid (keys $kept_disks->%*) {
6285 eval { PVE
::Storage
::volume_snapshot_delete
($storecfg, $volid, $snapname); };
6291 # Helper to parse vzdump backup device hints
6293 # $rpcenv: Environment, used to ckeck storage permissions
6294 # $user: User ID, to check storage permissions
6295 # $storecfg: Storage configuration
6296 # $fh: the file handle for reading the configuration
6297 # $devinfo: should contain device sizes for all backu-up'ed devices
6298 # $options: backup options (pool, default storage)
6300 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6301 my $parse_backup_hints = sub {
6302 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
6304 my $check_storage = sub { # assert if an image can be allocate
6305 my ($storeid, $scfg) = @_;
6306 die "Content type 'images' is not available on storage '$storeid'\n"
6307 if !$scfg->{content
}->{images
};
6308 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace'])
6309 if $user ne 'root@pam';
6312 my $virtdev_hash = {};
6313 while (defined(my $line = <$fh>)) {
6314 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6315 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6316 die "archive does not contain data for drive '$virtdev'\n"
6317 if !$devinfo->{$devname};
6319 if (defined($options->{storage
})) {
6320 $storeid = $options->{storage
} || 'local';
6321 } elsif (!$storeid) {
6324 $format = 'raw' if !$format;
6325 $devinfo->{$devname}->{devname
} = $devname;
6326 $devinfo->{$devname}->{virtdev
} = $virtdev;
6327 $devinfo->{$devname}->{format
} = $format;
6328 $devinfo->{$devname}->{storeid
} = $storeid;
6330 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6331 $check_storage->($storeid, $scfg); # permission and content type check
6333 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6334 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6336 my $drive = parse_drive
($virtdev, $2);
6338 if (drive_is_cloudinit
($drive)) {
6339 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6340 $storeid = $options->{storage
} if defined ($options->{storage
});
6341 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6342 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
6344 $check_storage->($storeid, $scfg); # permission and content type check
6346 $virtdev_hash->{$virtdev} = {
6348 storeid
=> $storeid,
6349 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6356 return $virtdev_hash;
6359 # Helper to allocate and activate all volumes required for a restore
6361 # $storecfg: Storage configuration
6362 # $virtdev_hash: as returned by parse_backup_hints()
6364 # Returns: { $virtdev => $volid }
6365 my $restore_allocate_devices = sub {
6366 my ($storecfg, $virtdev_hash, $vmid) = @_;
6369 foreach my $virtdev (sort keys %$virtdev_hash) {
6370 my $d = $virtdev_hash->{$virtdev};
6371 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6372 my $storeid = $d->{storeid
};
6373 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6375 # test if requested format is supported
6376 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6377 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6378 $d->{format
} = $defFormat if !$supported;
6381 if ($d->{is_cloudinit
}) {
6382 $name = "vm-$vmid-cloudinit";
6383 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6384 if ($scfg->{path
}) {
6385 $name .= ".$d->{format}";
6389 my $volid = PVE
::Storage
::vdisk_alloc
(
6390 $storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6392 print STDERR
"new volume ID is '$volid'\n";
6393 $d->{volid
} = $volid;
6395 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6397 $map->{$virtdev} = $volid;
6403 sub restore_update_config_line
{
6404 my ($cookie, $map, $line, $unique) = @_;
6406 return '' if $line =~ m/^\#qmdump\#/;
6407 return '' if $line =~ m/^\#vzdump\#/;
6408 return '' if $line =~ m/^lock:/;
6409 return '' if $line =~ m/^unused\d+:/;
6410 return '' if $line =~ m/^parent:/;
6414 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
6415 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6416 # try to convert old 1.X settings
6417 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6418 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
6419 my ($model, $macaddr) = split(/\=/, $devconfig);
6420 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
6423 bridge
=> "vmbr$ind",
6424 macaddr
=> $macaddr,
6426 my $netstr = print_net
($net);
6428 $res .= "net$cookie->{netcount}: $netstr\n";
6429 $cookie->{netcount
}++;
6431 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6432 my ($id, $netstr) = ($1, $2);
6433 my $net = parse_net
($netstr);
6434 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
6435 $netstr = print_net
($net);
6436 $res .= "$id: $netstr\n";
6437 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
6440 my $di = parse_drive
($virtdev, $value);
6441 if (defined($di->{backup
}) && !$di->{backup
}) {
6443 } elsif ($map->{$virtdev}) {
6444 delete $di->{format
}; # format can change on restore
6445 $di->{file
} = $map->{$virtdev};
6446 $value = print_drive
($di);
6447 $res .= "$virtdev: $value\n";
6451 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6453 if ($vmgenid ne '0') {
6454 # always generate a new vmgenid if there was a valid one setup
6455 $vmgenid = generate_uuid
();
6457 $res .= "vmgenid: $vmgenid\n";
6458 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6459 my ($uuid, $uuid_str);
6460 UUID
::generate
($uuid);
6461 UUID
::unparse
($uuid, $uuid_str);
6462 my $smbios1 = parse_smbios1
($2);
6463 $smbios1->{uuid
} = $uuid_str;
6464 $res .= $1.print_smbios1
($smbios1)."\n";
6472 my $restore_deactivate_volumes = sub {
6473 my ($storecfg, $virtdev_hash) = @_;
6476 for my $dev (values $virtdev_hash->%*) {
6477 push $vollist->@*, $dev->{volid
} if $dev->{volid
};
6480 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
6481 print STDERR
$@ if $@;
6484 my $restore_destroy_volumes = sub {
6485 my ($storecfg, $virtdev_hash) = @_;
6487 for my $dev (values $virtdev_hash->%*) {
6488 my $volid = $dev->{volid
} or next;
6490 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6491 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6493 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6497 my $restore_merge_config = sub {
6498 my ($filename, $backup_conf_raw, $override_conf) = @_;
6500 my $backup_conf = parse_vm_config
($filename, $backup_conf_raw);
6501 for my $key (keys $override_conf->%*) {
6502 $backup_conf->{$key} = $override_conf->{$key};
6505 return $backup_conf;
6509 my ($cfg, $vmid) = @_;
6511 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid, undef, 'images');
6513 my $volid_hash = {};
6514 foreach my $storeid (keys %$info) {
6515 foreach my $item (@{$info->{$storeid}}) {
6516 next if !($item->{volid
} && $item->{size
});
6517 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6518 $volid_hash->{$item->{volid
}} = $item;
6525 sub update_disk_config
{
6526 my ($vmid, $conf, $volid_hash) = @_;
6529 my $prefix = "VM $vmid";
6531 # used and unused disks
6532 my $referenced = {};
6534 # Note: it is allowed to define multiple storages with same path (alias), so
6535 # we need to check both 'volid' and real 'path' (two different volid can point
6536 # to the same path).
6538 my $referencedpath = {};
6541 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6542 my ($opt, $drive) = @_;
6544 my $volid = $drive->{file
};
6546 my $volume = $volid_hash->{$volid};
6548 # mark volid as "in-use" for next step
6549 $referenced->{$volid} = 1;
6550 if ($volume && (my $path = $volume->{path
})) {
6551 $referencedpath->{$path} = 1;
6554 return if drive_is_cdrom
($drive);
6557 my ($updated, $msg) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volume->{size
});
6558 if (defined($updated)) {
6560 $conf->{$opt} = print_drive
($updated);
6561 print "$prefix ($opt): $msg\n";
6565 # remove 'unusedX' entry if volume is used
6566 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
6567 my ($opt, $drive) = @_;
6569 my $volid = $drive->{file
};
6573 $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6574 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6575 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
6577 delete $conf->{$opt};
6580 $referenced->{$volid} = 1;
6581 $referencedpath->{$path} = 1 if $path;
6584 foreach my $volid (sort keys %$volid_hash) {
6585 next if $volid =~ m/vm-$vmid-state-/;
6586 next if $referenced->{$volid};
6587 my $path = $volid_hash->{$volid}->{path
};
6588 next if !$path; # just to be sure
6589 next if $referencedpath->{$path};
6591 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6592 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
6593 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6600 my ($vmid, $nolock, $dryrun) = @_;
6602 my $cfg = PVE
::Storage
::config
();
6604 print "rescan volumes...\n";
6605 my $volid_hash = scan_volids
($cfg, $vmid);
6607 my $updatefn = sub {
6610 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6612 PVE
::QemuConfig-
>check_lock($conf);
6615 foreach my $volid (keys %$volid_hash) {
6616 my $info = $volid_hash->{$volid};
6617 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6620 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
6622 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6625 if (defined($vmid)) {
6629 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6632 my $vmlist = config_list
();
6633 foreach my $vmid (keys %$vmlist) {
6637 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6643 sub restore_proxmox_backup_archive
{
6644 my ($archive, $vmid, $user, $options) = @_;
6646 my $storecfg = PVE
::Storage
::config
();
6648 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
6649 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6651 my $fingerprint = $scfg->{fingerprint
};
6652 my $keyfile = PVE
::Storage
::PBSPlugin
::pbs_encryption_key_file_name
($storecfg, $storeid);
6654 my $repo = PVE
::PBSClient
::get_repository
($scfg);
6656 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
6657 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
6658 local $ENV{PBS_PASSWORD
} = $password;
6659 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
6661 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6662 PVE
::Storage
::parse_volname
($storecfg, $archive);
6664 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6666 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6668 my $tmpdir = "/var/tmp/vzdumptmp$$";
6672 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6673 # disable interrupts (always do cleanups)
6677 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6679 # Note: $oldconf is undef if VM does not exists
6680 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6681 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6682 my $new_conf_raw = '';
6684 my $rpcenv = PVE
::RPCEnvironment
::get
();
6685 my $devinfo = {}; # info about drives included in backup
6686 my $virtdev_hash = {}; # info about allocated drives
6694 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6696 my $cfgfn = "$tmpdir/qemu-server.conf";
6697 my $firewall_config_fn = "$tmpdir/fw.conf";
6698 my $index_fn = "$tmpdir/index.json";
6700 my $cmd = "restore";
6702 my $param = [$pbs_backup_name, "index.json", $index_fn];
6703 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6704 my $index = PVE
::Tools
::file_get_contents
($index_fn);
6705 $index = decode_json
($index);
6707 foreach my $info (@{$index->{files
}}) {
6708 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
6710 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
6711 $devinfo->{$devname}->{size
} = $1;
6713 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6718 my $is_qemu_server_backup = scalar(
6719 grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}}
6721 if (!$is_qemu_server_backup) {
6722 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6724 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
6726 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6727 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6729 if ($has_firewall_config) {
6730 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6731 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6733 my $pve_firewall_dir = '/etc/pve/firewall';
6734 mkdir $pve_firewall_dir; # make sure the dir exists
6735 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6738 my $fh = IO
::File-
>new($cfgfn, "r") ||
6739 die "unable to read qemu-server.conf - $!\n";
6741 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6743 # fixme: rate limit?
6745 # create empty/temp config
6746 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6748 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6751 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6753 foreach my $virtdev (sort keys %$virtdev_hash) {
6754 my $d = $virtdev_hash->{$virtdev};
6755 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6757 # this fails if storage is unavailable
6758 my $volid = $d->{volid
};
6759 my $path = PVE
::Storage
::path
($storecfg, $volid);
6761 # for live-restore we only want to preload the efidisk and TPM state
6762 next if $options->{live
} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
6764 my $pbs_restore_cmd = [
6765 '/usr/bin/pbs-restore',
6766 '--repository', $repo,
6768 "$d->{devname}.img.fidx",
6773 push @$pbs_restore_cmd, '--format', $d->{format
} if $d->{format
};
6774 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e
$keyfile;
6776 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6777 push @$pbs_restore_cmd, '--skip-zero';
6780 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6781 print "restore proxmox backup image: $dbg_cmdstring\n";
6782 run_command
($pbs_restore_cmd);
6785 $fh->seek(0, 0) || die "seek failed - $!\n";
6787 my $cookie = { netcount
=> 0 };
6788 while (defined(my $line = <$fh>)) {
6789 $new_conf_raw .= restore_update_config_line
(
6801 if ($err || !$options->{live
}) {
6802 $restore_deactivate_volumes->($storecfg, $virtdev_hash);
6808 $restore_destroy_volumes->($storecfg, $virtdev_hash);
6812 if ($options->{live
}) {
6813 # keep lock during live-restore
6814 $new_conf_raw .= "\nlock: create";
6817 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $options->{override_conf
});
6818 PVE
::QemuConfig-
>write_config($vmid, $new_conf);
6820 eval { rescan
($vmid, 1); };
6823 PVE
::AccessControl
::add_vm_to_pool
($vmid, $options->{pool
}) if $options->{pool
};
6825 if ($options->{live
}) {
6831 local $SIG{PIPE
} = sub { die "got signal ($!) - abort\n"; };
6833 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6834 die "cannot do live-restore for template\n" if PVE
::QemuConfig-
>is_template($conf);
6836 # these special drives are already restored before start
6837 delete $devinfo->{'drive-efidisk0'};
6838 delete $devinfo->{'drive-tpmstate0-backup'};
6839 pbs_live_restore
($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
6841 PVE
::QemuConfig-
>remove_lock($vmid, "create");
6845 sub pbs_live_restore
{
6846 my ($vmid, $conf, $storecfg, $restored_disks, $repo, $keyfile, $snap) = @_;
6848 print "starting VM for live-restore\n";
6849 print "repository: '$repo', snapshot: '$snap'\n";
6851 my $pbs_backing = {};
6852 for my $ds (keys %$restored_disks) {
6853 $ds =~ m/^drive-(.*)$/;
6855 $pbs_backing->{$confname} = {
6856 repository
=> $repo,
6858 archive
=> "$ds.img.fidx",
6860 $pbs_backing->{$confname}->{keyfile
} = $keyfile if -e
$keyfile;
6862 my $drive = parse_drive
($confname, $conf->{$confname});
6863 print "restoring '$ds' to '$drive->{file}'\n";
6866 my $drives_streamed = 0;
6868 # make sure HA doesn't interrupt our restore by stopping the VM
6869 if (PVE
::HA
::Config
::vm_is_ha_managed
($vmid)) {
6870 run_command
(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
6873 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6874 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
6875 vm_start_nolock
($storecfg, $vmid, $conf, {paused
=> 1, 'pbs-backing' => $pbs_backing}, {});
6877 my $qmeventd_fd = register_qmeventd_handle
($vmid);
6879 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6880 # this will effectively collapse the backing image chain consisting of
6881 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6882 # removes itself once all backing images vanish with 'auto-remove=on')
6884 for my $ds (sort keys %$restored_disks) {
6885 my $job_id = "restore-$ds";
6886 mon_cmd
($vmid, 'block-stream',
6887 'job-id' => $job_id,
6890 $jobs->{$job_id} = {};
6893 mon_cmd
($vmid, 'cont');
6894 qemu_drive_mirror_monitor
($vmid, undef, $jobs, 'auto', 0, 'stream');
6896 print "restore-drive jobs finished successfully, removing all tracking block devices"
6897 ." to disconnect from Proxmox Backup Server\n";
6899 for my $ds (sort keys %$restored_disks) {
6900 mon_cmd
($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6903 close($qmeventd_fd);
6909 warn "An error occurred during live-restore: $err\n";
6910 _do_vm_stop
($storecfg, $vmid, 1, 1, 10, 0, 1);
6911 die "live-restore failed\n";
6915 sub restore_vma_archive
{
6916 my ($archive, $vmid, $user, $opts, $comp) = @_;
6918 my $readfrom = $archive;
6920 my $cfg = PVE
::Storage
::config
();
6922 my $bwlimit = $opts->{bwlimit
};
6924 my $dbg_cmdstring = '';
6925 my $add_pipe = sub {
6927 push @$commands, $cmd;
6928 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6929 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6934 if ($archive eq '-') {
6937 # If we use a backup from a PVE defined storage we also consider that
6938 # storage's rate limit:
6939 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6940 if (defined($volid)) {
6941 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6942 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6944 print STDERR
"applying read rate limit: $readlimit\n";
6945 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6946 $add_pipe->($cstream);
6952 my $info = PVE
::Storage
::decompressor_info
('vma', $comp);
6953 my $cmd = $info->{decompressor
};
6954 push @$cmd, $readfrom;
6958 my $tmpdir = "/var/tmp/vzdumptmp$$";
6961 # disable interrupts (always do cleanups)
6965 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6967 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6968 POSIX
::mkfifo
($mapfifo, 0600);
6970 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
6972 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6977 my $devinfo = {}; # info about drives included in backup
6978 my $virtdev_hash = {}; # info about allocated drives
6980 my $rpcenv = PVE
::RPCEnvironment
::get
();
6982 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6984 # Note: $oldconf is undef if VM does not exist
6985 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6986 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6987 my $new_conf_raw = '';
6991 my $print_devmap = sub {
6992 my $cfgfn = "$tmpdir/qemu-server.conf";
6994 # we can read the config - that is already extracted
6995 my $fh = IO
::File-
>new($cfgfn, "r") ||
6996 die "unable to read qemu-server.conf - $!\n";
6998 my $fwcfgfn = "$tmpdir/qemu-server.fw";
7000 my $pve_firewall_dir = '/etc/pve/firewall';
7001 mkdir $pve_firewall_dir; # make sure the dir exists
7002 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
7005 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
7007 foreach my $info (values %{$virtdev_hash}) {
7008 my $storeid = $info->{storeid
};
7009 next if defined($storage_limits{$storeid});
7011 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$storeid], $bwlimit) // 0;
7012 print STDERR
"rate limit for storage $storeid: $limit KiB/s\n" if $limit;
7013 $storage_limits{$storeid} = $limit * 1024;
7016 foreach my $devname (keys %$devinfo) {
7017 die "found no device mapping information for device '$devname'\n"
7018 if !$devinfo->{$devname}->{virtdev
};
7021 # create empty/temp config
7023 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
7024 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
7028 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
7030 # print restore information to $fifofh
7031 foreach my $virtdev (sort keys %$virtdev_hash) {
7032 my $d = $virtdev_hash->{$virtdev};
7033 next if $d->{is_cloudinit
}; # no need to restore cloudinit
7035 my $storeid = $d->{storeid
};
7036 my $volid = $d->{volid
};
7039 if (my $limit = $storage_limits{$storeid}) {
7040 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
7043 my $write_zeros = 1;
7044 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
7048 my $path = PVE
::Storage
::path
($cfg, $volid);
7050 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
7052 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
7055 $fh->seek(0, 0) || die "seek failed - $!\n";
7057 my $cookie = { netcount
=> 0 };
7058 while (defined(my $line = <$fh>)) {
7059 $new_conf_raw .= restore_update_config_line
(
7076 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
7077 local $SIG{ALRM
} = sub { die "got timeout\n"; };
7079 $oldtimeout = alarm($timeout);
7086 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
7087 my ($dev_id, $size, $devname) = ($1, $2, $3);
7088 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
7089 } elsif ($line =~ m/^CTIME: /) {
7090 # we correctly received the vma config, so we can disable
7091 # the timeout now for disk allocation (set to 10 minutes, so
7092 # that we always timeout if something goes wrong)
7095 print $fifofh "done\n";
7096 my $tmp = $oldtimeout || 0;
7097 $oldtimeout = undef;
7104 print "restore vma archive: $dbg_cmdstring\n";
7105 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
7109 alarm($oldtimeout) if $oldtimeout;
7111 $restore_deactivate_volumes->($cfg, $virtdev_hash);
7113 close($fifofh) if $fifofh;
7118 $restore_destroy_volumes->($cfg, $virtdev_hash);
7122 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $opts->{override_conf
});
7123 PVE
::QemuConfig-
>write_config($vmid, $new_conf);
7125 eval { rescan
($vmid, 1); };
7128 PVE
::AccessControl
::add_vm_to_pool
($vmid, $opts->{pool
}) if $opts->{pool
};
7131 sub restore_tar_archive
{
7132 my ($archive, $vmid, $user, $opts) = @_;
7134 if (scalar(keys $opts->{override_conf
}->%*) > 0) {
7135 my $keystring = join(' ', keys $opts->{override_conf
}->%*);
7136 die "cannot pass along options ($keystring) when restoring from tar archive\n";
7139 if ($archive ne '-') {
7140 my $firstfile = tar_archive_read_firstfile
($archive);
7141 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
7142 if $firstfile ne 'qemu-server.conf';
7145 my $storecfg = PVE
::Storage
::config
();
7147 # avoid zombie disks when restoring over an existing VM -> cleanup first
7148 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
7149 # skiplock=1 because qmrestore has set the 'create' lock itself already
7150 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
7151 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
7153 my $tocmd = "/usr/lib/qemu-server/qmextract";
7155 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
7156 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
7157 $tocmd .= ' --prealloc' if $opts->{prealloc
};
7158 $tocmd .= ' --info' if $opts->{info
};
7160 # tar option "xf" does not autodetect compression when read from STDIN,
7161 # so we pipe to zcat
7162 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
7163 PVE
::Tools
::shellquote
("--to-command=$tocmd");
7165 my $tmpdir = "/var/tmp/vzdumptmp$$";
7168 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
7169 local $ENV{VZDUMP_VMID
} = $vmid;
7170 local $ENV{VZDUMP_USER
} = $user;
7172 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
7173 my $new_conf_raw = '';
7175 # disable interrupts (always do cleanups)
7179 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
7187 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
7189 if ($archive eq '-') {
7190 print "extracting archive from STDIN\n";
7191 run_command
($cmd, input
=> "<&STDIN");
7193 print "extracting archive '$archive'\n";
7197 return if $opts->{info
};
7201 my $statfile = "$tmpdir/qmrestore.stat";
7202 if (my $fd = IO
::File-
>new($statfile, "r")) {
7203 while (defined (my $line = <$fd>)) {
7204 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
7205 $map->{$1} = $2 if $1;
7207 print STDERR
"unable to parse line in statfile - $line\n";
7213 my $confsrc = "$tmpdir/qemu-server.conf";
7215 my $srcfd = IO
::File-
>new($confsrc, "r") || die "unable to open file '$confsrc'\n";
7217 my $cookie = { netcount
=> 0 };
7218 while (defined (my $line = <$srcfd>)) {
7219 $new_conf_raw .= restore_update_config_line
(
7230 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
7236 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
7238 PVE
::Cluster
::cfs_update
(); # make sure we read new file
7240 eval { rescan
($vmid, 1); };
7244 sub foreach_storage_used_by_vm
{
7245 my ($conf, $func) = @_;
7249 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7250 my ($ds, $drive) = @_;
7251 return if drive_is_cdrom
($drive);
7253 my $volid = $drive->{file
};
7255 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
7256 $sidhash->{$sid} = $sid if $sid;
7259 foreach my $sid (sort keys %$sidhash) {
7264 my $qemu_snap_storage = {
7267 sub do_snapshots_with_qemu
{
7268 my ($storecfg, $volid, $deviceid) = @_;
7270 return if $deviceid =~ m/tpmstate0/;
7272 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
7273 my $scfg = $storecfg->{ids
}->{$storage_name};
7274 die "could not find storage '$storage_name'\n" if !defined($scfg);
7276 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
7280 if ($volid =~ m/\.(qcow2|qed)$/){
7287 sub qga_check_running
{
7288 my ($vmid, $nowarn) = @_;
7290 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
7292 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
7298 sub template_create
{
7299 my ($vmid, $conf, $disk) = @_;
7301 my $storecfg = PVE
::Storage
::config
();
7303 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7304 my ($ds, $drive) = @_;
7306 return if drive_is_cdrom
($drive);
7307 return if $disk && $ds ne $disk;
7309 my $volid = $drive->{file
};
7310 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
7312 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
7313 $drive->{file
} = $voliddst;
7314 $conf->{$ds} = print_drive
($drive);
7315 PVE
::QemuConfig-
>write_config($vmid, $conf);
7319 sub convert_iscsi_path
{
7322 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
7327 my $initiator_name = get_initiator_name
();
7329 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7330 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7333 die "cannot convert iscsi path '$path', unkown format\n";
7336 sub qemu_img_convert
{
7337 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
7339 my $storecfg = PVE
::Storage
::config
();
7340 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
7341 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
7343 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
7347 my $src_is_iscsi = 0;
7351 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
7352 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
7353 $src_format = qemu_img_format
($src_scfg, $src_volname);
7354 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
7355 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
7356 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
7357 } elsif (-f
$src_volid || -b
$src_volid) {
7358 $src_path = $src_volid;
7359 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7364 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
7366 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7367 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
7368 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7369 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
7372 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
7373 push @$cmd, '-l', "snapshot.name=$snapname"
7374 if $snapname && $src_format && $src_format eq "qcow2";
7375 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
7376 push @$cmd, '-T', $cachemode if defined($cachemode);
7378 if ($src_is_iscsi) {
7379 push @$cmd, '--image-opts';
7380 $src_path = convert_iscsi_path
($src_path);
7381 } elsif ($src_format) {
7382 push @$cmd, '-f', $src_format;
7385 if ($dst_is_iscsi) {
7386 push @$cmd, '--target-image-opts';
7387 $dst_path = convert_iscsi_path
($dst_path);
7389 push @$cmd, '-O', $dst_format;
7392 push @$cmd, $src_path;
7394 if (!$dst_is_iscsi && $is_zero_initialized) {
7395 push @$cmd, "zeroinit:$dst_path";
7397 push @$cmd, $dst_path;
7402 if($line =~ m/\((\S+)\/100\
%\)/){
7404 my $transferred = int($size * $percent / 100);
7405 my $total_h = render_bytes
($size, 1);
7406 my $transferred_h = render_bytes
($transferred, 1);
7408 print "transferred $transferred_h of $total_h ($percent%)\n";
7413 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
7415 die "copy failed: $err" if $err;
7418 sub qemu_img_format
{
7419 my ($scfg, $volname) = @_;
7421 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7428 sub qemu_drive_mirror
{
7429 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
7431 $jobs = {} if !$jobs;
7435 $jobs->{"drive-$drive"} = {};
7437 if ($dst_volid =~ /^nbd:/) {
7438 $qemu_target = $dst_volid;
7441 my $storecfg = PVE
::Storage
::config
();
7442 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
7444 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7446 $format = qemu_img_format
($dst_scfg, $dst_volname);
7448 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7450 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
7453 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
7454 $opts->{format
} = $format if $format;
7456 if (defined($src_bitmap)) {
7457 $opts->{sync
} = 'incremental';
7458 $opts->{bitmap
} = $src_bitmap;
7459 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7462 if (defined($bwlimit)) {
7463 $opts->{speed
} = $bwlimit * 1024;
7464 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
7466 print "drive mirror is starting for drive-$drive\n";
7469 # if a job already runs for this device we get an error, catch it for cleanup
7470 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
7472 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7474 die "mirroring error: $err\n";
7477 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
7480 # $completion can be either
7481 # 'complete': wait until all jobs are ready, block-job-complete them (default)
7482 # 'cancel': wait until all jobs are ready, block-job-cancel them
7483 # 'skip': wait until all jobs are ready, return with block jobs in ready state
7484 # 'auto': wait until all jobs disappear, only use for jobs which complete automatically
7485 sub qemu_drive_mirror_monitor
{
7486 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
7488 $completion //= 'complete';
7492 my $err_complete = 0;
7494 my $starttime = time ();
7496 die "block job ('$op') timed out\n" if $err_complete > 300;
7498 my $stats = mon_cmd
($vmid, "query-block-jobs");
7501 my $running_jobs = {};
7502 for my $stat (@$stats) {
7503 next if $stat->{type
} ne $op;
7504 $running_jobs->{$stat->{device
}} = $stat;
7507 my $readycounter = 0;
7509 for my $job_id (sort keys %$jobs) {
7510 my $job = $running_jobs->{$job_id};
7512 my $vanished = !defined($job);
7513 my $complete = defined($jobs->{$job_id}->{complete
}) && $vanished;
7514 if($complete || ($vanished && $completion eq 'auto')) {
7515 print "$job_id: $op-job finished\n";
7516 delete $jobs->{$job_id};
7520 die "$job_id: '$op' has been cancelled\n" if !defined($job);
7522 my $busy = $job->{busy
};
7523 my $ready = $job->{ready
};
7524 if (my $total = $job->{len
}) {
7525 my $transferred = $job->{offset
} || 0;
7526 my $remaining = $total - $transferred;
7527 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
7529 my $duration = $ctime - $starttime;
7530 my $total_h = render_bytes
($total, 1);
7531 my $transferred_h = render_bytes
($transferred, 1);
7533 my $status = sprintf(
7534 "transferred $transferred_h of $total_h ($percent%%) in %s",
7535 render_duration
($duration),
7540 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7542 $status .= ", ready";
7545 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready
};
7546 $jobs->{$job_id}->{ready
} = $ready;
7549 $readycounter++ if $job->{ready
};
7552 last if scalar(keys %$jobs) == 0;
7554 if ($readycounter == scalar(keys %$jobs)) {
7555 print "all '$op' jobs are ready\n";
7557 # do the complete later (or has already been done)
7558 last if $completion eq 'skip' || $completion eq 'auto';
7560 if ($vmiddst && $vmiddst != $vmid) {
7561 my $agent_running = $qga && qga_check_running
($vmid);
7562 if ($agent_running) {
7563 print "freeze filesystem\n";
7564 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
7567 print "suspend vm\n";
7568 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
7572 # if we clone a disk for a new target vm, we don't switch the disk
7573 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
7575 if ($agent_running) {
7576 print "unfreeze filesystem\n";
7577 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
7580 print "resume vm\n";
7581 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
7588 for my $job_id (sort keys %$jobs) {
7589 # try to switch the disk if source and destination are on the same guest
7590 print "$job_id: Completing block job_id...\n";
7593 if ($completion eq 'complete') {
7594 $op = 'block-job-complete';
7595 } elsif ($completion eq 'cancel') {
7596 $op = 'block-job-cancel';
7598 die "invalid completion value: $completion\n";
7600 eval { mon_cmd
($vmid, $op, device
=> $job_id) };
7601 if ($@ =~ m/cannot be completed/) {
7602 print "$job_id: block job cannot be completed, trying again.\n";
7605 print "$job_id: Completed successfully.\n";
7606 $jobs->{$job_id}->{complete
} = 1;
7617 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7618 die "block job ($op) error: $err";
7622 sub qemu_blockjobs_cancel
{
7623 my ($vmid, $jobs) = @_;
7625 foreach my $job (keys %$jobs) {
7626 print "$job: Cancelling block job\n";
7627 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
7628 $jobs->{$job}->{cancel
} = 1;
7632 my $stats = mon_cmd
($vmid, "query-block-jobs");
7634 my $running_jobs = {};
7635 foreach my $stat (@$stats) {
7636 $running_jobs->{$stat->{device
}} = $stat;
7639 foreach my $job (keys %$jobs) {
7641 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
7642 print "$job: Done.\n";
7643 delete $jobs->{$job};
7647 last if scalar(keys %$jobs) == 0;
7654 my ($storecfg, $source, $dest, $full, $newvollist, $jobs, $completion, $qga, $bwlimit) = @_;
7656 my ($vmid, $running) = $source->@{qw(vmid running)};
7657 my ($src_drivename, $drive, $snapname) = $source->@{qw(drivename drive snapname)};
7659 my ($newvmid, $dst_drivename, $efisize) = $dest->@{qw(vmid drivename efisize)};
7660 my ($storage, $format) = $dest->@{qw(storage format)};
7662 my $use_drive_mirror = $full && $running && $src_drivename && !$snapname;
7664 if ($src_drivename && $dst_drivename && $src_drivename ne $dst_drivename) {
7665 die "cloning from/to EFI disk requires EFI disk\n"
7666 if $src_drivename eq 'efidisk0' || $dst_drivename eq 'efidisk0';
7667 die "cloning from/to TPM state requires TPM state\n"
7668 if $src_drivename eq 'tpmstate0' || $dst_drivename eq 'tpmstate0';
7670 # This would lead to two device nodes in QEMU pointing to the same backing image!
7671 die "cannot change drive name when cloning disk from/to the same VM\n"
7672 if $use_drive_mirror && $vmid == $newvmid;
7675 die "cannot move TPM state while VM is running\n"
7676 if $use_drive_mirror && $src_drivename eq 'tpmstate0';
7680 print "create " . ($full ?
'full' : 'linked') . " clone of drive ";
7681 print "$src_drivename " if $src_drivename;
7682 print "($drive->{file})\n";
7685 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
7686 push @$newvollist, $newvolid;
7689 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7690 $storeid = $storage if $storage;
7692 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7696 if (drive_is_cloudinit
($drive)) {
7697 $name = "vm-$newvmid-cloudinit";
7698 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7699 if ($scfg->{path
}) {
7700 $name .= ".$dst_format";
7703 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
7704 } elsif ($dst_drivename eq 'efidisk0') {
7705 $size = $efisize or die "internal error - need to specify EFI disk size\n";
7706 } elsif ($dst_drivename eq 'tpmstate0') {
7707 $dst_format = 'raw';
7708 $size = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
7710 ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 10);
7712 $newvolid = PVE
::Storage
::vdisk_alloc
(
7713 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7715 push @$newvollist, $newvolid;
7717 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7719 if (drive_is_cloudinit
($drive)) {
7720 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7721 # if this is the case, we have to complete any block-jobs still there from
7722 # previous drive-mirrors
7723 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7724 qemu_drive_mirror_monitor
($vmid, $newvmid, $jobs, $completion, $qga);
7729 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7730 if ($use_drive_mirror) {
7731 qemu_drive_mirror
($vmid, $src_drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7732 $completion, $qga, $bwlimit);
7734 # TODO: handle bwlimits
7735 if ($dst_drivename eq 'efidisk0') {
7736 # the relevant data on the efidisk may be smaller than the source
7737 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7738 # that is given by the OVMF_VARS.fd
7739 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
7740 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
7742 my $src_format = (PVE
::Storage
::parse_volname
($storecfg, $drive->{file
}))[6];
7744 # better for Ceph if block size is not too small, see bug #3324
7747 my $cmd = ['qemu-img', 'dd', '-n', '-O', $dst_format];
7749 if ($src_format eq 'qcow2' && $snapname) {
7750 die "cannot clone qcow2 EFI disk snapshot - requires QEMU >= 6.2\n"
7751 if !min_version
(kvm_user_version
(), 6, 2);
7752 push $cmd->@*, '-l', $snapname;
7754 push $cmd->@*, "bs=$bs", "osize=$size", "if=$src_path", "of=$dst_path";
7757 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7763 my ($size) = eval { PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 10) };
7765 my $disk = dclone
($drive);
7766 delete $disk->{format
};
7767 $disk->{file
} = $newvolid;
7768 $disk->{size
} = $size if defined($size);
7773 sub get_running_qemu_version
{
7775 my $res = mon_cmd
($vmid, "query-version");
7776 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7779 sub qemu_use_old_bios_files
{
7780 my ($machine_type) = @_;
7782 return if !$machine_type;
7784 my $use_old_bios_files = undef;
7786 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7788 $use_old_bios_files = 1;
7790 my $version = extract_version
($machine_type, kvm_user_version
());
7791 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7792 # load new efi bios files on migration. So this hack is required to allow
7793 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7794 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7795 $use_old_bios_files = !min_version
($version, 2, 4);
7798 return ($use_old_bios_files, $machine_type);
7801 sub get_efivars_size
{
7802 my ($conf, $efidisk) = @_;
7804 my $arch = get_vm_arch
($conf);
7805 $efidisk //= $conf->{efidisk0
} ? parse_drive
('efidisk0', $conf->{efidisk0
}) : undef;
7806 my $smm = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
7807 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk, $smm);
7808 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
7809 return -s
$ovmf_vars;
7812 sub update_efidisk_size
{
7815 return if !defined($conf->{efidisk0
});
7817 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
7818 $disk->{size
} = get_efivars_size
($conf);
7819 $conf->{efidisk0
} = print_drive
($disk);
7824 sub update_tpmstate_size
{
7827 my $disk = PVE
::QemuServer
::parse_drive
('tpmstate0', $conf->{tpmstate0
});
7828 $disk->{size
} = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
7829 $conf->{tpmstate0
} = print_drive
($disk);
7832 sub create_efidisk
($$$$$$$) {
7833 my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk, $smm) = @_;
7835 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk, $smm);
7836 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7838 my $vars_size_b = -s
$ovmf_vars;
7839 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
7840 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7841 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7843 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
7844 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
7846 return ($volid, $size/1024);
7849 sub vm_iothreads_list
{
7852 my $res = mon_cmd
($vmid, 'query-iothreads');
7855 foreach my $iothread (@$res) {
7856 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7863 my ($conf, $drive) = @_;
7867 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7869 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7875 my $controller = int($drive->{index} / $maxdev);
7876 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single')
7880 return ($maxdev, $controller, $controller_prefix);
7883 sub windows_version
{
7886 return 0 if !$ostype;
7890 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7892 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7894 } elsif ($ostype =~ m/^win(\d+)$/) {
7901 sub resolve_dst_disk_format
{
7902 my ($storecfg, $storeid, $src_volname, $format) = @_;
7903 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7906 # if no target format is specified, use the source disk format as hint
7908 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7909 $format = qemu_img_format
($scfg, $src_volname);
7915 # test if requested format is supported - else use default
7916 my $supported = grep { $_ eq $format } @$validFormats;
7917 $format = $defFormat if !$supported;
7921 # NOTE: if this logic changes, please update docs & possibly gui logic
7922 sub find_vmstate_storage
{
7923 my ($conf, $storecfg) = @_;
7925 # first, return storage from conf if set
7926 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
7928 my ($target, $shared, $local);
7930 foreach_storage_used_by_vm
($conf, sub {
7932 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7933 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7934 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7937 # second, use shared storage where VM has at least one disk
7938 # third, use local storage where VM has at least one disk
7939 # fall back to local storage
7940 $target = $shared // $local // 'local';
7946 my ($uuid, $uuid_str);
7947 UUID
::generate
($uuid);
7948 UUID
::unparse
($uuid, $uuid_str);
7952 sub generate_smbios1_uuid
{
7953 return "uuid=".generate_uuid
();
7959 mon_cmd
($vmid, 'nbd-server-stop');
7962 sub create_reboot_request
{
7964 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7965 or die "failed to create reboot trigger file: $!\n";
7969 sub clear_reboot_request
{
7971 my $path = "/run/qemu-server/$vmid.reboot";
7974 $res = unlink($path);
7975 die "could not remove reboot request for $vmid: $!"
7976 if !$res && $! != POSIX
::ENOENT
;
7981 sub bootorder_from_legacy
{
7982 my ($conf, $bootcfg) = @_;
7984 my $boot = $bootcfg->{legacy
} || $boot_fmt->{legacy
}->{default};
7985 my $bootindex_hash = {};
7987 foreach my $o (split(//, $boot)) {
7988 $bootindex_hash->{$o} = $i*100;
7994 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7995 my ($ds, $drive) = @_;
7997 if (drive_is_cdrom
($drive, 1)) {
7998 if ($bootindex_hash->{d
}) {
7999 $bootorder->{$ds} = $bootindex_hash->{d
};
8000 $bootindex_hash->{d
} += 1;
8002 } elsif ($bootindex_hash->{c
}) {
8003 $bootorder->{$ds} = $bootindex_hash->{c
}
8004 if $conf->{bootdisk
} && $conf->{bootdisk
} eq $ds;
8005 $bootindex_hash->{c
} += 1;
8009 if ($bootindex_hash->{n
}) {
8010 for (my $i = 0; $i < $MAX_NETS; $i++) {
8011 my $netname = "net$i";
8012 next if !$conf->{$netname};
8013 $bootorder->{$netname} = $bootindex_hash->{n
};
8014 $bootindex_hash->{n
} += 1;
8021 # Generate default device list for 'boot: order=' property. Matches legacy
8022 # default boot order, but with explicit device names. This is important, since
8023 # the fallback for when neither 'order' nor the old format is specified relies
8024 # on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
8025 sub get_default_bootdevices
{
8031 my $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 0);
8032 push @ret, $first if $first;
8035 $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 1);
8036 push @ret, $first if $first;
8039 for (my $i = 0; $i < $MAX_NETS; $i++) {
8040 my $netname = "net$i";
8041 next if !$conf->{$netname};
8042 push @ret, $netname;
8049 sub device_bootorder
{
8052 return bootorder_from_legacy
($conf) if !defined($conf->{boot
});
8054 my $boot = parse_property_string
($boot_fmt, $conf->{boot
});
8057 if (!defined($boot) || $boot->{legacy
}) {
8058 $bootorder = bootorder_from_legacy
($conf, $boot);
8059 } elsif ($boot->{order
}) {
8060 my $i = 100; # start at 100 to allow user to insert devices before us with -args
8061 for my $dev (PVE
::Tools
::split_list
($boot->{order
})) {
8062 $bootorder->{$dev} = $i++;
8069 sub register_qmeventd_handle
{
8073 my $peer = "/var/run/qmeventd.sock";
8078 $fh = IO
::Socket
::UNIX-
>new(Peer
=> $peer, Blocking
=> 0, Timeout
=> 1);
8080 if ($! != EINTR
&& $! != EAGAIN
) {
8081 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
8084 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
8085 . "after $count retries\n";
8090 # send handshake to mark VM as backing up
8091 print $fh to_json
({vzdump
=> {vmid
=> "$vmid"}});
8093 # return handle to be closed later when inhibit is no longer required
8097 # bash completion helper
8099 sub complete_backup_archives
{
8100 my ($cmdname, $pname, $cvalue) = @_;
8102 my $cfg = PVE
::Storage
::config
();
8106 if ($cvalue =~ m/^([^:]+):/) {
8110 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
8113 foreach my $id (keys %$data) {
8114 foreach my $item (@{$data->{$id}}) {
8115 next if $item->{format
} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
8116 push @$res, $item->{volid
} if defined($item->{volid
});
8123 my $complete_vmid_full = sub {
8126 my $idlist = vmstatus
();
8130 foreach my $id (keys %$idlist) {
8131 my $d = $idlist->{$id};
8132 if (defined($running)) {
8133 next if $d->{template
};
8134 next if $running && $d->{status
} ne 'running';
8135 next if !$running && $d->{status
} eq 'running';
8144 return &$complete_vmid_full();
8147 sub complete_vmid_stopped
{
8148 return &$complete_vmid_full(0);
8151 sub complete_vmid_running
{
8152 return &$complete_vmid_full(1);
8155 sub complete_storage
{
8157 my $cfg = PVE
::Storage
::config
();
8158 my $ids = $cfg->{ids
};
8161 foreach my $sid (keys %$ids) {
8162 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
8163 next if !$ids->{$sid}->{content
}->{images
};
8170 sub complete_migration_storage
{
8171 my ($cmd, $param, $current_value, $all_args) = @_;
8173 my $targetnode = @$all_args[1];
8175 my $cfg = PVE
::Storage
::config
();
8176 my $ids = $cfg->{ids
};
8179 foreach my $sid (keys %$ids) {
8180 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
8181 next if !$ids->{$sid}->{content
}->{images
};
8190 my $qmpstatus = eval {
8191 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid);
8192 mon_cmd
($vmid, "query-status");
8195 return $qmpstatus && $qmpstatus->{status
} eq "paused";
8198 sub check_volume_storage_type
{
8199 my ($storecfg, $vol) = @_;
8201 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($vol);
8202 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
8203 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $vol);
8205 die "storage '$storeid' does not support content-type '$vtype'\n"
8206 if !$scfg->{content
}->{$vtype};