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.secboot.fd",
69 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
72 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
73 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
76 "$EDK2_FW_BASE/OVMF_CODE.fd",
77 "$EDK2_FW_BASE/OVMF_VARS.fd",
82 "$EDK2_FW_BASE/AAVMF_CODE.fd",
83 "$EDK2_FW_BASE/AAVMF_VARS.fd",
88 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
90 # Note about locking: we use flock on the config file protect against concurent actions.
91 # Aditionaly, we have a 'lock' setting in the config file. This can be set to 'migrate',
92 # 'backup', 'snapshot' or 'rollback'. Most actions are not allowed when such lock is set.
93 # But you can ignore this kind of lock with the --skiplock flag.
95 cfs_register_file
('/qemu-server/',
99 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
100 description
=> "Some command save/restore state from this location.",
106 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
107 description
=> "Specifies the Qemu machine type.",
109 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
116 my ($map, $source) = @_;
118 return $source if !defined($map);
120 return $map->{entries
}->{$source}
121 if $map->{entries
} && defined($map->{entries
}->{$source});
123 return $map->{default} if $map->{default};
125 # identity (fallback)
129 PVE
::JSONSchema
::register_standard_option
('pve-targetstorage', {
130 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.",
132 format
=> 'storagepair-list',
136 #no warnings 'redefine';
140 $nodename_cache //= PVE
::INotify
::nodename
();
141 return $nodename_cache;
148 enum
=> [qw(i6300esb ib700)],
149 description
=> "Watchdog type to emulate.",
150 default => 'i6300esb',
155 enum
=> [qw(reset shutdown poweroff pause debug none)],
156 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
160 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
164 description
=> "Enable/disable communication with a Qemu Guest Agent (QGA) running in the VM.",
169 fstrim_cloned_disks
=> {
170 description
=> "Run fstrim after moving a disk or migrating the VM.",
176 description
=> "Select the agent type",
180 enum
=> [qw(virtio isa)],
186 description
=> "Select the VGA type.",
191 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
194 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
206 description
=> "The size of the file in MB.",
210 pattern
=> '[a-zA-Z0-9\-]+',
212 format_description
=> 'string',
213 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
220 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
221 description
=> "Configure an audio device."
225 enum
=> ['spice', 'none'],
228 description
=> "Driver backend for the audio device."
232 my $spice_enhancements_fmt = {
237 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
241 enum
=> ['off', 'all', 'filter'],
244 description
=> "Enable video streaming. Uses compression for detected video streams."
251 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
253 description
=> "The file on the host to gather entropy from. In most cases '/dev/urandom'"
254 ." should be preferred over '/dev/random' to avoid entropy-starvation issues on the"
255 ." host. Using urandom does *not* decrease security in any meaningful way, as it's"
256 ." still seeded from real entropy, and the bytes provided will most likely be mixed"
257 ." with real entropy on the guest as well. '/dev/hwrng' can be used to pass through"
258 ." a hardware RNG from the host.",
262 description
=> "Maximum bytes of entropy allowed to get injected into the guest every"
263 ." 'period' milliseconds. Prefer a lower value when using '/dev/random' as source. Use"
264 ." `0` to disable limiting (potentially dangerous!).",
267 # default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
268 # (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
269 # reading from /dev/urandom
274 description
=> "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
275 ." the guest to retrieve another 'max_bytes' of entropy.",
285 description
=> "Specifies whether a VM will be started during system bootup.",
291 description
=> "Automatic restart after crash (currently ignored).",
296 type
=> 'string', format
=> 'pve-hotplug-features',
297 description
=> "Selectively enable hotplug features. This is a comma separated list of"
298 ." hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable"
299 ." hotplug completely. Using '1' as value is an alias for the default `network,disk,usb`.",
300 default => 'network,disk,usb',
305 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
311 description
=> "Lock/unlock the VM.",
312 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
317 description
=> "Limit of CPU usage.",
318 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has"
319 ." total of '2' CPU time. Value '0' indicates no CPU limit.",
327 description
=> "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
328 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler."
329 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
330 ." weights of all the other running VMs.",
333 default => 'cgroup v1: 1024, cgroup v2: 100',
338 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when"
339 ." you use the balloon device.",
346 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
352 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the"
353 ." more memory this VM gets. Number is relative to weights of all other running VMs."
354 ." Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
362 description
=> "Keyboard layout for VNC server. The default is read from the"
363 ."'/etc/pve/datacenter.cfg' configuration file. It should not be necessary to set it.",
364 enum
=> PVE
::Tools
::kvmkeymaplist
(),
369 type
=> 'string', format
=> 'dns-name',
370 description
=> "Set a name for the VM. Only used on the configuration web interface.",
375 description
=> "SCSI controller model",
376 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
382 description
=> "Description for the VM. Shown in the web-interface VM's summary."
383 ." This is saved as comment inside the configuration file.",
384 maxLength
=> 1024 * 8,
389 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
390 description
=> "Specify guest operating system.",
391 verbose_description
=> <<EODESC,
392 Specify guest operating system. This is used to enable special
393 optimization/features for specific operating systems:
396 other;; unspecified OS
397 wxp;; Microsoft Windows XP
398 w2k;; Microsoft Windows 2000
399 w2k3;; Microsoft Windows 2003
400 w2k8;; Microsoft Windows 2008
401 wvista;; Microsoft Windows Vista
402 win7;; Microsoft Windows 7
403 win8;; Microsoft Windows 8/2012/2012r2
404 win10;; Microsoft Windows 10/2016/2019
405 win11;; Microsoft Windows 11/2022
406 l24;; Linux 2.4 Kernel
407 l26;; Linux 2.6 - 5.X Kernel
408 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
413 type
=> 'string', format
=> 'pve-qm-boot',
414 description
=> "Specify guest boot order. Use the 'order=' sub-property as usage with no"
415 ." key or 'legacy=' is deprecated.",
419 type
=> 'string', format
=> 'pve-qm-bootdisk',
420 description
=> "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
421 pattern
=> '(ide|sata|scsi|virtio)\d+',
426 description
=> "The number of CPUs. Please use option -sockets instead.",
433 description
=> "The number of CPU sockets.",
440 description
=> "The number of cores per socket.",
447 description
=> "Enable/disable NUMA.",
453 description
=> "Enable/disable hugepages memory.",
454 enum
=> [qw(any 2 1024)],
460 description
=> "Use together with hugepages. If enabled, hugepages will not not be deleted"
461 ." after VM shutdown and can be used for subsequent starts.",
466 description
=> "Number of hotplugged vcpus.",
473 description
=> "Enable/disable ACPI.",
478 description
=> "Enable/disable communication with the Qemu Guest Agent and its properties.",
480 format
=> $agent_fmt,
485 description
=> "Enable/disable KVM hardware virtualization.",
491 description
=> "Enable/disable time drift fix.",
497 description
=> "Set the real time clock (RTC) to local time. This is enabled by default if"
498 ." the `ostype` indicates a Microsoft Windows OS.",
503 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
507 type
=> 'string', format
=> $vga_fmt,
508 description
=> "Configure the VGA hardware.",
509 verbose_description
=> "Configure the VGA Hardware. If you want to use high resolution"
510 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
511 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
512 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
513 ." display server. For win* OS you can select how many independent displays you want,"
514 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
515 ." using a serial device as terminal.",
519 type
=> 'string', format
=> 'pve-qm-watchdog',
520 description
=> "Create a virtual hardware watchdog device.",
521 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled (by a guest"
522 ." action), the watchdog must be periodically polled by an agent inside the guest or"
523 ." else the watchdog will reset the guest (or execute the respective action specified)",
528 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
529 description
=> "Set the initial date of the real time clock. Valid format for date are:"
530 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
531 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
534 startup
=> get_standard_option
('pve-startup-order'),
538 description
=> "Enable/disable Template.",
544 description
=> "Arbitrary arguments passed to kvm.",
545 verbose_description
=> <<EODESCR,
546 Arbitrary arguments passed to kvm, for example:
548 args: -no-reboot -no-hpet
550 NOTE: this option is for experts only.
557 description
=> "Enable/disable the USB tablet device.",
558 verbose_description
=> "Enable/disable the USB tablet device. This device is usually needed"
559 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
560 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
561 ." may consider disabling this to save some context switches. This is turned off by"
562 ." default if you use spice (`qm set <vmid> --vga qxl`).",
567 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
571 migrate_downtime
=> {
574 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
580 type
=> 'string', format
=> 'pve-qm-ide',
581 typetext
=> '<volume>',
582 description
=> "This is an alias for option -ide2",
586 description
=> "Emulated CPU type.",
588 format
=> 'pve-vm-cpu-conf',
590 parent
=> get_standard_option
('pve-snapshot-name', {
592 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
596 description
=> "Timestamp for snapshots.",
602 type
=> 'string', format
=> 'pve-volume-id',
603 description
=> "Reference to a volume which stores the VM state. This is used internally"
606 vmstatestorage
=> get_standard_option
('pve-storage-id', {
607 description
=> "Default storage for VM state volumes/files.",
610 runningmachine
=> get_standard_option
('pve-qemu-machine', {
611 description
=> "Specifies the QEMU machine type of the running vm. This is used internally"
615 description
=> "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
616 ." internally for snapshots.",
619 pattern
=> $PVE::QemuServer
::CPUConfig
::qemu_cmdline_cpu_re
,
620 format_description
=> 'QEMU -cpu parameter'
622 machine
=> get_standard_option
('pve-qemu-machine'),
624 description
=> "Virtual processor architecture. Defaults to the host.",
627 enum
=> [qw(x86_64 aarch64)],
630 description
=> "Specify SMBIOS type 1 fields.",
631 type
=> 'string', format
=> 'pve-qm-smbios1',
638 description
=> "Sets the protection flag of the VM. This will disable the remove VM and"
639 ." remove disk operations.",
645 enum
=> [ qw(seabios ovmf) ],
646 description
=> "Select BIOS implementation.",
647 default => 'seabios',
651 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
652 format_description
=> 'UUID',
653 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
654 ." to disable explicitly.",
655 verbose_description
=> "The VM generation ID (vmgenid) device exposes a 128-bit integer"
656 ." value identifier to the guest OS. This allows to notify the guest operating system"
657 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
658 ." execution or creation from a template). The guest operating system notices the"
659 ." change, and is then able to react as appropriate by marking its copies of"
660 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
661 ."Note that auto-creation only works when done through API/CLI create or update methods"
662 .", but not when manually editing the config file.",
663 default => "1 (autogenerated)",
668 format
=> 'pve-volume-id',
670 description
=> "Script that will be executed during various steps in the vms lifetime.",
674 format
=> $ivshmem_fmt,
675 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to"
681 format
=> $audio_fmt,
682 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
685 spice_enhancements
=> {
687 format
=> $spice_enhancements_fmt,
688 description
=> "Configure additional enhancements for SPICE.",
692 type
=> 'string', format
=> 'pve-tag-list',
693 description
=> 'Tags of the VM. This is only meta information.',
699 description
=> "Configure a VirtIO-based Random Number Generator.",
708 description
=> 'Specify a custom file containing all meta data passed to the VM via"
709 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
710 format
=> 'pve-volume-id',
711 format_description
=> 'volume',
716 description
=> 'Specify a custom file containing all network data passed to the VM via'
718 format
=> 'pve-volume-id',
719 format_description
=> 'volume',
724 description
=> 'Specify a custom file containing all user data passed to the VM via'
726 format
=> 'pve-volume-id',
727 format_description
=> 'volume',
730 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
732 my $confdesc_cloudinit = {
736 description
=> 'Specifies the cloud-init configuration format. The default depends on the'
737 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
738 .' and `configdrive2` for windows.',
739 enum
=> ['configdrive2', 'nocloud', 'opennebula'],
744 description
=> "cloud-init: User name to change ssh keys and password for instead of the"
745 ." image's configured default user.",
750 description
=> 'cloud-init: Password to assign the user. Using this is generally not'
751 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
752 .' support hashed passwords.',
757 description
=> 'cloud-init: Specify custom files to replace the automatically generated'
759 format
=> 'pve-qm-cicustom',
764 description
=> "cloud-init: Sets DNS search domains for a container. Create will'
765 .' automatically use the setting from the host if neither searchdomain nor nameserver'
770 type
=> 'string', format
=> 'address-list',
771 description
=> "cloud-init: Sets DNS server IP address for a container. Create will'
772 .' automatically use the setting from the host if neither searchdomain nor nameserver'
778 format
=> 'urlencoded',
779 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
783 # what about other qemu settings ?
785 #machine => 'string',
798 ##soundhw => 'string',
800 while (my ($k, $v) = each %$confdesc) {
801 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
804 my $MAX_USB_DEVICES = 5;
806 my $MAX_SERIAL_PORTS = 4;
807 my $MAX_PARALLEL_PORTS = 3;
813 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
814 description
=> "CPUs accessing this NUMA node.",
815 format_description
=> "id[-id];...",
819 description
=> "Amount of memory this NUMA node provides.",
824 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
825 description
=> "Host NUMA nodes to use.",
826 format_description
=> "id[-id];...",
831 enum
=> [qw(preferred bind interleave)],
832 description
=> "NUMA allocation policy.",
836 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
839 type
=> 'string', format
=> $numa_fmt,
840 description
=> "NUMA topology.",
842 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
844 for (my $i = 0; $i < $MAX_NUMA; $i++) {
845 $confdesc->{"numa$i"} = $numadesc;
848 my $nic_model_list = [
864 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
866 my $net_fmt_bridge_descr = <<__EOD__;
867 Bridge to attach the network device to. The Proxmox VE standard bridge
870 If you do not specify a bridge, we create a kvm user (NATed) network
871 device, which provides DHCP and DNS services. The following addresses
878 The DHCP server assign addresses to the guest starting from 10.0.2.15.
882 macaddr
=> get_standard_option
('mac-addr', {
883 description
=> "MAC address. That address must be unique withing your network. This is"
884 ." automatically generated if not specified.",
888 description
=> "Network Card Model. The 'virtio' model provides the best performance with"
889 ." very low CPU overhead. If your guest does not support this driver, it is usually"
890 ." best to use 'e1000'.",
891 enum
=> $nic_model_list,
894 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
897 description
=> $net_fmt_bridge_descr,
898 format_description
=> 'bridge',
899 pattern
=> '[-_.\w\d]+',
904 minimum
=> 0, maximum
=> 16,
905 description
=> 'Number of packet queues to be used on the device.',
911 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
916 minimum
=> 1, maximum
=> 4094,
917 description
=> 'VLAN tag to apply to packets on this interface.',
922 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
923 description
=> 'VLAN trunks to pass through this interface.',
924 format_description
=> 'vlanid[;vlanid...]',
929 description
=> 'Whether this interface should be protected by the firewall.',
934 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
939 minimum
=> 1, maximum
=> 65520,
940 description
=> "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
947 type
=> 'string', format
=> $net_fmt,
948 description
=> "Specify network devices.",
951 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
956 format
=> 'pve-ipv4-config',
957 format_description
=> 'IPv4Format/CIDR',
958 description
=> 'IPv4 address in CIDR format.',
965 format_description
=> 'GatewayIPv4',
966 description
=> 'Default gateway for IPv4 traffic.',
972 format
=> 'pve-ipv6-config',
973 format_description
=> 'IPv6Format/CIDR',
974 description
=> 'IPv6 address in CIDR format.',
981 format_description
=> 'GatewayIPv6',
982 description
=> 'Default gateway for IPv6 traffic.',
987 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
990 type
=> 'string', format
=> 'pve-qm-ipconfig',
991 description
=> <<'EODESCR',
992 cloud-init: Specify IP addresses and gateways for the corresponding interface.
994 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
996 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
997 gateway should be provided.
998 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
999 cloud-init 19.4 or newer.
1001 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
1005 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
1007 for (my $i = 0; $i < $MAX_NETS; $i++) {
1008 $confdesc->{"net$i"} = $netdesc;
1009 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
1012 foreach my $key (keys %$confdesc_cloudinit) {
1013 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1016 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
1017 sub verify_volume_id_or_qm_path
{
1018 my ($volid, $noerr) = @_;
1020 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
1024 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
1025 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
1036 type
=> 'string', format
=> 'pve-qm-usb-device',
1037 format_description
=> 'HOSTUSBDEVICE|spice',
1038 description
=> <<EODESCR,
1039 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1041 'bus-port(.port)*' (decimal numbers) or
1042 'vendor_id:product_id' (hexadeciaml numbers) or
1045 You can use the 'lsusb -t' command to list existing usb devices.
1047 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1048 machines - use with special care.
1050 The value 'spice' can be used to add a usb redirection devices for spice.
1056 description
=> "Specifies whether if given host option is a USB3 device or port.",
1063 type
=> 'string', format
=> $usb_fmt,
1064 description
=> "Configure an USB device (n is 0 to 4).",
1066 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1071 pattern
=> '(/dev/.+|socket)',
1072 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1073 verbose_description
=> <<EODESCR,
1074 Create a serial device inside the VM (n is 0 to 3), and pass through a
1075 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1076 host side (use 'qm terminal' to open a terminal connection).
1078 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1079 use with special care.
1081 CAUTION: Experimental! User reported problems with this option.
1088 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1089 description
=> "Map host parallel devices (n is 0 to 2).",
1090 verbose_description
=> <<EODESCR,
1091 Map host parallel devices (n is 0 to 2).
1093 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1094 machines - use with special care.
1096 CAUTION: Experimental! User reported problems with this option.
1100 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1101 $confdesc->{"parallel$i"} = $paralleldesc;
1104 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1105 $confdesc->{"serial$i"} = $serialdesc;
1108 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
1109 $confdesc->{"hostpci$i"} = $PVE::QemuServer
::PCI
::hostpcidesc
;
1112 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1113 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1116 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1117 $confdesc->{"usb$i"} = $usbdesc;
1125 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1126 . " Deprecated, use 'order=' instead.",
1127 pattern
=> '[acdn]{1,4}',
1128 format_description
=> "[acdn]{1,4}",
1130 # note: this is also the fallback if boot: is not given at all
1136 format
=> 'pve-qm-bootdev-list',
1137 format_description
=> "device[;device...]",
1138 description
=> <<EODESC,
1139 The guest will attempt to boot from devices in the order they appear here.
1141 Disks, optical drives and passed-through storage USB devices will be directly
1142 booted from, NICs will load PXE, and PCIe devices will either behave like disks
1143 (e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1145 Note that only devices in this list will be marked as bootable and thus loaded
1146 by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1147 (e.g. software-raid), you need to specify all of them here.
1149 Overrides the deprecated 'legacy=[acdn]*' value when given.
1153 PVE
::JSONSchema
::register_format
('pve-qm-boot', $boot_fmt);
1155 PVE
::JSONSchema
::register_format
('pve-qm-bootdev', \
&verify_bootdev
);
1156 sub verify_bootdev
{
1157 my ($dev, $noerr) = @_;
1159 my $special = $dev =~ m/^efidisk/ || $dev =~ m/^tpmstate/;
1160 return $dev if PVE
::QemuServer
::Drive
::is_valid_drivename
($dev) && !$special;
1164 return 0 if $dev !~ m/^$base\d+$/;
1165 return 0 if !$confdesc->{$dev};
1169 return $dev if $check->("net");
1170 return $dev if $check->("usb");
1171 return $dev if $check->("hostpci");
1174 die "invalid boot device '$dev'\n";
1177 sub print_bootorder
{
1179 return "" if !@$devs;
1180 my $data = { order
=> join(';', @$devs) };
1181 return PVE
::JSONSchema
::print_property_string
($data, $boot_fmt);
1184 my $kvm_api_version = 0;
1187 return $kvm_api_version if $kvm_api_version;
1189 open my $fh, '<', '/dev/kvm' or return;
1191 # 0xae00 => KVM_GET_API_VERSION
1192 $kvm_api_version = ioctl($fh, 0xae00, 0);
1195 return $kvm_api_version;
1198 my $kvm_user_version = {};
1201 sub kvm_user_version
{
1204 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1205 my $st = stat($binary);
1207 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1208 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1209 $cachedmtime == $st->mtime;
1211 $kvm_user_version->{$binary} = 'unknown';
1212 $kvm_mtime->{$binary} = $st->mtime;
1216 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1217 $kvm_user_version->{$binary} = $2;
1221 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1224 return $kvm_user_version->{$binary};
1227 my sub extract_version
{
1228 my ($machine_type, $version) = @_;
1229 $version = kvm_user_version
() if !defined($version);
1230 PVE
::QemuServer
::Machine
::extract_version
($machine_type, $version)
1233 sub kernel_has_vhost_net
{
1234 return -c
'/dev/vhost-net';
1239 return defined($confdesc->{$key});
1243 sub get_cdrom_path
{
1245 return $cdrom_path if $cdrom_path;
1247 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1248 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1249 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1253 my ($storecfg, $vmid, $cdrom) = @_;
1255 if ($cdrom eq 'cdrom') {
1256 return get_cdrom_path
();
1257 } elsif ($cdrom eq 'none') {
1259 } elsif ($cdrom =~ m
|^/|) {
1262 return PVE
::Storage
::path
($storecfg, $cdrom);
1266 # try to convert old style file names to volume IDs
1267 sub filename_to_volume_id
{
1268 my ($vmid, $file, $media) = @_;
1270 if (!($file eq 'none' || $file eq 'cdrom' ||
1271 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1273 return if $file =~ m
|/|;
1275 if ($media && $media eq 'cdrom') {
1276 $file = "local:iso/$file";
1278 $file = "local:$vmid/$file";
1285 sub verify_media_type
{
1286 my ($opt, $vtype, $media) = @_;
1291 if ($media eq 'disk') {
1293 } elsif ($media eq 'cdrom') {
1296 die "internal error";
1299 return if ($vtype eq $etype);
1301 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1304 sub cleanup_drive_path
{
1305 my ($opt, $storecfg, $drive) = @_;
1307 # try to convert filesystem paths to volume IDs
1309 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1310 ($drive->{file
} !~ m
|^/dev/.+|) &&
1311 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1312 ($drive->{file
} !~ m/^\d+$/)) {
1313 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1314 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1316 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1317 verify_media_type
($opt, $vtype, $drive->{media
});
1318 $drive->{file
} = $volid;
1321 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1324 sub parse_hotplug_features
{
1329 return $res if $data eq '0';
1331 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1333 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1334 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1337 die "invalid hotplug feature '$feature'\n";
1343 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1344 sub pve_verify_hotplug_features
{
1345 my ($value, $noerr) = @_;
1347 return $value if parse_hotplug_features
($value);
1351 die "unable to parse hotplug option\n";
1355 my($fh, $noerr) = @_;
1358 my $SG_GET_VERSION_NUM = 0x2282;
1360 my $versionbuf = "\x00" x
8;
1361 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1363 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1366 my $version = unpack("I", $versionbuf);
1367 if ($version < 30000) {
1368 die "scsi generic interface too old\n" if !$noerr;
1372 my $buf = "\x00" x
36;
1373 my $sensebuf = "\x00" x
8;
1374 my $cmd = pack("C x3 C x1", 0x12, 36);
1376 # see /usr/include/scsi/sg.h
1377 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";
1379 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1380 length($sensebuf), 0, length($buf), $buf,
1381 $cmd, $sensebuf, 6000);
1383 $ret = ioctl($fh, $SG_IO, $packet);
1385 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1389 my @res = unpack($sg_io_hdr_t, $packet);
1390 if ($res[17] || $res[18]) {
1391 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1396 (my $byte0, my $byte1, $res->{vendor
},
1397 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1399 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1400 $res->{type
} = $byte0 & 31;
1408 my $fh = IO
::File-
>new("+<$path") || return;
1409 my $res = scsi_inquiry
($fh, 1);
1415 sub print_tabletdevice_full
{
1416 my ($conf, $arch) = @_;
1418 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1420 # we use uhci for old VMs because tablet driver was buggy in older qemu
1422 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1428 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1431 sub print_keyboarddevice_full
{
1432 my ($conf, $arch, $machine) = @_;
1434 return if $arch ne 'aarch64';
1436 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1439 my sub get_drive_id
{
1441 return "$drive->{interface}$drive->{index}";
1444 sub print_drivedevice_full
{
1445 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1450 my $drive_id = get_drive_id
($drive);
1451 if ($drive->{interface
} eq 'virtio') {
1452 my $pciaddr = print_pci_addr
("$drive_id", $bridges, $arch, $machine_type);
1453 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1454 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread
};
1455 } elsif ($drive->{interface
} eq 'scsi') {
1457 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1458 my $unit = $drive->{index} % $maxdev;
1459 my $devicetype = 'hd';
1461 if (drive_is_cdrom
($drive)) {
1464 if ($drive->{file
} =~ m
|^/|) {
1465 $path = $drive->{file
};
1466 if (my $info = path_is_scsi
($path)) {
1467 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1468 $devicetype = 'block';
1469 } elsif ($info->{type
} == 1) { # tape
1470 $devicetype = 'generic';
1474 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1477 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1478 my $version = extract_version
($machine_type, kvm_user_version
());
1479 if ($path =~ m/^iscsi\:\/\
// &&
1480 !min_version
($version, 4, 1)) {
1481 $devicetype = 'generic';
1485 if (!$conf->{scsihw
} || $conf->{scsihw
} =~ m/^lsi/ || $conf->{scsihw
} eq 'pvscsi') {
1486 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
1488 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1489 .",lun=$drive->{index}";
1491 $device .= ",drive=drive-$drive_id,id=$drive_id";
1493 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1494 $device .= ",rotation_rate=1";
1496 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1498 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1499 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1500 my $controller = int($drive->{index} / $maxdev);
1501 my $unit = $drive->{index} % $maxdev;
1502 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1504 $device = "ide-$devicetype";
1505 if ($drive->{interface
} eq 'ide') {
1506 $device .= ",bus=ide.$controller,unit=$unit";
1508 $device .= ",bus=ahci$controller.$unit";
1510 $device .= ",drive=drive-$drive_id,id=$drive_id";
1512 if ($devicetype eq 'hd') {
1513 if (my $model = $drive->{model
}) {
1514 $model = URI
::Escape
::uri_unescape
($model);
1515 $device .= ",model=$model";
1517 if ($drive->{ssd
}) {
1518 $device .= ",rotation_rate=1";
1521 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1522 } elsif ($drive->{interface
} eq 'usb') {
1524 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1526 die "unsupported interface type";
1529 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1531 if (my $serial = $drive->{serial
}) {
1532 $serial = URI
::Escape
::uri_unescape
($serial);
1533 $device .= ",serial=$serial";
1540 sub get_initiator_name
{
1543 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return;
1544 while (defined(my $line = <$fh>)) {
1545 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1554 sub print_drive_commandline_full
{
1555 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1558 my $volid = $drive->{file
};
1559 my $format = $drive->{format
};
1560 my $drive_id = get_drive_id
($drive);
1562 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1563 my $scfg = $storeid ? PVE
::Storage
::storage_config
($storecfg, $storeid) : undef;
1565 if (drive_is_cdrom
($drive)) {
1566 $path = get_iso_path
($storecfg, $vmid, $volid);
1567 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
1570 $path = PVE
::Storage
::path
($storecfg, $volid);
1571 $format //= qemu_img_format
($scfg, $volname);
1578 my $is_rbd = $path =~ m/^rbd:/;
1581 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1582 foreach my $o (@qemu_drive_options) {
1583 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1586 # snapshot only accepts on|off
1587 if (defined($drive->{snapshot
})) {
1588 my $v = $drive->{snapshot
} ?
'on' : 'off';
1589 $opts .= ",snapshot=$v";
1592 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1593 my ($dir, $qmpname) = @$type;
1594 if (my $v = $drive->{"mbps$dir"}) {
1595 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1597 if (my $v = $drive->{"mbps${dir}_max"}) {
1598 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1600 if (my $v = $drive->{"bps${dir}_max_length"}) {
1601 $opts .= ",throttling.bps$qmpname-max-length=$v";
1603 if (my $v = $drive->{"iops${dir}"}) {
1604 $opts .= ",throttling.iops$qmpname=$v";
1606 if (my $v = $drive->{"iops${dir}_max"}) {
1607 $opts .= ",throttling.iops$qmpname-max=$v";
1609 if (my $v = $drive->{"iops${dir}_max_length"}) {
1610 $opts .= ",throttling.iops$qmpname-max-length=$v";
1615 $format = "rbd" if $is_rbd;
1616 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1618 $opts .= ",format=alloc-track,file.driver=$format";
1620 $opts .= ",format=$format";
1623 my $cache_direct = 0;
1625 if (my $cache = $drive->{cache
}) {
1626 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1627 } elsif (!drive_is_cdrom
($drive) && !($scfg && $scfg->{type
} eq 'btrfs' && !$scfg->{nocow
})) {
1628 $opts .= ",cache=none";
1632 # io_uring with cache mode writeback or writethrough on krbd will hang...
1633 my $rbd_no_io_uring = $scfg && $scfg->{type
} eq 'rbd' && $scfg->{krbd
} && !$cache_direct;
1635 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1636 # sometimes, just plain disable...
1637 my $lvm_no_io_uring = $scfg && $scfg->{type
} eq 'lvm';
1639 if (!$drive->{aio
}) {
1640 if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring) {
1641 # io_uring supports all cache modes
1642 $opts .= ",aio=io_uring";
1644 # aio native works only with O_DIRECT
1646 $opts .= ",aio=native";
1648 $opts .= ",aio=threads";
1653 if (!drive_is_cdrom
($drive)) {
1655 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1656 $detectzeroes = 'off';
1657 } elsif ($drive->{discard
}) {
1658 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1660 # This used to be our default with discard not being specified:
1661 $detectzeroes = 'on';
1664 # note: 'detect-zeroes' works per blockdev and we want it to persist
1665 # after the alloc-track is removed, so put it on 'file' directly
1666 my $dz_param = $pbs_name ?
"file.detect-zeroes" : "detect-zeroes";
1667 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
1671 $opts .= ",backing=$pbs_name";
1672 $opts .= ",auto-remove=on";
1675 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1676 my $file_param = "file";
1678 # non-rbd drivers require the underlying file to be a seperate block
1679 # node, so add a second .file indirection
1680 $file_param .= ".file" if !$is_rbd;
1681 $file_param .= ".filename";
1683 my $pathinfo = $path ?
"$file_param=$path," : '';
1685 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1688 sub print_pbs_blockdev
{
1689 my ($pbs_conf, $pbs_name) = @_;
1690 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1691 $blockdev .= ",repository=$pbs_conf->{repository}";
1692 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1693 $blockdev .= ",archive=$pbs_conf->{archive}";
1694 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile
};
1698 sub print_netdevice_full
{
1699 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1701 my $device = $net->{model
};
1702 if ($net->{model
} eq 'virtio') {
1703 $device = 'virtio-net-pci';
1706 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1707 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1708 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1709 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1710 # and out of each queue plus one config interrupt and control vector queue
1711 my $vectors = $net->{queues
} * 2 + 2;
1712 $tmpstr .= ",vectors=$vectors,mq=on";
1714 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1716 if (my $mtu = $net->{mtu
}) {
1717 if ($net->{model
} eq 'virtio' && $net->{bridge
}) {
1718 my $bridge_mtu = PVE
::Network
::read_bridge_mtu
($net->{bridge
});
1721 } elsif ($mtu < 576) {
1722 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1723 } elsif ($mtu > $bridge_mtu) {
1724 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1726 $tmpstr .= ",host_mtu=$mtu";
1728 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
1732 if ($use_old_bios_files) {
1734 if ($device eq 'virtio-net-pci') {
1735 $romfile = 'pxe-virtio.rom';
1736 } elsif ($device eq 'e1000') {
1737 $romfile = 'pxe-e1000.rom';
1738 } elsif ($device eq 'e1000e') {
1739 $romfile = 'pxe-e1000e.rom';
1740 } elsif ($device eq 'ne2k') {
1741 $romfile = 'pxe-ne2k_pci.rom';
1742 } elsif ($device eq 'pcnet') {
1743 $romfile = 'pxe-pcnet.rom';
1744 } elsif ($device eq 'rtl8139') {
1745 $romfile = 'pxe-rtl8139.rom';
1747 $tmpstr .= ",romfile=$romfile" if $romfile;
1753 sub print_netdev_full
{
1754 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1757 if ($netid =~ m/^net(\d+)$/) {
1761 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1763 my $ifname = "tap${vmid}i$i";
1765 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1766 die "interface name '$ifname' is too long (max 15 character)\n"
1767 if length($ifname) >= 16;
1769 my $vhostparam = '';
1770 if (is_native
($arch)) {
1771 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1774 my $vmname = $conf->{name
} || "vm$vmid";
1777 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1779 if ($net->{bridge
}) {
1780 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1781 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1783 $netdev = "type=user,id=$netid,hostname=$vmname";
1786 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1792 'cirrus' => 'cirrus-vga',
1794 'vmware' => 'vmware-svga',
1795 'virtio' => 'virtio-vga',
1798 sub print_vga_device
{
1799 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1801 my $type = $vga_map->{$vga->{type
}};
1802 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1803 $type = 'virtio-gpu';
1805 my $vgamem_mb = $vga->{memory
};
1807 my $max_outputs = '';
1809 $type = $id ?
'qxl' : 'qxl-vga';
1811 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1812 # set max outputs so linux can have up to 4 qxl displays with one device
1813 if (min_version
($machine_version, 4, 1)) {
1814 $max_outputs = ",max_outputs=4";
1819 die "no devicetype for $vga->{type}\n" if !$type;
1823 if ($vga->{type
} eq 'virtio') {
1824 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1825 $memory = ",max_hostmem=$bytes";
1827 # from https://www.spice-space.org/multiple-monitors.html
1828 $memory = ",vgamem_mb=$vga->{memory}";
1829 my $ram = $vgamem_mb * 4;
1830 my $vram = $vgamem_mb * 2;
1831 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1833 $memory = ",vgamem_mb=$vga->{memory}";
1835 } elsif ($qxlnum && $id) {
1836 $memory = ",ram_size=67108864,vram_size=33554432";
1840 if ($type eq 'VGA' && windows_version
($conf->{ostype
})) {
1841 $edidoff=",edid=off" if (!defined($conf->{bios
}) || $conf->{bios
} ne 'ovmf');
1844 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1845 my $vgaid = "vga" . ($id // '');
1848 if ($q35 && $vgaid eq 'vga') {
1849 # the first display uses pcie.0 bus on q35 machines
1850 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1852 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1855 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
1858 sub parse_number_sets
{
1861 foreach my $part (split(/;/, $set)) {
1862 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1863 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1864 push @$res, [ $1, $2 ];
1866 die "invalid range: $part\n";
1875 my $res = parse_property_string
($numa_fmt, $data);
1876 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1877 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1881 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1885 my $res = eval { parse_property_string
($net_fmt, $data) };
1890 if (!defined($res->{macaddr
})) {
1891 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1892 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1897 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1898 sub parse_ipconfig
{
1901 my $res = eval { parse_property_string
($ipconfig_fmt, $data) };
1907 if ($res->{gw
} && !$res->{ip
}) {
1908 warn 'gateway specified without specifying an IP address';
1911 if ($res->{gw6
} && !$res->{ip6
}) {
1912 warn 'IPv6 gateway specified without specifying an IPv6 address';
1915 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1916 warn 'gateway specified together with DHCP';
1919 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1921 warn "IPv6 gateway specified together with $res->{ip6} address";
1925 if (!$res->{ip
} && !$res->{ip6
}) {
1926 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1935 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1938 sub add_random_macs
{
1939 my ($settings) = @_;
1941 foreach my $opt (keys %$settings) {
1942 next if $opt !~ m/^net(\d+)$/;
1943 my $net = parse_net
($settings->{$opt});
1945 $settings->{$opt} = print_net
($net);
1949 sub vm_is_volid_owner
{
1950 my ($storecfg, $vmid, $volid) = @_;
1952 if ($volid !~ m
|^/|) {
1954 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1955 if ($owner && ($owner == $vmid)) {
1963 sub vmconfig_register_unused_drive
{
1964 my ($storecfg, $vmid, $conf, $drive) = @_;
1966 if (drive_is_cloudinit
($drive)) {
1967 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1969 } elsif (!drive_is_cdrom
($drive)) {
1970 my $volid = $drive->{file
};
1971 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1972 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1977 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1981 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1982 format_description
=> 'UUID',
1983 description
=> "Set SMBIOS1 UUID.",
1988 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1989 format_description
=> 'Base64 encoded string',
1990 description
=> "Set SMBIOS1 version.",
1995 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1996 format_description
=> 'Base64 encoded string',
1997 description
=> "Set SMBIOS1 serial number.",
2002 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2003 format_description
=> 'Base64 encoded string',
2004 description
=> "Set SMBIOS1 manufacturer.",
2009 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2010 format_description
=> 'Base64 encoded string',
2011 description
=> "Set SMBIOS1 product ID.",
2016 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2017 format_description
=> 'Base64 encoded string',
2018 description
=> "Set SMBIOS1 SKU string.",
2023 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2024 format_description
=> 'Base64 encoded string',
2025 description
=> "Set SMBIOS1 family string.",
2030 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
2038 my $res = eval { parse_property_string
($smbios1_fmt, $data) };
2045 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2048 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2050 sub parse_watchdog
{
2055 my $res = eval { parse_property_string
($watchdog_fmt, $value) };
2060 sub parse_guest_agent
{
2063 return {} if !defined($conf->{agent
});
2065 my $res = eval { parse_property_string
($agent_fmt, $conf->{agent
}) };
2068 # if the agent is disabled ignore the other potentially set properties
2069 return {} if !$res->{enabled
};
2074 my ($conf, $key) = @_;
2075 return undef if !defined($conf->{agent
});
2077 my $agent = parse_guest_agent
($conf);
2078 return $agent->{$key};
2084 return {} if !$value;
2085 my $res = eval { parse_property_string
($vga_fmt, $value) };
2095 my $res = eval { parse_property_string
($rng_fmt, $value) };
2100 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2101 sub verify_usb_device
{
2102 my ($value, $noerr) = @_;
2104 return $value if parse_usb_device
($value);
2108 die "unable to parse usb device\n";
2111 # add JSON properties for create and set function
2112 sub json_config_properties
{
2115 foreach my $opt (keys %$confdesc) {
2116 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' ||
2117 $opt eq 'runningmachine' || $opt eq 'runningcpu';
2118 $prop->{$opt} = $confdesc->{$opt};
2124 # return copy of $confdesc_cloudinit to generate documentation
2125 sub cloudinit_config_properties
{
2127 return dclone
($confdesc_cloudinit);
2131 my ($key, $value) = @_;
2133 die "unknown setting '$key'\n" if !$confdesc->{$key};
2135 my $type = $confdesc->{$key}->{type
};
2137 if (!defined($value)) {
2138 die "got undefined value\n";
2141 if ($value =~ m/[\n\r]/) {
2142 die "property contains a line feed\n";
2145 if ($type eq 'boolean') {
2146 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2147 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2148 die "type check ('boolean') failed - got '$value'\n";
2149 } elsif ($type eq 'integer') {
2150 return int($1) if $value =~ m/^(\d+)$/;
2151 die "type check ('integer') failed - got '$value'\n";
2152 } elsif ($type eq 'number') {
2153 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2154 die "type check ('number') failed - got '$value'\n";
2155 } elsif ($type eq 'string') {
2156 if (my $fmt = $confdesc->{$key}->{format
}) {
2157 PVE
::JSONSchema
::check_format
($fmt, $value);
2160 $value =~ s/^\"(.*)\"$/$1/;
2163 die "internal error"
2168 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
2170 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2172 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2174 if ($conf->{template
}) {
2175 # check if any base image is still used by a linked clone
2176 PVE
::QemuConfig-
>foreach_volume_full($conf, { include_unused
=> 1 }, sub {
2177 my ($ds, $drive) = @_;
2178 return if drive_is_cdrom
($drive);
2180 my $volid = $drive->{file
};
2181 return if !$volid || $volid =~ m
|^/|;
2183 die "base volume '$volid' is still in use by linked cloned\n"
2184 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2190 my $remove_owned_drive = sub {
2191 my ($ds, $drive) = @_;
2192 return if drive_is_cdrom
($drive, 1);
2194 my $volid = $drive->{file
};
2195 return if !$volid || $volid =~ m
|^/|;
2196 return if $volids->{$volid};
2198 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2199 return if !$path || !$owner || ($owner != $vmid);
2201 $volids->{$volid} = 1;
2202 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2203 warn "Could not remove disk '$volid', check manually: $@" if $@;
2206 # only remove disks owned by this VM (referenced in the config)
2207 my $include_opts = {
2208 include_unused
=> 1,
2209 extra_keys
=> ['vmstate'],
2211 PVE
::QemuConfig-
>foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2213 for my $snap (values %{$conf->{snapshots
}}) {
2214 next if !defined($snap->{vmstate
});
2215 my $drive = PVE
::QemuConfig-
>parse_volume('vmstate', $snap->{vmstate
}, 1);
2216 next if !defined($drive);
2217 $remove_owned_drive->('vmstate', $drive);
2220 PVE
::QemuConfig-
>foreach_volume_full($conf->{pending
}, $include_opts, $remove_owned_drive);
2222 if ($purge_unreferenced) { # also remove unreferenced disk
2223 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid, undef, 'images');
2224 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2225 my ($volid, $sid, $volname, $d) = @_;
2226 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2231 if (defined $replacement_conf) {
2232 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2234 PVE
::QemuConfig-
>destroy_config($vmid);
2238 sub parse_vm_config
{
2239 my ($filename, $raw) = @_;
2241 return if !defined($raw);
2244 digest
=> Digest
::SHA
::sha1_hex
($raw),
2249 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2250 || die "got strange filename '$filename'";
2258 my @lines = split(/\n/, $raw);
2259 foreach my $line (@lines) {
2260 next if $line =~ m/^\s*$/;
2262 if ($line =~ m/^\[PENDING\]\s*$/i) {
2263 $section = 'pending';
2264 if (defined($descr)) {
2266 $conf->{description
} = $descr;
2269 $conf = $res->{$section} = {};
2272 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2274 if (defined($descr)) {
2276 $conf->{description
} = $descr;
2279 $conf = $res->{snapshots
}->{$section} = {};
2283 if ($line =~ m/^\#(.*)\s*$/) {
2284 $descr = '' if !defined($descr);
2285 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2289 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2290 $descr = '' if !defined($descr);
2291 $descr .= PVE
::Tools
::decode_text
($2);
2292 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2293 $conf->{snapstate
} = $1;
2294 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2297 $conf->{$key} = $value;
2298 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2300 if ($section eq 'pending') {
2301 $conf->{delete} = $value; # we parse this later
2303 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2305 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2308 eval { $value = check_type
($key, $value); };
2310 warn "vm $vmid - unable to parse value of '$key' - $@";
2312 $key = 'ide2' if $key eq 'cdrom';
2313 my $fmt = $confdesc->{$key}->{format
};
2314 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2315 my $v = parse_drive
($key, $value);
2316 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2317 $v->{file
} = $volid;
2318 $value = print_drive
($v);
2320 warn "vm $vmid - unable to parse value of '$key'\n";
2325 $conf->{$key} = $value;
2328 warn "vm $vmid - unable to parse config: $line\n";
2332 if (defined($descr)) {
2334 $conf->{description
} = $descr;
2336 delete $res->{snapstate
}; # just to be sure
2341 sub write_vm_config
{
2342 my ($filename, $conf) = @_;
2344 delete $conf->{snapstate
}; # just to be sure
2346 if ($conf->{cdrom
}) {
2347 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2348 $conf->{ide2
} = $conf->{cdrom
};
2349 delete $conf->{cdrom
};
2352 # we do not use 'smp' any longer
2353 if ($conf->{sockets
}) {
2354 delete $conf->{smp
};
2355 } elsif ($conf->{smp
}) {
2356 $conf->{sockets
} = $conf->{smp
};
2357 delete $conf->{cores
};
2358 delete $conf->{smp
};
2361 my $used_volids = {};
2363 my $cleanup_config = sub {
2364 my ($cref, $pending, $snapname) = @_;
2366 foreach my $key (keys %$cref) {
2367 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2368 $key eq 'snapstate' || $key eq 'pending';
2369 my $value = $cref->{$key};
2370 if ($key eq 'delete') {
2371 die "propertry 'delete' is only allowed in [PENDING]\n"
2373 # fixme: check syntax?
2376 eval { $value = check_type
($key, $value); };
2377 die "unable to parse value of '$key' - $@" if $@;
2379 $cref->{$key} = $value;
2381 if (!$snapname && is_valid_drivename
($key)) {
2382 my $drive = parse_drive
($key, $value);
2383 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2388 &$cleanup_config($conf);
2390 &$cleanup_config($conf->{pending
}, 1);
2392 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2393 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2394 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2397 # remove 'unusedX' settings if we re-add a volume
2398 foreach my $key (keys %$conf) {
2399 my $value = $conf->{$key};
2400 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2401 delete $conf->{$key};
2405 my $generate_raw_config = sub {
2406 my ($conf, $pending) = @_;
2410 # add description as comment to top of file
2411 if (defined(my $descr = $conf->{description
})) {
2413 foreach my $cl (split(/\n/, $descr)) {
2414 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2417 $raw .= "#\n" if $pending;
2421 foreach my $key (sort keys %$conf) {
2422 next if $key =~ /^(digest|description|pending|snapshots)$/;
2423 $raw .= "$key: $conf->{$key}\n";
2428 my $raw = &$generate_raw_config($conf);
2430 if (scalar(keys %{$conf->{pending
}})){
2431 $raw .= "\n[PENDING]\n";
2432 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2435 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2436 $raw .= "\n[$snapname]\n";
2437 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2447 # we use static defaults from our JSON schema configuration
2448 foreach my $key (keys %$confdesc) {
2449 if (defined(my $default = $confdesc->{$key}->{default})) {
2450 $res->{$key} = $default;
2458 my $vmlist = PVE
::Cluster
::get_vmlist
();
2460 return $res if !$vmlist || !$vmlist->{ids
};
2461 my $ids = $vmlist->{ids
};
2462 my $nodename = nodename
();
2464 foreach my $vmid (keys %$ids) {
2465 my $d = $ids->{$vmid};
2466 next if !$d->{node
} || $d->{node
} ne $nodename;
2467 next if !$d->{type
} || $d->{type
} ne 'qemu';
2468 $res->{$vmid}->{exists} = 1;
2473 # test if VM uses local resources (to prevent migration)
2474 sub check_local_resources
{
2475 my ($conf, $noerr) = @_;
2479 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2480 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2482 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2484 foreach my $k (keys %$conf) {
2485 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2486 # sockets are safe: they will recreated be on the target side post-migrate
2487 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2488 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2491 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2496 # check if used storages are available on all nodes (use by migrate)
2497 sub check_storage_availability
{
2498 my ($storecfg, $conf, $node) = @_;
2500 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2501 my ($ds, $drive) = @_;
2503 my $volid = $drive->{file
};
2506 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2509 # check if storage is available on both nodes
2510 my $scfg = PVE
::Storage
::storage_check_enabled
($storecfg, $sid);
2511 PVE
::Storage
::storage_check_enabled
($storecfg, $sid, $node);
2513 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $volid);
2515 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2516 if !$scfg->{content
}->{$vtype};
2520 # list nodes where all VM images are available (used by has_feature API)
2522 my ($conf, $storecfg) = @_;
2524 my $nodelist = PVE
::Cluster
::get_nodelist
();
2525 my $nodehash = { map { $_ => 1 } @$nodelist };
2526 my $nodename = nodename
();
2528 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2529 my ($ds, $drive) = @_;
2531 my $volid = $drive->{file
};
2534 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2536 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2537 if ($scfg->{disable
}) {
2539 } elsif (my $avail = $scfg->{nodes
}) {
2540 foreach my $node (keys %$nodehash) {
2541 delete $nodehash->{$node} if !$avail->{$node};
2543 } elsif (!$scfg->{shared
}) {
2544 foreach my $node (keys %$nodehash) {
2545 delete $nodehash->{$node} if $node ne $nodename
2554 sub check_local_storage_availability
{
2555 my ($conf, $storecfg) = @_;
2557 my $nodelist = PVE
::Cluster
::get_nodelist
();
2558 my $nodehash = { map { $_ => {} } @$nodelist };
2560 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2561 my ($ds, $drive) = @_;
2563 my $volid = $drive->{file
};
2566 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2568 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2570 if ($scfg->{disable
}) {
2571 foreach my $node (keys %$nodehash) {
2572 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2574 } elsif (my $avail = $scfg->{nodes
}) {
2575 foreach my $node (keys %$nodehash) {
2576 if (!$avail->{$node}) {
2577 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2584 foreach my $node (values %$nodehash) {
2585 if (my $unavail = $node->{unavailable_storages
}) {
2586 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2593 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2595 my ($vmid, $nocheck, $node) = @_;
2597 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2598 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2603 my $vzlist = config_list
();
2605 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2607 while (defined(my $de = $fd->read)) {
2608 next if $de !~ m/^(\d+)\.pid$/;
2610 next if !defined($vzlist->{$vmid});
2611 if (my $pid = check_running
($vmid)) {
2612 $vzlist->{$vmid}->{pid
} = $pid;
2619 our $vmstatus_return_properties = {
2620 vmid
=> get_standard_option
('pve-vmid'),
2622 description
=> "Qemu process status.",
2624 enum
=> ['stopped', 'running'],
2627 description
=> "Maximum memory in bytes.",
2630 renderer
=> 'bytes',
2633 description
=> "Root disk size in bytes.",
2636 renderer
=> 'bytes',
2639 description
=> "VM name.",
2644 description
=> "Qemu QMP agent status.",
2649 description
=> "PID of running qemu process.",
2654 description
=> "Uptime.",
2657 renderer
=> 'duration',
2660 description
=> "Maximum usable CPUs.",
2665 description
=> "The current config lock, if any.",
2670 description
=> "The current configured tags, if any",
2674 'running-machine' => {
2675 description
=> "The currently running machine type (if running).",
2680 description
=> "The currently running QEMU version (if running).",
2686 my $last_proc_pid_stat;
2688 # get VM status information
2689 # This must be fast and should not block ($full == false)
2690 # We only query KVM using QMP if $full == true (this can be slow)
2692 my ($opt_vmid, $full) = @_;
2696 my $storecfg = PVE
::Storage
::config
();
2698 my $list = vzlist
();
2699 my $defaults = load_defaults
();
2701 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2703 my $cpucount = $cpuinfo->{cpus
} || 1;
2705 foreach my $vmid (keys %$list) {
2706 next if $opt_vmid && ($vmid ne $opt_vmid);
2708 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2710 my $d = { vmid
=> int($vmid) };
2711 $d->{pid
} = int($list->{$vmid}->{pid
}) if $list->{$vmid}->{pid
};
2713 # fixme: better status?
2714 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2716 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2717 if (defined($size)) {
2718 $d->{disk
} = 0; # no info available
2719 $d->{maxdisk
} = $size;
2725 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2726 * ($conf->{cores
} || $defaults->{cores
});
2727 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2728 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2730 $d->{name
} = $conf->{name
} || "VM $vmid";
2731 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2732 : $defaults->{memory
}*(1024*1024);
2734 if ($conf->{balloon
}) {
2735 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2736 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2737 : $defaults->{shares
};
2748 $d->{diskwrite
} = 0;
2750 $d->{template
} = 1 if PVE
::QemuConfig-
>is_template($conf);
2752 $d->{serial
} = 1 if conf_has_serial
($conf);
2753 $d->{lock} = $conf->{lock} if $conf->{lock};
2754 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2759 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2760 foreach my $dev (keys %$netdev) {
2761 next if $dev !~ m/^tap([1-9]\d*)i/;
2763 my $d = $res->{$vmid};
2766 $d->{netout
} += $netdev->{$dev}->{receive
};
2767 $d->{netin
} += $netdev->{$dev}->{transmit
};
2770 $d->{nics
}->{$dev}->{netout
} = int($netdev->{$dev}->{receive
});
2771 $d->{nics
}->{$dev}->{netin
} = int($netdev->{$dev}->{transmit
});
2776 my $ctime = gettimeofday
;
2778 foreach my $vmid (keys %$list) {
2780 my $d = $res->{$vmid};
2781 my $pid = $d->{pid
};
2784 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2785 next if !$pstat; # not running
2787 my $used = $pstat->{utime} + $pstat->{stime
};
2789 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2791 if ($pstat->{vsize
}) {
2792 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2795 my $old = $last_proc_pid_stat->{$pid};
2797 $last_proc_pid_stat->{$pid} = {
2805 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2807 if ($dtime > 1000) {
2808 my $dutime = $used - $old->{used
};
2810 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2811 $last_proc_pid_stat->{$pid} = {
2817 $d->{cpu
} = $old->{cpu
};
2821 return $res if !$full;
2823 my $qmpclient = PVE
::QMPClient-
>new();
2825 my $ballooncb = sub {
2826 my ($vmid, $resp) = @_;
2828 my $info = $resp->{'return'};
2829 return if !$info->{max_mem
};
2831 my $d = $res->{$vmid};
2833 # use memory assigned to VM
2834 $d->{maxmem
} = $info->{max_mem
};
2835 $d->{balloon
} = $info->{actual
};
2837 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2838 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2839 $d->{freemem
} = $info->{free_mem
};
2842 $d->{ballooninfo
} = $info;
2845 my $blockstatscb = sub {
2846 my ($vmid, $resp) = @_;
2847 my $data = $resp->{'return'} || [];
2848 my $totalrdbytes = 0;
2849 my $totalwrbytes = 0;
2851 for my $blockstat (@$data) {
2852 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2853 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2855 $blockstat->{device
} =~ s/drive-//;
2856 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2858 $res->{$vmid}->{diskread
} = $totalrdbytes;
2859 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2862 my $machinecb = sub {
2863 my ($vmid, $resp) = @_;
2864 my $data = $resp->{'return'} || [];
2866 $res->{$vmid}->{'running-machine'} =
2867 PVE
::QemuServer
::Machine
::current_from_query_machines
($data);
2870 my $versioncb = sub {
2871 my ($vmid, $resp) = @_;
2872 my $data = $resp->{'return'} // {};
2873 my $version = 'unknown';
2875 if (my $v = $data->{qemu
}) {
2876 $version = $v->{major
} . "." . $v->{minor
} . "." . $v->{micro
};
2879 $res->{$vmid}->{'running-qemu'} = $version;
2882 my $statuscb = sub {
2883 my ($vmid, $resp) = @_;
2885 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2886 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
2887 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
2888 # this fails if ballon driver is not loaded, so this must be
2889 # the last commnand (following command are aborted if this fails).
2890 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2892 my $status = 'unknown';
2893 if (!defined($status = $resp->{'return'}->{status
})) {
2894 warn "unable to get VM status\n";
2898 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2901 foreach my $vmid (keys %$list) {
2902 next if $opt_vmid && ($vmid ne $opt_vmid);
2903 next if !$res->{$vmid}->{pid
}; # not running
2904 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2907 $qmpclient->queue_execute(undef, 2);
2909 foreach my $vmid (keys %$list) {
2910 next if $opt_vmid && ($vmid ne $opt_vmid);
2911 next if !$res->{$vmid}->{pid
}; #not running
2913 # we can't use the $qmpclient since it might have already aborted on
2914 # 'query-balloon', but this might also fail for older versions...
2915 my $qemu_support = eval { mon_cmd
($vmid, "query-proxmox-support") };
2916 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
2919 foreach my $vmid (keys %$list) {
2920 next if $opt_vmid && ($vmid ne $opt_vmid);
2921 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2927 sub conf_has_serial
{
2930 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2931 if ($conf->{"serial$i"}) {
2939 sub conf_has_audio
{
2940 my ($conf, $id) = @_;
2943 my $audio = $conf->{"audio$id"};
2944 return if !defined($audio);
2946 my $audioproperties = parse_property_string
($audio_fmt, $audio);
2947 my $audiodriver = $audioproperties->{driver
} // 'spice';
2950 dev
=> $audioproperties->{device
},
2951 dev_id
=> "audiodev$id",
2952 backend
=> $audiodriver,
2953 backend_id
=> "$audiodriver-backend${id}",
2958 my ($audio, $audiopciaddr, $machine_version) = @_;
2962 my $id = $audio->{dev_id
};
2964 if (min_version
($machine_version, 4, 2)) {
2965 $audiodev = ",audiodev=$audio->{backend_id}";
2968 if ($audio->{dev
} eq 'AC97') {
2969 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
2970 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
2971 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
2972 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
2973 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
2975 die "unkown audio device '$audio->{dev}', implement me!";
2978 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2986 socket => "/var/run/qemu-server/$vmid.swtpm",
2987 pid
=> "/var/run/qemu-server/$vmid.swtpm.pid",
2991 sub add_tpm_device
{
2992 my ($vmid, $devices, $conf) = @_;
2994 return if !$conf->{tpmstate0
};
2996 my $paths = get_tpm_paths
($vmid);
2998 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
2999 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
3000 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
3004 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
3006 return if !$tpmdrive;
3009 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
3010 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
3012 $state = PVE
::Storage
::map_volume
($storecfg, $tpm->{file
});
3014 $state = $tpm->{file
};
3017 my $paths = get_tpm_paths
($vmid);
3019 # during migration, we will get state from remote
3022 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3029 "--create-platform-cert",
3032 "/etc/swtpm_setup.conf", # do not use XDG configs
3034 "0", # force creation as root, error if not possible
3035 "--not-overwrite", # ignore existing state, do not modify
3038 push @$setup_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3039 # TPM 2.0 supports ECC crypto, use if possible
3040 push @$setup_cmd, "--ecc" if $tpm->{version
} eq 'v2.0';
3042 run_command
($setup_cmd, outfunc
=> sub {
3043 print "swtpm_setup: $1\n";
3047 my $emulator_cmd = [
3051 "backend-uri=file://$state,mode=0600",
3053 "type=unixio,path=$paths->{socket},mode=0600",
3055 "file=$paths->{pid}",
3056 "--terminate", # terminate on QEMU disconnect
3059 push @$emulator_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3060 run_command
($emulator_cmd, outfunc
=> sub { print $1; });
3062 my $tries = 100; # swtpm may take a bit to start before daemonizing, wait up to 5s for pid
3063 while (! -e
$paths->{pid
}) {
3064 die "failed to start swtpm: pid file '$paths->{pid}' wasn't created.\n" if --$tries == 0;
3068 # return untainted PID of swtpm daemon so it can be killed on error
3069 file_read_firstline
($paths->{pid
}) =~ m/(\d+)/;
3073 sub vga_conf_has_spice
{
3076 my $vgaconf = parse_vga
($vga);
3077 my $vgatype = $vgaconf->{type
};
3078 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3085 return get_host_arch
() eq $arch;
3090 return $conf->{arch
} // get_host_arch
();
3093 my $default_machines = {
3098 sub get_installed_machine_version
{
3099 my ($kvmversion) = @_;
3100 $kvmversion = kvm_user_version
() if !defined($kvmversion);
3101 $kvmversion =~ m/^(\d+\.\d+)/;
3105 sub windows_get_pinned_machine_version
{
3106 my ($machine, $base_version, $kvmversion) = @_;
3108 my $pin_version = $base_version;
3109 if (!defined($base_version) ||
3110 !PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($base_version, $kvmversion)
3112 $pin_version = get_installed_machine_version
($kvmversion);
3114 if (!$machine || $machine eq 'pc') {
3115 $machine = "pc-i440fx-$pin_version";
3116 } elsif ($machine eq 'q35') {
3117 $machine = "pc-q35-$pin_version";
3118 } elsif ($machine eq 'virt') {
3119 $machine = "virt-$pin_version";
3121 warn "unknown machine type '$machine', not touching that!\n";
3127 sub get_vm_machine
{
3128 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
3130 my $machine = $forcemachine || $conf->{machine
};
3132 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
3133 $kvmversion //= kvm_user_version
();
3134 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3135 # layout which confuses windows quite a bit and may result in various regressions..
3136 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3137 if (windows_version
($conf->{ostype
})) {
3138 $machine = windows_get_pinned_machine_version
($machine, '5.1', $kvmversion);
3141 $machine ||= $default_machines->{$arch};
3142 if ($add_pve_version) {
3143 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
3144 $machine .= "+pve$pvever";
3148 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3149 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3150 $machine = $1 if $is_pxe;
3152 # for version-pinned machines that do not include a pve-version (e.g.
3153 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3154 $machine .= '+pve0';
3156 $machine .= '.pxe' if $is_pxe;
3162 sub get_ovmf_files
($$) {
3163 my ($arch, $efidisk) = @_;
3165 my $types = $OVMF->{$arch}
3166 or die "no OVMF images known for architecture '$arch'\n";
3168 my $type = 'default';
3169 if (defined($efidisk->{efitype
}) && $efidisk->{efitype
} eq '4m') {
3170 $type = $efidisk->{'pre-enrolled-keys'} ?
"4m-ms" : "4m";
3173 return $types->{$type}->@*;
3177 aarch64
=> '/usr/bin/qemu-system-aarch64',
3178 x86_64
=> '/usr/bin/qemu-system-x86_64',
3180 sub get_command_for_arch
($) {
3182 return '/usr/bin/kvm' if is_native
($arch);
3184 my $cmd = $Arch2Qemu->{$arch}
3185 or die "don't know how to emulate architecture '$arch'\n";
3189 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3190 # to use in a QEMU command line (-cpu element), first array_intersect the result
3191 # of query_supported_ with query_understood_. This is necessary because:
3193 # a) query_understood_ returns flags the host cannot use and
3194 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
3195 # flags, but CPU settings - with most of them being flags. Those settings
3196 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
3198 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3199 # expensive. If you need the value returned from this, you can get it much
3200 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3201 # $accel being 'kvm' or 'tcg'.
3203 # pvestatd calls this function on startup and whenever the QEMU/KVM version
3204 # changes, automatically populating pmxcfs.
3206 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3207 # since kvm and tcg machines support different flags
3209 sub query_supported_cpu_flags
{
3212 $arch //= get_host_arch
();
3213 my $default_machine = $default_machines->{$arch};
3217 # FIXME: Once this is merged, the code below should work for ARM as well:
3218 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3219 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3222 my $kvm_supported = defined(kvm_version
());
3223 my $qemu_cmd = get_command_for_arch
($arch);
3225 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
3227 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3228 my $query_supported_run_qemu = sub {
3234 '-machine', $default_machine,
3236 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
3237 '-mon', 'chardev=qmp,mode=control',
3238 '-pidfile', $pidfile,
3243 push @$cmd, '-accel', 'tcg';
3246 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
3247 die "QEMU flag querying VM exited with code " . $rc if $rc;
3250 my $cmd_result = mon_cmd
(
3252 'query-cpu-model-expansion',
3254 model
=> { name
=> 'host' }
3257 my $props = $cmd_result->{model
}->{props
};
3258 foreach my $prop (keys %$props) {
3259 next if $props->{$prop} ne '1';
3260 # QEMU returns some flags multiple times, with '_', '.' or '-'
3261 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3262 # We only keep those with underscores, to match /proc/cpuinfo
3263 $prop =~ s/\.|-/_/g;
3264 $flags->{$prop} = 1;
3269 # force stop with 10 sec timeout and 'nocheck', always stop, even if QMP failed
3270 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
3274 return [ sort keys %$flags ];
3277 # We need to query QEMU twice, since KVM and TCG have different supported flags
3278 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
3279 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
3280 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3282 if ($kvm_supported) {
3283 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
3284 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3291 # Understood CPU flags are written to a file at 'pve-qemu' compile time
3292 my $understood_cpu_flag_dir = "/usr/share/kvm";
3293 sub query_understood_cpu_flags
{
3294 my $arch = get_host_arch
();
3295 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3297 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3300 my $raw = file_get_contents
($filepath);
3301 $raw =~ s/^\s+|\s+$//g;
3302 my @flags = split(/\s+/, $raw);
3307 my sub get_cpuunits
{
3309 return $conf->{cpuunits
} // (PVE
::CGroup
::cgroup_mode
() == 2 ?
100 : 1024);
3311 sub config_to_command
{
3312 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3316 my $globalFlags = [];
3317 my $machineFlags = [];
3322 my $ostype = $conf->{ostype
};
3323 my $winversion = windows_version
($ostype);
3324 my $kvm = $conf->{kvm
};
3325 my $nodename = nodename
();
3327 my $arch = get_vm_arch
($conf);
3328 my $kvm_binary = get_command_for_arch
($arch);
3329 my $kvmver = kvm_user_version
($kvm_binary);
3331 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3332 $kvmver //= "undefined";
3333 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3336 my $add_pve_version = min_version
($kvmver, 4, 1);
3338 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
3339 my $machine_version = extract_version
($machine_type, $kvmver);
3340 $kvm //= 1 if is_native
($arch);
3342 $machine_version =~ m/(\d+)\.(\d+)/;
3343 my ($machine_major, $machine_minor) = ($1, $2);
3345 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3346 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3347 } elsif (!min_version
($kvmver, $machine_major, $machine_minor)) {
3348 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3349 ." please upgrade node '$nodename'\n"
3350 } elsif (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
3351 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
3352 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3353 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3354 ." node '$nodename'\n";
3357 # if a specific +pve version is required for a feature, use $version_guard
3358 # instead of min_version to allow machines to be run with the minimum
3360 my $required_pve_version = 0;
3361 my $version_guard = sub {
3362 my ($major, $minor, $pve) = @_;
3363 return 0 if !min_version
($machine_version, $major, $minor, $pve);
3364 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
3365 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
3366 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3370 if ($kvm && !defined kvm_version
()) {
3371 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3372 ." or enable in BIOS.\n";
3375 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3376 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3377 my $use_old_bios_files = undef;
3378 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3380 my $cpuunits = get_cpuunits
($conf);
3382 push @$cmd, $kvm_binary;
3384 push @$cmd, '-id', $vmid;
3386 my $vmname = $conf->{name
} || "vm$vmid";
3388 push @$cmd, '-name', $vmname;
3390 push @$cmd, '-no-shutdown';
3394 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3395 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
3396 push @$cmd, '-mon', "chardev=qmp,mode=control";
3398 if (min_version
($machine_version, 2, 12)) {
3399 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3400 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3403 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3405 push @$cmd, '-daemonize';
3407 if ($conf->{smbios1
}) {
3408 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3409 if ($smbios_conf->{base64
}) {
3410 # Do not pass base64 flag to qemu
3411 delete $smbios_conf->{base64
};
3412 my $smbios_string = "";
3413 foreach my $key (keys %$smbios_conf) {
3415 if ($key eq "uuid") {
3416 $value = $smbios_conf->{uuid
}
3418 $value = decode_base64
($smbios_conf->{$key});
3420 # qemu accepts any binary data, only commas need escaping by double comma
3422 $smbios_string .= "," . $key . "=" . $value if $value;
3424 push @$cmd, '-smbios', "type=1" . $smbios_string;
3426 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3430 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3432 if (my $efidisk = $conf->{efidisk0
}) {
3433 $d = parse_drive
('efidisk0', $efidisk);
3436 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch, $d);
3437 die "uefi base image '$ovmf_code' not found\n" if ! -f
$ovmf_code;
3439 my ($path, $format);
3440 my $read_only_str = '';
3442 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3443 $format = $d->{format
};
3445 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3446 if (!defined($format)) {
3447 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3448 $format = qemu_img_format
($scfg, $volname);
3452 die "efidisk format must be specified\n"
3453 if !defined($format);
3456 $read_only_str = ',readonly=on' if drive_is_read_only
($conf, $d);
3458 warn "no efidisk configured! Using temporary efivars disk.\n";
3459 $path = "/tmp/$vmid-ovmf.fd";
3460 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3466 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3467 $size_str = ",size=" . (-s
$ovmf_vars);
3470 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3472 if ($path =~ m/^rbd:/) {
3473 $cache = ',cache=writeback';
3474 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3477 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
3478 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
3481 if ($q35) { # tell QEMU to load q35 config early
3482 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3483 if (min_version
($machine_version, 4, 0)) {
3484 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3486 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3490 if ($conf->{vmgenid
}) {
3491 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3494 # add usb controllers
3495 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
(
3496 $conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3497 push @$devices, @usbcontrollers if @usbcontrollers;
3498 my $vga = parse_vga
($conf->{vga
});
3500 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3501 $vga->{type
} = 'qxl' if $qxlnum;
3503 if (!$vga->{type
}) {
3504 if ($arch eq 'aarch64') {
3505 $vga->{type
} = 'virtio';
3506 } elsif (min_version
($machine_version, 2, 9)) {
3507 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3509 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3513 # enable absolute mouse coordinates (needed by vnc)
3515 if (defined($conf->{tablet
})) {
3516 $tablet = $conf->{tablet
};
3518 $tablet = $defaults->{tablet
};
3519 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3520 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3524 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3525 my $kbd = print_keyboarddevice_full
($conf, $arch);
3526 push @$devices, '-device', $kbd if defined($kbd);
3529 my $bootorder = device_bootorder
($conf);
3531 # host pci device passthrough
3532 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE
::QemuServer
::PCI
::print_hostpci_devices
(
3533 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
3536 my $usb_dev_features = {};
3537 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3539 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
(
3540 $conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
3541 push @$devices, @usbdevices if @usbdevices;
3544 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3545 if (my $path = $conf->{"serial$i"}) {
3546 if ($path eq 'socket') {
3547 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3548 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3549 # On aarch64, serial0 is the UART device. Qemu only allows
3550 # connecting UART devices via the '-serial' command line, as
3551 # the device has a fixed slot on the hardware...
3552 if ($arch eq 'aarch64' && $i == 0) {
3553 push @$devices, '-serial', "chardev:serial$i";
3555 push @$devices, '-device', "isa-serial,chardev=serial$i";
3558 die "no such serial device\n" if ! -c
$path;
3559 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3560 push @$devices, '-device', "isa-serial,chardev=serial$i";
3566 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3567 if (my $path = $conf->{"parallel$i"}) {
3568 die "no such parallel device\n" if ! -c
$path;
3569 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3570 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3571 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3575 if (min_version
($machine_version, 4, 0) && (my $audio = conf_has_audio
($conf))) {
3576 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3577 my $audio_devs = audio_devs
($audio, $audiopciaddr, $machine_version);
3578 push @$devices, @$audio_devs;
3581 add_tpm_device
($vmid, $devices, $conf);
3584 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3585 $sockets = $conf->{sockets
} if $conf->{sockets
};
3587 my $cores = $conf->{cores
} || 1;
3589 my $maxcpus = $sockets * $cores;
3591 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3593 my $allowed_vcpus = $cpuinfo->{cpus
};
3595 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n" if ($allowed_vcpus < $maxcpus);
3597 if ($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3598 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3599 for (my $i = 2; $i <= $vcpus; $i++) {
3600 my $cpustr = print_cpu_device
($conf,$i);
3601 push @$cmd, '-device', $cpustr;
3606 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3608 push @$cmd, '-nodefaults';
3610 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3612 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3614 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3616 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3617 push @$devices, '-device', print_vga_device
(
3618 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3619 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3620 push @$cmd, '-vnc', "unix:$socket,password=on";
3622 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3623 push @$cmd, '-nographic';
3627 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3628 my $useLocaltime = $conf->{localtime};
3630 if ($winversion >= 5) { # windows
3631 $useLocaltime = 1 if !defined($conf->{localtime});
3633 # use time drift fix when acpi is enabled
3634 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3635 $tdf = 1 if !defined($conf->{tdf
});
3639 if ($winversion >= 6) {
3640 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3641 push @$cmd, '-no-hpet';
3644 push @$rtcFlags, 'driftfix=slew' if $tdf;
3646 if ($conf->{startdate
} && $conf->{startdate
} ne 'now') {
3647 push @$rtcFlags, "base=$conf->{startdate}";
3648 } elsif ($useLocaltime) {
3649 push @$rtcFlags, 'base=localtime';
3653 push @$cmd, '-cpu', $forcecpu;
3655 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3658 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3660 push @$cmd, '-S' if $conf->{freeze
};
3662 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3664 my $guest_agent = parse_guest_agent
($conf);
3666 if ($guest_agent->{enabled
}) {
3667 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3668 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
3670 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3671 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3672 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3673 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3674 } elsif ($guest_agent->{type
} eq 'isa') {
3675 push @$devices, '-device', "isa-serial,chardev=qga0";
3679 my $rng = $conf->{rng0
} ? parse_rng
($conf->{rng0
}) : undef;
3680 if ($rng && $version_guard->(4, 1, 2)) {
3681 check_rng_source
($rng->{source
});
3683 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3684 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3685 my $limiter_str = "";
3687 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3690 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3691 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3692 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3700 for (my $i = 1; $i < $qxlnum; $i++){
3701 push @$devices, '-device', print_vga_device
(
3702 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3705 # assume other OS works like Linux
3706 my ($ram, $vram) = ("134217728", "67108864");
3707 if ($vga->{memory
}) {
3708 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3709 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3711 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3712 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3716 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3718 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3719 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3720 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3722 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3723 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3724 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3726 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3727 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3729 my $spice_enhancement_str = $conf->{spice_enhancements
} // '';
3730 my $spice_enhancement = parse_property_string
($spice_enhancements_fmt, $spice_enhancement_str);
3731 if ($spice_enhancement->{foldersharing
}) {
3732 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3733 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3736 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3737 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3738 if $spice_enhancement->{videostreaming
};
3740 push @$devices, '-spice', "$spice_opts";
3743 # enable balloon by default, unless explicitly disabled
3744 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3745 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3746 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3749 if ($conf->{watchdog
}) {
3750 my $wdopts = parse_watchdog
($conf->{watchdog
});
3751 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3752 my $watchdog = $wdopts->{model
} || 'i6300esb';
3753 push @$devices, '-device', "$watchdog$pciaddr";
3754 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3758 my $scsicontroller = {};
3759 my $ahcicontroller = {};
3760 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3762 # Add iscsi initiator name if available
3763 if (my $initiator = get_initiator_name
()) {
3764 push @$devices, '-iscsi', "initiator-name=$initiator";
3767 PVE
::QemuConfig-
>foreach_volume($conf, sub {
3768 my ($ds, $drive) = @_;
3770 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3771 check_volume_storage_type
($storecfg, $drive->{file
});
3772 push @$vollist, $drive->{file
};
3775 # ignore efidisk here, already added in bios/fw handling code above
3776 return if $drive->{interface
} eq 'efidisk';
3778 return if $drive->{interface
} eq 'tpmstate';
3780 $use_virtio = 1 if $ds =~ m/^virtio/;
3782 $drive->{bootindex
} = $bootorder->{$ds} if $bootorder->{$ds};
3784 if ($drive->{interface
} eq 'virtio'){
3785 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3788 if ($drive->{interface
} eq 'scsi') {
3790 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3792 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3793 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3795 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3796 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3799 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3800 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3801 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3802 } elsif ($drive->{iothread
}) {
3803 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3807 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3808 $queues = ",num_queues=$drive->{queues}";
3811 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
3812 if !$scsicontroller->{$controller};
3813 $scsicontroller->{$controller}=1;
3816 if ($drive->{interface
} eq 'sata') {
3817 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3818 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3819 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
3820 if !$ahcicontroller->{$controller};
3821 $ahcicontroller->{$controller}=1;
3824 my $pbs_conf = $pbs_backing->{$ds};
3825 my $pbs_name = undef;
3827 $pbs_name = "drive-$ds-pbs";
3828 push @$devices, '-blockdev', print_pbs_blockdev
($pbs_conf, $pbs_name);
3831 my $drive_cmd = print_drive_commandline_full
(
3832 $storecfg, $vmid, $drive, $pbs_name, min_version
($kvmver, 6, 0));
3834 # extra protection for templates, but SATA and IDE don't support it..
3835 $drive_cmd .= ',readonly=on' if drive_is_read_only
($conf, $drive);
3837 push @$devices, '-drive',$drive_cmd;
3838 push @$devices, '-device', print_drivedevice_full
(
3839 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3842 for (my $i = 0; $i < $MAX_NETS; $i++) {
3843 my $netname = "net$i";
3845 next if !$conf->{$netname};
3846 my $d = parse_net
($conf->{$netname});
3849 $use_virtio = 1 if $d->{model
} eq 'virtio';
3851 $d->{bootindex
} = $bootorder->{$netname} if $bootorder->{$netname};
3853 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, $netname);
3854 push @$devices, '-netdev', $netdevfull;
3856 my $netdevicefull = print_netdevice_full
(
3857 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
3859 push @$devices, '-device', $netdevicefull;
3862 if ($conf->{ivshmem
}) {
3863 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3867 $bus = print_pcie_addr
("ivshmem");
3869 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3872 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3873 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3875 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3876 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
3877 .",size=$ivshmem->{size}M";
3880 # pci.4 is nested in pci.1
3881 $bridges->{1} = 1 if $bridges->{4};
3885 if (min_version
($machine_version, 2, 3)) {
3890 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3894 for my $k (sort {$b cmp $a} keys %$bridges) {
3895 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3898 if ($k == 2 && $legacy_igd) {
3901 $pciaddr = print_pci_addr
("pci.$k_name", undef, $arch, $machine_type);
3903 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3905 # add after -readconfig pve-q35.cfg
3906 splice @$devices, 2, 0, '-device', $devstr;
3908 unshift @$devices, '-device', $devstr if $k > 0;
3913 push @$machineFlags, 'accel=tcg';
3916 my $machine_type_min = $machine_type;
3917 if ($add_pve_version) {
3918 $machine_type_min =~ s/\+pve\d+$//;
3919 $machine_type_min .= "+pve$required_pve_version";
3921 push @$machineFlags, "type=${machine_type_min}";
3923 push @$cmd, @$devices;
3924 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
3925 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
3926 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
3928 if (my $vmstate = $conf->{vmstate
}) {
3929 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3930 push @$vollist, $vmstate;
3931 push @$cmd, '-loadstate', $statepath;
3932 print "activating and using '$vmstate' as vmstate\n";
3935 if (PVE
::QemuConfig-
>is_template($conf)) {
3936 # needed to workaround base volumes being read-only
3937 push @$cmd, '-snapshot';
3941 if ($conf->{args
}) {
3942 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3946 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3949 sub check_rng_source
{
3952 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3953 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
3956 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
3957 if ($source eq '/dev/hwrng' && file_read_firstline
($rng_current) eq 'none') {
3958 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
3959 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
3960 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
3961 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
3969 my $res = mon_cmd
($vmid, 'query-spice');
3971 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3974 sub vm_devices_list
{
3977 my $res = mon_cmd
($vmid, 'query-pci');
3978 my $devices_to_check = [];
3980 foreach my $pcibus (@$res) {
3981 push @$devices_to_check, @{$pcibus->{devices
}},
3984 while (@$devices_to_check) {
3986 for my $d (@$devices_to_check) {
3987 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3988 next if !$d->{'pci_bridge'};
3990 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3991 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3993 $devices_to_check = $to_check;
3996 my $resblock = mon_cmd
($vmid, 'query-block');
3997 foreach my $block (@$resblock) {
3998 if($block->{device
} =~ m/^drive-(\S+)/){
4003 my $resmice = mon_cmd
($vmid, 'query-mice');
4004 foreach my $mice (@$resmice) {
4005 if ($mice->{name
} eq 'QEMU HID Tablet') {
4006 $devices->{tablet
} = 1;
4011 # for usb devices there is no query-usb
4012 # but we can iterate over the entries in
4013 # qom-list path=/machine/peripheral
4014 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4015 foreach my $per (@$resperipheral) {
4016 if ($per->{name
} =~ m/^usb\d+$/) {
4017 $devices->{$per->{name
}} = 1;
4025 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4027 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
4029 my $devices_list = vm_devices_list
($vmid);
4030 return 1 if defined($devices_list->{$deviceid});
4032 # add PCI bridge if we need it for the device
4033 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
4035 if ($deviceid eq 'tablet') {
4037 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4039 } elsif ($deviceid eq 'keyboard') {
4041 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4043 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4045 die "usb hotplug currently not reliable\n";
4046 # since we can't reliably hot unplug all added usb devices and usb
4047 # passthrough breaks live migration we disable usb hotplugging for now
4048 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
4050 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4052 qemu_iothread_add
($vmid, $deviceid, $device);
4054 qemu_driveadd
($storecfg, $vmid, $device);
4055 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4057 qemu_deviceadd
($vmid, $devicefull);
4058 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4060 eval { qemu_drivedel
($vmid, $deviceid); };
4065 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4068 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4069 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4070 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4072 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4074 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4075 qemu_iothread_add
($vmid, $deviceid, $device);
4076 $devicefull .= ",iothread=iothread-$deviceid";
4079 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4080 $devicefull .= ",num_queues=$device->{queues}";
4083 qemu_deviceadd
($vmid, $devicefull);
4084 qemu_deviceaddverify
($vmid, $deviceid);
4086 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4088 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4089 qemu_driveadd
($storecfg, $vmid, $device);
4091 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4092 eval { qemu_deviceadd
($vmid, $devicefull); };
4094 eval { qemu_drivedel
($vmid, $deviceid); };
4099 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4101 return if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4103 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
4104 my $use_old_bios_files = undef;
4105 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4107 my $netdevicefull = print_netdevice_full
(
4108 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4109 qemu_deviceadd
($vmid, $netdevicefull);
4111 qemu_deviceaddverify
($vmid, $deviceid);
4112 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4115 eval { qemu_netdevdel
($vmid, $deviceid); };
4120 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4123 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4124 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4126 qemu_deviceadd
($vmid, $devicefull);
4127 qemu_deviceaddverify
($vmid, $deviceid);
4130 die "can't hotplug device '$deviceid'\n";
4136 # fixme: this should raise exceptions on error!
4137 sub vm_deviceunplug
{
4138 my ($vmid, $conf, $deviceid) = @_;
4140 my $devices_list = vm_devices_list
($vmid);
4141 return 1 if !defined($devices_list->{$deviceid});
4143 my $bootdisks = PVE
::QemuServer
::Drive
::get_bootdisks
($conf);
4144 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
4146 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4147 qemu_devicedel
($vmid, $deviceid);
4148 } elsif ($deviceid =~ m/^usb\d+$/) {
4149 die "usb hotplug currently not reliable\n";
4150 # when unplugging usb devices this way, there may be remaining usb
4151 # controllers/hubs so we disable it for now
4152 #qemu_devicedel($vmid, $deviceid);
4153 #qemu_devicedelverify($vmid, $deviceid);
4154 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4155 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4157 qemu_devicedel
($vmid, $deviceid);
4158 qemu_devicedelverify
($vmid, $deviceid);
4159 qemu_drivedel
($vmid, $deviceid);
4160 qemu_iothread_del
($vmid, $deviceid, $device);
4161 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4162 qemu_devicedel
($vmid, $deviceid);
4163 qemu_devicedelverify
($vmid, $deviceid);
4164 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4165 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4167 qemu_devicedel
($vmid, $deviceid);
4168 qemu_drivedel
($vmid, $deviceid);
4169 qemu_deletescsihw
($conf, $vmid, $deviceid);
4171 qemu_iothread_del
($vmid, "virtioscsi$device->{index}", $device)
4172 if $conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single');
4173 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4174 qemu_devicedel
($vmid, $deviceid);
4175 qemu_devicedelverify
($vmid, $deviceid);
4176 qemu_netdevdel
($vmid, $deviceid);
4178 die "can't unplug device '$deviceid'\n";
4184 sub qemu_deviceadd
{
4185 my ($vmid, $devicefull) = @_;
4187 $devicefull = "driver=".$devicefull;
4188 my %options = split(/[=,]/, $devicefull);
4190 mon_cmd
($vmid, "device_add" , %options);
4193 sub qemu_devicedel
{
4194 my ($vmid, $deviceid) = @_;
4196 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
4199 sub qemu_iothread_add
{
4200 my ($vmid, $deviceid, $device) = @_;
4202 if ($device->{iothread
}) {
4203 my $iothreads = vm_iothreads_list
($vmid);
4204 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4208 sub qemu_iothread_del
{
4209 my ($vmid, $deviceid, $device) = @_;
4211 if ($device->{iothread
}) {
4212 my $iothreads = vm_iothreads_list
($vmid);
4213 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4217 sub qemu_objectadd
{
4218 my ($vmid, $objectid, $qomtype) = @_;
4220 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4225 sub qemu_objectdel
{
4226 my ($vmid, $objectid) = @_;
4228 mon_cmd
($vmid, "object-del", id
=> $objectid);
4234 my ($storecfg, $vmid, $device) = @_;
4236 my $kvmver = get_running_qemu_version
($vmid);
4237 my $io_uring = min_version
($kvmver, 6, 0);
4238 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device, undef, $io_uring);
4239 $drive =~ s/\\/\\\\/g;
4240 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
4242 # If the command succeeds qemu prints: "OK
"
4243 return 1 if $ret =~ m/OK/s;
4245 die "adding drive failed
: $ret\n";
4249 my ($vmid, $deviceid) = @_;
4251 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
4254 return 1 if $ret eq "";
4256 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4257 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4259 die "deleting drive
$deviceid failed
: $ret\n";
4262 sub qemu_deviceaddverify {
4263 my ($vmid, $deviceid) = @_;
4265 for (my $i = 0; $i <= 5; $i++) {
4266 my $devices_list = vm_devices_list($vmid);
4267 return 1 if defined($devices_list->{$deviceid});
4271 die "error on hotplug device
'$deviceid'\n";
4275 sub qemu_devicedelverify {
4276 my ($vmid, $deviceid) = @_;
4278 # need to verify that the device is correctly removed as device_del
4279 # is async and empty return is not reliable
4281 for (my $i = 0; $i <= 5; $i++) {
4282 my $devices_list = vm_devices_list($vmid);
4283 return 1 if !defined($devices_list->{$deviceid});
4287 die "error on hot-unplugging device
'$deviceid'\n";
4290 sub qemu_findorcreatescsihw {
4291 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4293 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4295 my $scsihwid="$controller_prefix$controller";
4296 my $devices_list = vm_devices_list($vmid);
4298 if (!defined($devices_list->{$scsihwid})) {
4299 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4305 sub qemu_deletescsihw {
4306 my ($conf, $vmid, $opt) = @_;
4308 my $device = parse_drive($opt, $conf->{$opt});
4310 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4311 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4315 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4317 my $devices_list = vm_devices_list($vmid);
4318 foreach my $opt (keys %{$devices_list}) {
4319 if (is_valid_drivename($opt)) {
4320 my $drive = parse_drive($opt, $conf->{$opt});
4321 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4327 my $scsihwid="scsihw
$controller";
4329 vm_deviceunplug($vmid, $conf, $scsihwid);
4334 sub qemu_add_pci_bridge {
4335 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4341 print_pci_addr($device, $bridges, $arch, $machine_type);
4343 while (my ($k, $v) = each %$bridges) {
4346 return 1 if !defined($bridgeid) || $bridgeid < 1;
4348 my $bridge = "pci
.$bridgeid";
4349 my $devices_list = vm_devices_list($vmid);
4351 if (!defined($devices_list->{$bridge})) {
4352 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4358 sub qemu_set_link_status {
4359 my ($vmid, $device, $up) = @_;
4361 mon_cmd($vmid, "set_link
", name => $device,
4362 up => $up ? JSON::true : JSON::false);
4365 sub qemu_netdevadd {
4366 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4368 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4369 my %options = split(/[=,]/, $netdev);
4371 if (defined(my $vhost = $options{vhost})) {
4372 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4375 if (defined(my $queues = $options{queues})) {
4376 $options{queues} = $queues + 0;
4379 mon_cmd($vmid, "netdev_add
", %options);
4383 sub qemu_netdevdel {
4384 my ($vmid, $deviceid) = @_;
4386 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4389 sub qemu_usb_hotplug {
4390 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4394 # remove the old one first
4395 vm_deviceunplug($vmid, $conf, $deviceid);
4397 # check if xhci controller is necessary and available
4398 if ($device->{usb3}) {
4400 my $devicelist = vm_devices_list($vmid);
4402 if (!$devicelist->{xhci}) {
4403 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4404 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4407 my $d = parse_usb_device($device->{host});
4408 $d->{usb3} = $device->{usb3};
4411 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4414 sub qemu_cpu_hotplug {
4415 my ($vmid, $conf, $vcpus) = @_;
4417 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4420 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4421 $sockets = $conf->{sockets} if $conf->{sockets};
4422 my $cores = $conf->{cores} || 1;
4423 my $maxcpus = $sockets * $cores;
4425 $vcpus = $maxcpus if !$vcpus;
4427 die "you can
't add more vcpus than maxcpus\n"
4428 if $vcpus > $maxcpus;
4430 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4432 if ($vcpus < $currentvcpus) {
4434 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4436 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4437 qemu_devicedel($vmid, "cpu$i");
4439 my $currentrunningvcpus = undef;
4441 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4442 last if scalar(@{$currentrunningvcpus}) == $i-1;
4443 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4447 #update conf after each succesfull cpu unplug
4448 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4449 PVE::QemuConfig->write_config($vmid, $conf);
4452 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4458 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4459 die "vcpus in running vm does not match its configuration\n"
4460 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4462 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4464 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4465 my $cpustr = print_cpu_device($conf, $i);
4466 qemu_deviceadd($vmid, $cpustr);
4469 my $currentrunningvcpus = undef;
4471 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4472 last if scalar(@{$currentrunningvcpus}) == $i;
4473 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4477 #update conf after each succesfull cpu hotplug
4478 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4479 PVE::QemuConfig->write_config($vmid, $conf);
4483 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4484 mon_cmd($vmid, "cpu-add", id => int($i));
4489 sub qemu_block_set_io_throttle {
4490 my ($vmid, $deviceid,
4491 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4492 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4493 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4494 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4496 return if !check_running($vmid) ;
4498 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4500 bps_rd => int($bps_rd),
4501 bps_wr => int($bps_wr),
4503 iops_rd => int($iops_rd),
4504 iops_wr => int($iops_wr),
4505 bps_max => int($bps_max),
4506 bps_rd_max => int($bps_rd_max),
4507 bps_wr_max => int($bps_wr_max),
4508 iops_max => int($iops_max),
4509 iops_rd_max => int($iops_rd_max),
4510 iops_wr_max => int($iops_wr_max),
4511 bps_max_length => int($bps_max_length),
4512 bps_rd_max_length => int($bps_rd_max_length),
4513 bps_wr_max_length => int($bps_wr_max_length),
4514 iops_max_length => int($iops_max_length),
4515 iops_rd_max_length => int($iops_rd_max_length),
4516 iops_wr_max_length => int($iops_wr_max_length),
4521 sub qemu_block_resize {
4522 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4524 my $running = check_running($vmid);
4526 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4528 return if !$running;
4530 my $padding = (1024 - $size % 1024) % 1024;
4531 $size = $size + $padding;
4536 device => $deviceid,
4542 sub qemu_volume_snapshot {
4543 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4545 my $running = check_running($vmid);
4547 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4548 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4550 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4554 sub qemu_volume_snapshot_delete {
4555 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4557 my $running = check_running($vmid);
4562 my $conf = PVE::QemuConfig->load_config($vmid);
4563 PVE::QemuConfig->foreach_volume($conf, sub {
4564 my ($ds, $drive) = @_;
4565 $running = 1 if $drive->{file} eq $volid;
4569 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4570 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4572 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4576 sub set_migration_caps {
4577 my ($vmid, $savevm) = @_;
4579 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4581 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm
' : 'pbs-dirty-bitmap-migration
';
4582 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4587 "auto-converge" => 1,
4589 "x-rdma-pin-all" => 0,
4592 "dirty-bitmaps" => $dirty_bitmaps,
4595 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4597 for my $supported_capability (@$supported_capabilities) {
4599 capability => $supported_capability->{capability},
4600 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4604 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4608 my ($conf, $func, @param) = @_;
4612 my $test_volid = sub {
4613 my ($key, $drive, $snapname) = @_;
4615 my $volid = $drive->{file};
4618 $volhash->{$volid}->{cdrom} //= 1;
4619 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
4621 my $replicate = $drive->{replicate} // 1;
4622 $volhash->{$volid}->{replicate} //= 0;
4623 $volhash->{$volid}->{replicate} = 1 if $replicate;
4625 $volhash->{$volid}->{shared} //= 0;
4626 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
4628 $volhash->{$volid}->{referenced_in_config} //= 0;
4629 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4631 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4632 if defined($snapname);
4634 my $size = $drive->{size};
4635 $volhash->{$volid}->{size} //= $size if $size;
4637 $volhash->{$volid}->{is_vmstate} //= 0;
4638 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate
';
4640 $volhash->{$volid}->{is_tpmstate} //= 0;
4641 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0
';
4643 $volhash->{$volid}->{is_unused} //= 0;
4644 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
4646 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
4649 my $include_opts = {
4650 extra_keys => ['vmstate
'],
4651 include_unused => 1,
4654 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
4655 foreach my $snapname (keys %{$conf->{snapshots}}) {
4656 my $snap = $conf->{snapshots}->{$snapname};
4657 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
4660 foreach my $volid (keys %$volhash) {
4661 &$func($volid, $volhash->{$volid}, @param);
4665 my $fast_plug_option = {
4673 'vmstatestorage
' => 1,
4678 # hotplug changes in [PENDING]
4679 # $selection hash can be used to only apply specified options, for
4680 # example: { cores => 1 } (only apply changed 'cores
')
4681 # $errors ref is used to return error messages
4682 sub vmconfig_hotplug_pending {
4683 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4685 my $defaults = load_defaults();
4686 my $arch = get_vm_arch($conf);
4687 my $machine_type = get_vm_machine($conf, undef, $arch);
4689 # commit values which do not have any impact on running VM first
4690 # Note: those option cannot raise errors, we we do not care about
4691 # $selection and always apply them.
4693 my $add_error = sub {
4694 my ($opt, $msg) = @_;
4695 $errors->{$opt} = "hotplug problem - $msg";
4699 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4700 if ($fast_plug_option->{$opt}) {
4701 $conf->{$opt} = $conf->{pending}->{$opt};
4702 delete $conf->{pending}->{$opt};
4708 PVE::QemuConfig->write_config($vmid, $conf);
4711 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4713 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
4714 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4715 foreach my $opt (sort keys %$pending_delete_hash) {
4716 next if $selection && !$selection->{$opt};
4717 my $force = $pending_delete_hash->{$opt}->{force};
4719 if ($opt eq 'hotplug
') {
4720 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4721 } elsif ($opt eq 'tablet
') {
4722 die "skip\n" if !$hotplug_features->{usb};
4723 if ($defaults->{tablet}) {
4724 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4725 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4726 if $arch eq 'aarch64
';
4728 vm_deviceunplug($vmid, $conf, 'tablet
');
4729 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4731 } elsif ($opt =~ m/^usb\d+/) {
4733 # since we cannot reliably hot unplug usb devices we are disabling it
4734 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4735 #vm_deviceunplug($vmid, $conf, $opt);
4736 } elsif ($opt eq 'vcpus
') {
4737 die "skip\n" if !$hotplug_features->{cpu};
4738 qemu_cpu_hotplug($vmid, $conf, undef);
4739 } elsif ($opt eq 'balloon
') {
4740 # enable balloon device is not hotpluggable
4741 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4742 # here we reset the ballooning value to memory
4743 my $balloon = $conf->{memory} || $defaults->{memory};
4744 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4745 } elsif ($fast_plug_option->{$opt}) {
4747 } elsif ($opt =~ m/^net(\d+)$/) {
4748 die "skip\n" if !$hotplug_features->{network};
4749 vm_deviceunplug($vmid, $conf, $opt);
4750 } elsif (is_valid_drivename($opt)) {
4751 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4752 vm_deviceunplug($vmid, $conf, $opt);
4753 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4754 } elsif ($opt =~ m/^memory$/) {
4755 die "skip\n" if !$hotplug_features->{memory};
4756 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4757 } elsif ($opt eq 'cpuunits
') {
4758 $cgroup->change_cpu_shares(undef, 1024);
4759 } elsif ($opt eq 'cpulimit
') {
4760 $cgroup->change_cpu_quota(-1, 100000);
4766 &$add_error($opt, $err) if $err ne "skip\n";
4768 delete $conf->{$opt};
4769 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4773 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4774 $apply_pending_cloudinit = sub {
4775 return if $apply_pending_cloudinit_done; # once is enough
4776 $apply_pending_cloudinit_done = 1; # once is enough
4778 my ($key, $value) = @_;
4780 my @cloudinit_opts = keys %$confdesc_cloudinit;
4781 foreach my $opt (keys %{$conf->{pending}}) {
4782 next if !grep { $_ eq $opt } @cloudinit_opts;
4783 $conf->{$opt} = delete $conf->{pending}->{$opt};
4786 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4787 foreach my $opt (sort keys %$pending_delete_hash) {
4788 next if !grep { $_ eq $opt } @cloudinit_opts;
4789 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4790 delete $conf->{$opt};
4793 my $new_conf = { %$conf };
4794 $new_conf->{$key} = $value;
4795 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4798 foreach my $opt (keys %{$conf->{pending}}) {
4799 next if $selection && !$selection->{$opt};
4800 my $value = $conf->{pending}->{$opt};
4802 if ($opt eq 'hotplug
') {
4803 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4804 } elsif ($opt eq 'tablet
') {
4805 die "skip\n" if !$hotplug_features->{usb};
4807 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4808 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4809 if $arch eq 'aarch64
';
4810 } elsif ($value == 0) {
4811 vm_deviceunplug($vmid, $conf, 'tablet
');
4812 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4814 } elsif ($opt =~ m/^usb\d+$/) {
4816 # since we cannot reliably hot unplug usb devices we disable it for now
4817 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4818 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4819 #die "skip\n" if !$d;
4820 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4821 } elsif ($opt eq 'vcpus
') {
4822 die "skip\n" if !$hotplug_features->{cpu};
4823 qemu_cpu_hotplug($vmid, $conf, $value);
4824 } elsif ($opt eq 'balloon
') {
4825 # enable/disable balloning device is not hotpluggable
4826 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4827 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4828 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4830 # allow manual ballooning if shares is set to zero
4831 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4832 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4833 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4835 } elsif ($opt =~ m/^net(\d+)$/) {
4836 # some changes can be done without hotplug
4837 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4838 $vmid, $opt, $value, $arch, $machine_type);
4839 } elsif (is_valid_drivename($opt)) {
4840 die "skip\n" if $opt eq 'efidisk0
' || $opt eq 'tpmstate0
';
4841 # some changes can be done without hotplug
4842 my $drive = parse_drive($opt, $value);
4843 if (drive_is_cloudinit($drive)) {
4844 &$apply_pending_cloudinit($opt, $value);
4846 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4847 $vmid, $opt, $value, $arch, $machine_type);
4848 } elsif ($opt =~ m/^memory$/) { #dimms
4849 die "skip\n" if !$hotplug_features->{memory};
4850 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4851 } elsif ($opt eq 'cpuunits
') {
4852 $cgroup->change_cpu_shares($conf->{pending}->{$opt}, 1024);
4853 } elsif ($opt eq 'cpulimit
') {
4854 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4855 $cgroup->change_cpu_quota($cpulimit, 100000);
4857 die "skip\n"; # skip non-hot-pluggable options
4861 &$add_error($opt, $err) if $err ne "skip\n";
4863 $conf->{$opt} = $value;
4864 delete $conf->{pending}->{$opt};
4868 PVE::QemuConfig->write_config($vmid, $conf);
4871 sub try_deallocate_drive {
4872 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4874 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4875 my $volid = $drive->{file};
4876 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4877 my $sid = PVE::Storage::parse_volume_id($volid);
4878 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4880 # check if the disk is really unused
4881 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4882 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4883 PVE::Storage::vdisk_free($storecfg, $volid);
4886 # If vm is not owner of this disk remove from config
4894 sub vmconfig_delete_or_detach_drive {
4895 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4897 my $drive = parse_drive($opt, $conf->{$opt});
4899 my $rpcenv = PVE::RPCEnvironment::get();
4900 my $authuser = $rpcenv->get_user();
4903 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4904 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4906 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4912 sub vmconfig_apply_pending {
4913 my ($vmid, $conf, $storecfg, $errors) = @_;
4915 my $add_apply_error = sub {
4916 my ($opt, $msg) = @_;
4917 my $err_msg = "unable to apply pending change $opt : $msg";
4918 $errors->{$opt} = $err_msg;
4924 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4925 foreach my $opt (sort keys %$pending_delete_hash) {
4926 my $force = $pending_delete_hash->{$opt}->{force};
4928 if ($opt =~ m/^unused/) {
4929 die "internal error";
4930 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4931 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4935 $add_apply_error->($opt, $err);
4937 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4938 delete $conf->{$opt};
4942 PVE::QemuConfig->cleanup_pending($conf);
4944 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4945 next if $opt eq 'delete'; # just to be sure
4947 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4948 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4952 $add_apply_error->($opt, $err);
4954 $conf->{$opt} = delete $conf->{pending}->{$opt};
4958 # write all changes at once to avoid unnecessary i/o
4959 PVE::QemuConfig->write_config($vmid, $conf);
4962 sub vmconfig_update_net {
4963 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4965 my $newnet = parse_net($value);
4967 if ($conf->{$opt}) {
4968 my $oldnet = parse_net($conf->{$opt});
4970 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4971 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4972 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4973 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4975 # for non online change, we try to hot-unplug
4976 die "skip\n" if !$hotplug;
4977 vm_deviceunplug($vmid, $conf, $opt);
4980 die "internal error" if $opt !~ m/net(\d+)/;
4981 my $iface = "tap${vmid}i$1";
4983 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4984 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4985 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4986 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4987 PVE::Network::tap_unplug($iface);
4990 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4992 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4994 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4995 # Rate can be applied on its own but any change above needs to
4996 # include the rate in tap_plug since OVS resets everything.
4997 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
5000 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5001 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5009 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5015 sub vmconfig_update_disk {
5016 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5018 my $drive = parse_drive($opt, $value);
5020 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
5021 my $media = $drive->{media} || 'disk
';
5022 my $oldmedia = $old_drive->{media} || 'disk
';
5023 die "unable to change media type\n" if $media ne $oldmedia;
5025 if (!drive_is_cdrom($old_drive)) {
5027 if ($drive->{file} ne $old_drive->{file}) {
5029 die "skip\n" if !$hotplug;
5031 # unplug and register as unused
5032 vm_deviceunplug($vmid, $conf, $opt);
5033 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5036 # update existing disk
5038 # skip non hotpluggable value
5039 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5040 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5041 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5042 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
5043 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
5048 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5049 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5050 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5051 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5052 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5053 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5054 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5055 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5056 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5057 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5058 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5059 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5060 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5061 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5062 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5063 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5064 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5065 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5067 qemu_block_set_io_throttle(
5069 ($drive->{mbps} || 0)*1024*1024,
5070 ($drive->{mbps_rd} || 0)*1024*1024,
5071 ($drive->{mbps_wr} || 0)*1024*1024,
5072 $drive->{iops} || 0,
5073 $drive->{iops_rd} || 0,
5074 $drive->{iops_wr} || 0,
5075 ($drive->{mbps_max} || 0)*1024*1024,
5076 ($drive->{mbps_rd_max} || 0)*1024*1024,
5077 ($drive->{mbps_wr_max} || 0)*1024*1024,
5078 $drive->{iops_max} || 0,
5079 $drive->{iops_rd_max} || 0,
5080 $drive->{iops_wr_max} || 0,
5081 $drive->{bps_max_length} || 1,
5082 $drive->{bps_rd_max_length} || 1,
5083 $drive->{bps_wr_max_length} || 1,
5084 $drive->{iops_max_length} || 1,
5085 $drive->{iops_rd_max_length} || 1,
5086 $drive->{iops_wr_max_length} || 1,
5096 if ($drive->{file} eq 'none
') {
5097 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5098 if (drive_is_cloudinit($old_drive)) {
5099 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5102 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5104 # force eject if locked
5105 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5108 mon_cmd($vmid, "blockdev-change-medium",
5109 id => "$opt", filename => "$path");
5117 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5119 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5120 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5123 # called in locked context by incoming migration
5124 sub vm_migrate_get_nbd_disks {
5125 my ($storecfg, $conf, $replicated_volumes) = @_;
5127 my $local_volumes = {};
5128 PVE::QemuConfig->foreach_volume($conf, sub {
5129 my ($ds, $drive) = @_;
5131 return if drive_is_cdrom($drive);
5133 my $volid = $drive->{file};
5137 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5139 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5140 return if $scfg->{shared};
5142 # replicated disks re-use existing state via bitmap
5143 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5144 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
5146 return $local_volumes;
5149 # called in locked context by incoming migration
5150 sub vm_migrate_alloc_nbd_disks {
5151 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
5156 foreach my $opt (sort keys %$source_volumes) {
5157 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
5159 if ($use_existing) {
5160 $nbd->{$opt}->{drivestr} = print_drive($drive);
5161 $nbd->{$opt}->{volid} = $volid;
5162 $nbd->{$opt}->{replicated} = 1;
5166 # If a remote storage is specified and the format of the original
5167 # volume is not available there, fall back to the default format.
5168 # Otherwise use the same format as the original.
5169 if (!$storagemap->{identity}) {
5170 $storeid = map_storage($storagemap, $storeid);
5171 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5172 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5173 my $fileFormat = qemu_img_format($scfg, $volname);
5174 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
5176 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5177 $format = qemu_img_format($scfg, $volname);
5180 my $size = $drive->{size} / 1024;
5181 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
5182 my $newdrive = $drive;
5183 $newdrive->{format} = $format;
5184 $newdrive->{file} = $newvolid;
5185 my $drivestr = print_drive($newdrive);
5186 $nbd->{$opt}->{drivestr} = $drivestr;
5187 $nbd->{$opt}->{volid} = $newvolid;
5193 # see vm_start_nolock for parameters, additionally:
5195 # storagemap = parsed storage map for allocating NBD disks
5197 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5199 return PVE::QemuConfig->lock_config($vmid, sub {
5200 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5202 die "you can't start a vm
if it
's a template\n"
5203 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
5205 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended
');
5206 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup
');
5208 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5210 if ($has_backup_lock && $running) {
5211 # a backup is currently running, attempt to start the guest in the
5212 # existing QEMU instance
5213 return vm_resume($vmid);
5216 PVE::QemuConfig->check_lock($conf)
5217 if !($params->{skiplock} || $has_suspended_lock);
5219 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
5221 die "VM $vmid already running\n" if $running;
5223 if (my $storagemap = $migrate_opts->{storagemap}) {
5224 my $replicated = $migrate_opts->{replicated_volumes};
5225 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5226 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5228 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5229 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5233 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
5239 # statefile => 'tcp
', 'unix
' for migration or path/volid for RAM state
5240 # skiplock => 0/1, skip checking for config lock
5241 # skiptemplate => 0/1, skip checking whether VM is template
5242 # forcemachine => to force Qemu machine (rollback/migration)
5243 # forcecpu => a QEMU '-cpu
' argument string to override get_cpu_options
5244 # timeout => in seconds
5245 # paused => start VM in paused state (backup)
5246 # resume => resume from hibernation
5257 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
5258 # migratedfrom => source node
5259 # spice_ticket => used for spice migration, passed via tunnel/stdin
5260 # network => CIDR of migration network
5261 # type => secure/insecure - tunnel over encrypted connection or plain-text
5262 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
5263 # replicated_volumes = which volids should be re-used with bitmaps for nbd migration
5264 sub vm_start_nolock {
5265 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
5267 my $statefile = $params->{statefile};
5268 my $resume = $params->{resume};
5270 my $migratedfrom = $migrate_opts->{migratedfrom};
5271 my $migration_type = $migrate_opts->{type};
5275 # clean up leftover reboot request files
5276 eval { clear_reboot_request($vmid); };
5279 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5280 vmconfig_apply_pending($vmid, $conf, $storecfg);
5281 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5284 # don't regenerate the ISO
if the VM
is started as part of a live migration
5285 # this way we can reuse the old ISO with the correct config
5286 PVE
::QemuServer
::Cloudinit
::generate_cloudinitconfig
($conf, $vmid) if !$migratedfrom;
5288 my $defaults = load_defaults
();
5290 # set environment variable useful inside network script
5291 $ENV{PVE_MIGRATED_FROM
} = $migratedfrom if $migratedfrom;
5293 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-start', 1);
5295 my $forcemachine = $params->{forcemachine
};
5296 my $forcecpu = $params->{forcecpu
};
5298 # enforce machine and CPU type on suspended vm to ensure HW compatibility
5299 $forcemachine = $conf->{runningmachine
};
5300 $forcecpu = $conf->{runningcpu
};
5301 print "Resuming suspended VM\n";
5304 my ($cmd, $vollist, $spice_port) = config_to_command
($storecfg, $vmid,
5305 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
5308 my $get_migration_ip = sub {
5309 my ($nodename) = @_;
5311 return $migration_ip if defined($migration_ip);
5313 my $cidr = $migrate_opts->{network
};
5315 if (!defined($cidr)) {
5316 my $dc_conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5317 $cidr = $dc_conf->{migration
}->{network
};
5320 if (defined($cidr)) {
5321 my $ips = PVE
::Network
::get_local_ip_from_cidr
($cidr);
5323 die "could not get IP: no address configured on local " .
5324 "node for network '$cidr'\n" if scalar(@$ips) == 0;
5326 die "could not get IP: multiple addresses configured on local " .
5327 "node for network '$cidr'\n" if scalar(@$ips) > 1;
5329 $migration_ip = @$ips[0];
5332 $migration_ip = PVE
::Cluster
::remote_node_ip
($nodename, 1)
5333 if !defined($migration_ip);
5335 return $migration_ip;
5340 if ($statefile eq 'tcp') {
5341 my $localip = "localhost";
5342 my $datacenterconf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5343 my $nodename = nodename
();
5345 if (!defined($migration_type)) {
5346 if (defined($datacenterconf->{migration
}->{type
})) {
5347 $migration_type = $datacenterconf->{migration
}->{type
};
5349 $migration_type = 'secure';
5353 if ($migration_type eq 'insecure') {
5354 $localip = $get_migration_ip->($nodename);
5355 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5358 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5359 my $migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5360 $migrate_uri = "tcp:${localip}:${migrate_port}";
5361 push @$cmd, '-incoming', $migrate_uri;
5364 } elsif ($statefile eq 'unix') {
5365 # should be default for secure migrations as a ssh TCP forward
5366 # tunnel is not deterministic reliable ready and fails regurarly
5367 # to set up in time, so use UNIX socket forwards
5368 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5369 unlink $socket_addr;
5371 $migrate_uri = "unix:$socket_addr";
5373 push @$cmd, '-incoming', $migrate_uri;
5376 } elsif (-e
$statefile) {
5377 push @$cmd, '-loadstate', $statefile;
5379 my $statepath = PVE
::Storage
::path
($storecfg, $statefile);
5380 push @$vollist, $statefile;
5381 push @$cmd, '-loadstate', $statepath;
5383 } elsif ($params->{paused
}) {
5387 my $start_timeout = $params->{timeout
} // config_aware_timeout
($conf, $resume);
5389 my $pci_devices = {}; # host pci devices
5390 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
5391 my $dev = $conf->{"hostpci$i"} or next;
5392 $pci_devices->{$i} = parse_hostpci
($dev);
5395 my $pci_id_list = [ map { $_->{id
} } map { $_->{pciid
}->@* } values $pci_devices->%* ];
5396 # reserve all PCI IDs before actually doing anything with them
5397 PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_id_list, $vmid, $start_timeout);
5400 for my $id (sort keys %$pci_devices) {
5401 my $d = $pci_devices->{$id};
5402 for my $dev ($d->{pciid
}->@*) {
5403 PVE
::QemuServer
::PCI
::prepare_pci_device
($vmid, $dev->{id
}, $id, $d->{mdev
});
5408 eval { PVE
::QemuServer
::PCI
::remove_pci_reservation
($pci_id_list) };
5413 PVE
::Storage
::activate_volumes
($storecfg, $vollist);
5416 run_command
(['/bin/systemctl', 'stop', "$vmid.scope"], outfunc
=> sub{}, errfunc
=> sub{});
5418 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5419 # timeout should be more than enough here...
5420 PVE
::Systemd
::wait_for_unit_removed
("$vmid.scope", 5);
5422 my $cpuunits = get_cpuunits
($conf);
5425 timeout
=> $statefile ?
undef : $start_timeout,
5430 # when migrating, prefix QEMU output so other side can pick up any
5431 # errors that might occur and show the user
5432 if ($migratedfrom) {
5433 $run_params{quiet
} = 1;
5434 $run_params{logfunc
} = sub { print "QEMU: $_[0]\n" };
5437 my %systemd_properties = (
5438 Slice
=> 'qemu.slice',
5439 KillMode
=> 'process',
5441 TimeoutStopUSec
=> ULONG_MAX
, # infinity
5444 if (PVE
::CGroup
::cgroup_mode
() == 2) {
5445 $cpuunits = 10000 if $cpuunits >= 10000; # else we get an error
5446 $systemd_properties{CPUWeight
} = $cpuunits;
5448 $systemd_properties{CPUShares
} = $cpuunits;
5451 if (my $cpulimit = $conf->{cpulimit
}) {
5452 $systemd_properties{CPUQuota
} = int($cpulimit * 100);
5454 $systemd_properties{timeout
} = 10 if $statefile; # setting up the scope shoul be quick
5456 my $run_qemu = sub {
5457 PVE
::Tools
::run_fork
sub {
5458 PVE
::Systemd
::enter_systemd_scope
($vmid, "Proxmox VE VM $vmid", %systemd_properties);
5461 if (my $tpm = $conf->{tpmstate0
}) {
5462 # start the TPM emulator so QEMU can connect on start
5463 $tpmpid = start_swtpm
($storecfg, $vmid, $tpm, $migratedfrom);
5466 my $exitcode = run_command
($cmd, %run_params);
5468 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
5469 kill 'TERM', $tpmpid if $tpmpid;
5470 die "QEMU exited with code $exitcode\n";
5475 if ($conf->{hugepages
}) {
5478 my $hugepages_topology = PVE
::QemuServer
::Memory
::hugepages_topology
($conf);
5479 my $hugepages_host_topology = PVE
::QemuServer
::Memory
::hugepages_host_topology
();
5481 PVE
::QemuServer
::Memory
::hugepages_mount
();
5482 PVE
::QemuServer
::Memory
::hugepages_allocate
($hugepages_topology, $hugepages_host_topology);
5484 eval { $run_qemu->() };
5486 PVE
::QemuServer
::Memory
::hugepages_reset
($hugepages_host_topology)
5487 if !$conf->{keephugepages
};
5491 PVE
::QemuServer
::Memory
::hugepages_pre_deallocate
($hugepages_topology)
5492 if !$conf->{keephugepages
};
5494 eval { PVE
::QemuServer
::Memory
::hugepages_update_locked
($code); };
5497 eval { $run_qemu->() };
5501 # deactivate volumes if start fails
5502 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
5503 eval { PVE
::QemuServer
::PCI
::remove_pci_reservation
($pci_id_list) };
5505 die "start failed: $err";
5508 # re-reserve all PCI IDs now that we can know the actual VM PID
5509 my $pid = PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
5510 eval { PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_id_list, $vmid, undef, $pid) };
5513 print "migration listens on $migrate_uri\n" if $migrate_uri;
5514 $res->{migrate_uri
} = $migrate_uri;
5516 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5517 eval { mon_cmd
($vmid, "cont"); };
5521 #start nbd server for storage migration
5522 if (my $nbd = $migrate_opts->{nbd
}) {
5523 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version
} // 0;
5525 my $migrate_storage_uri;
5526 # nbd_protocol_version > 0 for unix socket support
5527 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5528 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5529 mon_cmd
($vmid, "nbd-server-start", addr
=> { type
=> 'unix', data
=> { path
=> $socket_path } } );
5530 $migrate_storage_uri = "nbd:unix:$socket_path";
5532 my $nodename = nodename
();
5533 my $localip = $get_migration_ip->($nodename);
5534 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5535 my $storage_migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5537 mon_cmd
($vmid, "nbd-server-start", addr
=> {
5540 host
=> "${localip}",
5541 port
=> "${storage_migrate_port}",
5544 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5545 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5548 $res->{migrate_storage_uri
} = $migrate_storage_uri;
5550 foreach my $opt (sort keys %$nbd) {
5551 my $drivestr = $nbd->{$opt}->{drivestr
};
5552 my $volid = $nbd->{$opt}->{volid
};
5553 mon_cmd
($vmid, "nbd-server-add", device
=> "drive-$opt", writable
=> JSON
::true
);
5554 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5555 print "storage migration listens on $nbd_uri volume:$drivestr\n";
5556 print "re-using replicated volume: $opt - $volid\n"
5557 if $nbd->{$opt}->{replicated
};
5559 $res->{drives
}->{$opt} = $nbd->{$opt};
5560 $res->{drives
}->{$opt}->{nbd_uri
} = $nbd_uri;
5564 if ($migratedfrom) {
5566 set_migration_caps
($vmid);
5571 print "spice listens on port $spice_port\n";
5572 $res->{spice_port
} = $spice_port;
5573 if ($migrate_opts->{spice_ticket
}) {
5574 mon_cmd
($vmid, "set_password", protocol
=> 'spice', password
=>
5575 $migrate_opts->{spice_ticket
});
5576 mon_cmd
($vmid, "expire_password", protocol
=> 'spice', time => "+30");
5581 mon_cmd
($vmid, "balloon", value
=> $conf->{balloon
}*1024*1024)
5582 if !$statefile && $conf->{balloon
};
5584 foreach my $opt (keys %$conf) {
5585 next if $opt !~ m/^net\d+$/;
5586 my $nicconf = parse_net
($conf->{$opt});
5587 qemu_set_link_status
($vmid, $opt, 0) if $nicconf->{link_down
};
5591 mon_cmd
($vmid, 'qom-set',
5592 path
=> "machine/peripheral/balloon0",
5593 property
=> "guest-stats-polling-interval",
5594 value
=> 2) if (!defined($conf->{balloon
}) || $conf->{balloon
});
5597 print "Resumed VM, removing state\n";
5598 if (my $vmstate = $conf->{vmstate
}) {
5599 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5600 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5602 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
5603 PVE
::QemuConfig-
>write_config($vmid, $conf);
5606 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5611 sub vm_commandline
{
5612 my ($storecfg, $vmid, $snapname) = @_;
5614 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5619 my $snapshot = $conf->{snapshots
}->{$snapname};
5620 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5622 # check for machine or CPU overrides in snapshot
5623 $forcemachine = $snapshot->{runningmachine
};
5624 $forcecpu = $snapshot->{runningcpu
};
5626 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5631 my $defaults = load_defaults
();
5633 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults,
5634 $forcemachine, $forcecpu);
5636 return PVE
::Tools
::cmd2string
($cmd);
5640 my ($vmid, $skiplock) = @_;
5642 PVE
::QemuConfig-
>lock_config($vmid, sub {
5644 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5646 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5648 mon_cmd
($vmid, "system_reset");
5652 sub get_vm_volumes
{
5656 foreach_volid
($conf, sub {
5657 my ($volid, $attr) = @_;
5659 return if $volid =~ m
|^/|;
5661 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5664 push @$vollist, $volid;
5670 sub vm_stop_cleanup
{
5671 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5676 my $vollist = get_vm_volumes
($conf);
5677 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5679 if (my $tpmdrive = $conf->{tpmstate0
}) {
5680 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
5681 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
5683 PVE
::Storage
::unmap_volume
($storecfg, $tpm->{file
});
5688 foreach my $ext (qw(mon qmp pid vnc qga)) {
5689 unlink "/var/run/qemu-server/${vmid}.$ext";
5692 if ($conf->{ivshmem
}) {
5693 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5694 # just delete it for now, VMs which have this already open do not
5695 # are affected, but new VMs will get a separated one. If this
5696 # becomes an issue we either add some sort of ref-counting or just
5697 # add a "don't delete on stop" flag to the ivshmem format.
5698 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5702 foreach my $key (keys %$conf) {
5703 next if $key !~ m/^hostpci(\d+)$/;
5704 my $hostpciindex = $1;
5705 my $d = parse_hostpci
($conf->{$key});
5706 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5708 foreach my $pci (@{$d->{pciid
}}) {
5709 my $pciid = $pci->{id
};
5710 push @$ids, $pci->{id
};
5711 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5714 PVE
::QemuServer
::PCI
::remove_pci_reservation
($ids);
5716 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5718 warn $@ if $@; # avoid errors - just warn
5721 # call only in locked context
5723 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5725 my $pid = check_running
($vmid, $nocheck);
5730 $conf = PVE
::QemuConfig-
>load_config($vmid);
5731 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5732 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5733 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5734 $timeout = $opts->{down
} if $opts->{down
};
5736 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5741 if (defined($conf) && get_qga_key
($conf, 'enabled')) {
5742 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5744 mon_cmd
($vmid, "system_powerdown");
5747 mon_cmd
($vmid, "quit");
5753 $timeout = 60 if !defined($timeout);
5756 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5761 if ($count >= $timeout) {
5763 warn "VM still running - terminating now with SIGTERM\n";
5766 die "VM quit/powerdown failed - got timeout\n";
5769 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5773 if (!check_running
($vmid, $nocheck)) {
5774 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5778 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5781 die "VM quit/powerdown failed\n";
5789 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5794 if ($count >= $timeout) {
5795 warn "VM still running - terminating now with SIGKILL\n";
5800 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5803 # Note: use $nocheck to skip tests if VM configuration file exists.
5804 # We need that when migration VMs to other nodes (files already moved)
5805 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5807 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5809 $force = 1 if !defined($force) && !$shutdown;
5812 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5813 kill 15, $pid if $pid;
5814 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5815 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5819 PVE
::QemuConfig-
>lock_config($vmid, sub {
5820 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5825 my ($vmid, $timeout) = @_;
5827 PVE
::QemuConfig-
>lock_config($vmid, sub {
5830 # only reboot if running, as qmeventd starts it again on a stop event
5831 return if !check_running
($vmid);
5833 create_reboot_request
($vmid);
5835 my $storecfg = PVE
::Storage
::config
();
5836 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5840 # avoid that the next normal shutdown will be confused for a reboot
5841 clear_reboot_request
($vmid);
5847 # note: if using the statestorage parameter, the caller has to check privileges
5849 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5856 PVE
::QemuConfig-
>lock_config($vmid, sub {
5858 $conf = PVE
::QemuConfig-
>load_config($vmid);
5860 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5861 PVE
::QemuConfig-
>check_lock($conf)
5862 if !($skiplock || $is_backing_up);
5864 die "cannot suspend to disk during backup\n"
5865 if $is_backing_up && $includestate;
5867 if ($includestate) {
5868 $conf->{lock} = 'suspending';
5869 my $date = strftime
("%Y-%m-%d", localtime(time()));
5870 $storecfg = PVE
::Storage
::config
();
5871 if (!$statestorage) {
5872 $statestorage = find_vmstate_storage
($conf, $storecfg);
5873 # check permissions for the storage
5874 my $rpcenv = PVE
::RPCEnvironment
::get
();
5875 if ($rpcenv->{type
} ne 'cli') {
5876 my $authuser = $rpcenv->get_user();
5877 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5882 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate(
5883 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5884 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5885 PVE
::QemuConfig-
>write_config($vmid, $conf);
5887 mon_cmd
($vmid, "stop");
5891 if ($includestate) {
5893 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5896 set_migration_caps
($vmid, 1);
5897 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5899 my $state = mon_cmd
($vmid, "query-savevm");
5900 if (!$state->{status
}) {
5901 die "savevm not active\n";
5902 } elsif ($state->{status
} eq 'active') {
5905 } elsif ($state->{status
} eq 'completed') {
5906 print "State saved, quitting\n";
5908 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5909 die "query-savevm failed with error '$state->{error}'\n"
5911 die "query-savevm returned status '$state->{status}'\n";
5917 PVE
::QemuConfig-
>lock_config($vmid, sub {
5918 $conf = PVE
::QemuConfig-
>load_config($vmid);
5920 # cleanup, but leave suspending lock, to indicate something went wrong
5922 mon_cmd
($vmid, "savevm-end");
5923 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5924 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5925 delete $conf->@{qw(vmstate runningmachine runningcpu)};
5926 PVE
::QemuConfig-
>write_config($vmid, $conf);
5932 die "lock changed unexpectedly\n"
5933 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5935 mon_cmd
($vmid, "quit");
5936 $conf->{lock} = 'suspended';
5937 PVE
::QemuConfig-
>write_config($vmid, $conf);
5943 my ($vmid, $skiplock, $nocheck) = @_;
5945 PVE
::QemuConfig-
>lock_config($vmid, sub {
5946 my $res = mon_cmd
($vmid, 'query-status');
5947 my $resume_cmd = 'cont';
5950 if ($res->{status
}) {
5951 return if $res->{status
} eq 'running'; # job done, go home
5952 $resume_cmd = 'system_wakeup' if $res->{status
} eq 'suspended';
5953 $reset = 1 if $res->{status
} eq 'shutdown';
5958 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5960 PVE
::QemuConfig-
>check_lock($conf)
5961 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5965 # required if a VM shuts down during a backup and we get a resume
5966 # request before the backup finishes for example
5967 mon_cmd
($vmid, "system_reset");
5969 mon_cmd
($vmid, $resume_cmd);
5974 my ($vmid, $skiplock, $key) = @_;
5976 PVE
::QemuConfig-
>lock_config($vmid, sub {
5978 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5980 # there is no qmp command, so we use the human monitor command
5981 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5982 die $res if $res ne '';
5986 # vzdump restore implementaion
5988 sub tar_archive_read_firstfile
{
5989 my $archive = shift;
5991 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5993 # try to detect archive type first
5994 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5995 die "unable to open file '$archive'\n";
5996 my $firstfile = <$fh>;
6000 die "ERROR: archive contaions no data\n" if !$firstfile;
6006 sub tar_restore_cleanup
{
6007 my ($storecfg, $statfile) = @_;
6009 print STDERR
"starting cleanup\n";
6011 if (my $fd = IO
::File-
>new($statfile, "r")) {
6012 while (defined(my $line = <$fd>)) {
6013 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6016 if ($volid =~ m
|^/|) {
6017 unlink $volid || die 'unlink failed\n';
6019 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6021 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6023 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6025 print STDERR
"unable to parse line in statfile - $line";
6032 sub restore_file_archive
{
6033 my ($archive, $vmid, $user, $opts) = @_;
6035 return restore_vma_archive
($archive, $vmid, $user, $opts)
6038 my $info = PVE
::Storage
::archive_info
($archive);
6039 my $format = $opts->{format
} // $info->{format
};
6040 my $comp = $info->{compression
};
6042 # try to detect archive format
6043 if ($format eq 'tar') {
6044 return restore_tar_archive
($archive, $vmid, $user, $opts);
6046 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
6050 # hepler to remove disks that will not be used after restore
6051 my $restore_cleanup_oldconf = sub {
6052 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6054 PVE
::QemuConfig-
>foreach_volume($oldconf, sub {
6055 my ($ds, $drive) = @_;
6057 return if drive_is_cdrom
($drive, 1);
6059 my $volid = $drive->{file
};
6060 return if !$volid || $volid =~ m
|^/|;
6062 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
6063 return if !$path || !$owner || ($owner != $vmid);
6065 # Note: only delete disk we want to restore
6066 # other volumes will become unused
6067 if ($virtdev_hash->{$ds}) {
6068 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
6075 # delete vmstate files, after the restore we have no snapshots anymore
6076 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6077 my $snap = $oldconf->{snapshots
}->{$snapname};
6078 if ($snap->{vmstate
}) {
6079 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
6087 # Helper to parse vzdump backup device hints
6089 # $rpcenv: Environment, used to ckeck storage permissions
6090 # $user: User ID, to check storage permissions
6091 # $storecfg: Storage configuration
6092 # $fh: the file handle for reading the configuration
6093 # $devinfo: should contain device sizes for all backu-up'ed devices
6094 # $options: backup options (pool, default storage)
6096 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6097 my $parse_backup_hints = sub {
6098 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
6100 my $virtdev_hash = {};
6102 while (defined(my $line = <$fh>)) {
6103 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6104 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6105 die "archive does not contain data for drive '$virtdev'\n"
6106 if !$devinfo->{$devname};
6108 if (defined($options->{storage
})) {
6109 $storeid = $options->{storage
} || 'local';
6110 } elsif (!$storeid) {
6113 $format = 'raw' if !$format;
6114 $devinfo->{$devname}->{devname
} = $devname;
6115 $devinfo->{$devname}->{virtdev
} = $virtdev;
6116 $devinfo->{$devname}->{format
} = $format;
6117 $devinfo->{$devname}->{storeid
} = $storeid;
6119 # check permission on storage
6120 my $pool = $options->{pool
}; # todo: do we need that?
6121 if ($user ne 'root@pam') {
6122 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6125 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6126 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6128 my $drive = parse_drive
($virtdev, $2);
6129 if (drive_is_cloudinit
($drive)) {
6130 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6131 $storeid = $options->{storage
} if defined ($options->{storage
});
6132 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6133 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
6135 $virtdev_hash->{$virtdev} = {
6137 storeid
=> $storeid,
6138 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6145 return $virtdev_hash;
6148 # Helper to allocate and activate all volumes required for a restore
6150 # $storecfg: Storage configuration
6151 # $virtdev_hash: as returned by parse_backup_hints()
6153 # Returns: { $virtdev => $volid }
6154 my $restore_allocate_devices = sub {
6155 my ($storecfg, $virtdev_hash, $vmid) = @_;
6158 foreach my $virtdev (sort keys %$virtdev_hash) {
6159 my $d = $virtdev_hash->{$virtdev};
6160 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6161 my $storeid = $d->{storeid
};
6162 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6164 # test if requested format is supported
6165 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6166 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6167 $d->{format
} = $defFormat if !$supported;
6170 if ($d->{is_cloudinit
}) {
6171 $name = "vm-$vmid-cloudinit";
6172 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6173 if ($scfg->{path
}) {
6174 $name .= ".$d->{format}";
6178 my $volid = PVE
::Storage
::vdisk_alloc
(
6179 $storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6181 print STDERR
"new volume ID is '$volid'\n";
6182 $d->{volid
} = $volid;
6184 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6186 $map->{$virtdev} = $volid;
6192 sub restore_update_config_line
{
6193 my ($cookie, $map, $line, $unique) = @_;
6195 return '' if $line =~ m/^\#qmdump\#/;
6196 return '' if $line =~ m/^\#vzdump\#/;
6197 return '' if $line =~ m/^lock:/;
6198 return '' if $line =~ m/^unused\d+:/;
6199 return '' if $line =~ m/^parent:/;
6203 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
6204 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6205 # try to convert old 1.X settings
6206 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6207 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
6208 my ($model, $macaddr) = split(/\=/, $devconfig);
6209 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
6212 bridge
=> "vmbr$ind",
6213 macaddr
=> $macaddr,
6215 my $netstr = print_net
($net);
6217 $res .= "net$cookie->{netcount}: $netstr\n";
6218 $cookie->{netcount
}++;
6220 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6221 my ($id, $netstr) = ($1, $2);
6222 my $net = parse_net
($netstr);
6223 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
6224 $netstr = print_net
($net);
6225 $res .= "$id: $netstr\n";
6226 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
6229 my $di = parse_drive
($virtdev, $value);
6230 if (defined($di->{backup
}) && !$di->{backup
}) {
6232 } elsif ($map->{$virtdev}) {
6233 delete $di->{format
}; # format can change on restore
6234 $di->{file
} = $map->{$virtdev};
6235 $value = print_drive
($di);
6236 $res .= "$virtdev: $value\n";
6240 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6242 if ($vmgenid ne '0') {
6243 # always generate a new vmgenid if there was a valid one setup
6244 $vmgenid = generate_uuid
();
6246 $res .= "vmgenid: $vmgenid\n";
6247 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6248 my ($uuid, $uuid_str);
6249 UUID
::generate
($uuid);
6250 UUID
::unparse
($uuid, $uuid_str);
6251 my $smbios1 = parse_smbios1
($2);
6252 $smbios1->{uuid
} = $uuid_str;
6253 $res .= $1.print_smbios1
($smbios1)."\n";
6261 my $restore_deactivate_volumes = sub {
6262 my ($storecfg, $devinfo) = @_;
6265 foreach my $devname (keys %$devinfo) {
6266 my $volid = $devinfo->{$devname}->{volid
};
6267 push @$vollist, $volid if $volid;
6270 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
6273 my $restore_destroy_volumes = sub {
6274 my ($storecfg, $devinfo) = @_;
6276 foreach my $devname (keys %$devinfo) {
6277 my $volid = $devinfo->{$devname}->{volid
};
6280 if ($volid =~ m
|^/|) {
6281 unlink $volid || die 'unlink failed\n';
6283 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6285 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6287 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6292 my ($cfg, $vmid) = @_;
6294 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid, undef, 'images');
6296 my $volid_hash = {};
6297 foreach my $storeid (keys %$info) {
6298 foreach my $item (@{$info->{$storeid}}) {
6299 next if !($item->{volid
} && $item->{size
});
6300 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6301 $volid_hash->{$item->{volid
}} = $item;
6308 sub update_disk_config
{
6309 my ($vmid, $conf, $volid_hash) = @_;
6312 my $prefix = "VM $vmid";
6314 # used and unused disks
6315 my $referenced = {};
6317 # Note: it is allowed to define multiple storages with same path (alias), so
6318 # we need to check both 'volid' and real 'path' (two different volid can point
6319 # to the same path).
6321 my $referencedpath = {};
6324 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6325 my ($opt, $drive) = @_;
6327 my $volid = $drive->{file
};
6329 my $volume = $volid_hash->{$volid};
6331 # mark volid as "in-use" for next step
6332 $referenced->{$volid} = 1;
6333 if ($volume && (my $path = $volume->{path
})) {
6334 $referencedpath->{$path} = 1;
6337 return if drive_is_cdrom
($drive);
6340 my ($updated, $msg) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volume->{size
});
6341 if (defined($updated)) {
6343 $conf->{$opt} = print_drive
($updated);
6344 print "$prefix ($opt): $msg\n";
6348 # remove 'unusedX' entry if volume is used
6349 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
6350 my ($opt, $drive) = @_;
6352 my $volid = $drive->{file
};
6356 $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6357 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6358 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
6360 delete $conf->{$opt};
6363 $referenced->{$volid} = 1;
6364 $referencedpath->{$path} = 1 if $path;
6367 foreach my $volid (sort keys %$volid_hash) {
6368 next if $volid =~ m/vm-$vmid-state-/;
6369 next if $referenced->{$volid};
6370 my $path = $volid_hash->{$volid}->{path
};
6371 next if !$path; # just to be sure
6372 next if $referencedpath->{$path};
6374 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6375 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
6376 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6383 my ($vmid, $nolock, $dryrun) = @_;
6385 my $cfg = PVE
::Storage
::config
();
6387 print "rescan volumes...\n";
6388 my $volid_hash = scan_volids
($cfg, $vmid);
6390 my $updatefn = sub {
6393 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6395 PVE
::QemuConfig-
>check_lock($conf);
6398 foreach my $volid (keys %$volid_hash) {
6399 my $info = $volid_hash->{$volid};
6400 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6403 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
6405 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6408 if (defined($vmid)) {
6412 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6415 my $vmlist = config_list
();
6416 foreach my $vmid (keys %$vmlist) {
6420 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6426 sub restore_proxmox_backup_archive
{
6427 my ($archive, $vmid, $user, $options) = @_;
6429 my $storecfg = PVE
::Storage
::config
();
6431 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
6432 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6434 my $fingerprint = $scfg->{fingerprint
};
6435 my $keyfile = PVE
::Storage
::PBSPlugin
::pbs_encryption_key_file_name
($storecfg, $storeid);
6437 my $repo = PVE
::PBSClient
::get_repository
($scfg);
6439 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
6440 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
6441 local $ENV{PBS_PASSWORD
} = $password;
6442 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
6444 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6445 PVE
::Storage
::parse_volname
($storecfg, $archive);
6447 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6449 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6451 my $tmpdir = "/var/tmp/vzdumptmp$$";
6455 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6456 # disable interrupts (always do cleanups)
6460 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6462 # Note: $oldconf is undef if VM does not exists
6463 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6464 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6465 my $new_conf_raw = '';
6467 my $rpcenv = PVE
::RPCEnvironment
::get
();
6476 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6478 my $cfgfn = "$tmpdir/qemu-server.conf";
6479 my $firewall_config_fn = "$tmpdir/fw.conf";
6480 my $index_fn = "$tmpdir/index.json";
6482 my $cmd = "restore";
6484 my $param = [$pbs_backup_name, "index.json", $index_fn];
6485 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6486 my $index = PVE
::Tools
::file_get_contents
($index_fn);
6487 $index = decode_json
($index);
6489 # print Dumper($index);
6490 foreach my $info (@{$index->{files
}}) {
6491 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
6493 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
6494 $devinfo->{$devname}->{size
} = $1;
6496 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6501 my $is_qemu_server_backup = scalar(
6502 grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}}
6504 if (!$is_qemu_server_backup) {
6505 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6507 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
6509 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6510 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6512 if ($has_firewall_config) {
6513 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6514 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6516 my $pve_firewall_dir = '/etc/pve/firewall';
6517 mkdir $pve_firewall_dir; # make sure the dir exists
6518 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6521 my $fh = IO
::File-
>new($cfgfn, "r") ||
6522 die "unable to read qemu-server.conf - $!\n";
6524 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6526 # fixme: rate limit?
6528 # create empty/temp config
6529 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6531 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6534 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6536 foreach my $virtdev (sort keys %$virtdev_hash) {
6537 my $d = $virtdev_hash->{$virtdev};
6538 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6540 # this fails if storage is unavailable
6541 my $volid = $d->{volid
};
6542 my $path = PVE
::Storage
::path
($storecfg, $volid);
6544 # for live-restore we only want to preload the efidisk and TPM state
6545 next if $options->{live
} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
6547 my $pbs_restore_cmd = [
6548 '/usr/bin/pbs-restore',
6549 '--repository', $repo,
6551 "$d->{devname}.img.fidx",
6556 push @$pbs_restore_cmd, '--format', $d->{format
} if $d->{format
};
6557 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e
$keyfile;
6559 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6560 push @$pbs_restore_cmd, '--skip-zero';
6563 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6564 print "restore proxmox backup image: $dbg_cmdstring\n";
6565 run_command
($pbs_restore_cmd);
6568 $fh->seek(0, 0) || die "seek failed - $!\n";
6570 my $cookie = { netcount
=> 0 };
6571 while (defined(my $line = <$fh>)) {
6572 $new_conf_raw .= restore_update_config_line
(
6584 if ($err || !$options->{live
}) {
6585 $restore_deactivate_volumes->($storecfg, $devinfo);
6591 $restore_destroy_volumes->($storecfg, $devinfo);
6595 if ($options->{live
}) {
6596 # keep lock during live-restore
6597 $new_conf_raw .= "\nlock: create";
6600 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6602 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6604 eval { rescan
($vmid, 1); };
6607 PVE
::AccessControl
::add_vm_to_pool
($vmid, $options->{pool
}) if $options->{pool
};
6609 if ($options->{live
}) {
6615 local $SIG{PIPE
} = sub { die "got signal ($!) - abort\n"; };
6617 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6618 die "cannot do live-restore for template\n" if PVE
::QemuConfig-
>is_template($conf);
6620 # these special drives are already restored before start
6621 delete $devinfo->{'drive-efidisk0'};
6622 delete $devinfo->{'drive-tpmstate0-backup'};
6623 pbs_live_restore
($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
6625 PVE
::QemuConfig-
>remove_lock($vmid, "create");
6629 sub pbs_live_restore
{
6630 my ($vmid, $conf, $storecfg, $restored_disks, $repo, $keyfile, $snap) = @_;
6632 print "starting VM for live-restore\n";
6633 print "repository: '$repo', snapshot: '$snap'\n";
6635 my $pbs_backing = {};
6636 for my $ds (keys %$restored_disks) {
6637 $ds =~ m/^drive-(.*)$/;
6639 $pbs_backing->{$confname} = {
6640 repository
=> $repo,
6642 archive
=> "$ds.img.fidx",
6644 $pbs_backing->{$confname}->{keyfile
} = $keyfile if -e
$keyfile;
6646 my $drive = parse_drive
($confname, $conf->{$confname});
6647 print "restoring '$ds' to '$drive->{file}'\n";
6650 my $drives_streamed = 0;
6652 # make sure HA doesn't interrupt our restore by stopping the VM
6653 if (PVE
::HA
::Config
::vm_is_ha_managed
($vmid)) {
6654 run_command
(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
6657 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6658 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
6659 vm_start_nolock
($storecfg, $vmid, $conf, {paused
=> 1, 'pbs-backing' => $pbs_backing}, {});
6661 my $qmeventd_fd = register_qmeventd_handle
($vmid);
6663 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6664 # this will effectively collapse the backing image chain consisting of
6665 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6666 # removes itself once all backing images vanish with 'auto-remove=on')
6668 for my $ds (sort keys %$restored_disks) {
6669 my $job_id = "restore-$ds";
6670 mon_cmd
($vmid, 'block-stream',
6671 'job-id' => $job_id,
6674 $jobs->{$job_id} = {};
6677 mon_cmd
($vmid, 'cont');
6678 qemu_drive_mirror_monitor
($vmid, undef, $jobs, 'auto', 0, 'stream');
6680 print "restore-drive jobs finished successfully, removing all tracking block devices"
6681 ." to disconnect from Proxmox Backup Server\n";
6683 for my $ds (sort keys %$restored_disks) {
6684 mon_cmd
($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6687 close($qmeventd_fd);
6693 warn "An error occured during live-restore: $err\n";
6694 _do_vm_stop
($storecfg, $vmid, 1, 1, 10, 0, 1);
6695 die "live-restore failed\n";
6699 sub restore_vma_archive
{
6700 my ($archive, $vmid, $user, $opts, $comp) = @_;
6702 my $readfrom = $archive;
6704 my $cfg = PVE
::Storage
::config
();
6706 my $bwlimit = $opts->{bwlimit
};
6708 my $dbg_cmdstring = '';
6709 my $add_pipe = sub {
6711 push @$commands, $cmd;
6712 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6713 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6718 if ($archive eq '-') {
6721 # If we use a backup from a PVE defined storage we also consider that
6722 # storage's rate limit:
6723 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6724 if (defined($volid)) {
6725 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6726 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6728 print STDERR
"applying read rate limit: $readlimit\n";
6729 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6730 $add_pipe->($cstream);
6736 my $info = PVE
::Storage
::decompressor_info
('vma', $comp);
6737 my $cmd = $info->{decompressor
};
6738 push @$cmd, $readfrom;
6742 my $tmpdir = "/var/tmp/vzdumptmp$$";
6745 # disable interrupts (always do cleanups)
6749 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6751 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6752 POSIX
::mkfifo
($mapfifo, 0600);
6754 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
6756 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6763 my $rpcenv = PVE
::RPCEnvironment
::get
();
6765 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6767 # Note: $oldconf is undef if VM does not exist
6768 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6769 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6770 my $new_conf_raw = '';
6774 my $print_devmap = sub {
6775 my $cfgfn = "$tmpdir/qemu-server.conf";
6777 # we can read the config - that is already extracted
6778 my $fh = IO
::File-
>new($cfgfn, "r") ||
6779 die "unable to read qemu-server.conf - $!\n";
6781 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6783 my $pve_firewall_dir = '/etc/pve/firewall';
6784 mkdir $pve_firewall_dir; # make sure the dir exists
6785 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6788 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6790 foreach my $info (values %{$virtdev_hash}) {
6791 my $storeid = $info->{storeid
};
6792 next if defined($storage_limits{$storeid});
6794 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$storeid], $bwlimit) // 0;
6795 print STDERR
"rate limit for storage $storeid: $limit KiB/s\n" if $limit;
6796 $storage_limits{$storeid} = $limit * 1024;
6799 foreach my $devname (keys %$devinfo) {
6800 die "found no device mapping information for device '$devname'\n"
6801 if !$devinfo->{$devname}->{virtdev
};
6804 # create empty/temp config
6806 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6807 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6811 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6813 # print restore information to $fifofh
6814 foreach my $virtdev (sort keys %$virtdev_hash) {
6815 my $d = $virtdev_hash->{$virtdev};
6816 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6818 my $storeid = $d->{storeid
};
6819 my $volid = $d->{volid
};
6822 if (my $limit = $storage_limits{$storeid}) {
6823 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6826 my $write_zeros = 1;
6827 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6831 my $path = PVE
::Storage
::path
($cfg, $volid);
6833 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6835 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6838 $fh->seek(0, 0) || die "seek failed - $!\n";
6840 my $cookie = { netcount
=> 0 };
6841 while (defined(my $line = <$fh>)) {
6842 $new_conf_raw .= restore_update_config_line
(
6859 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6860 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6862 $oldtimeout = alarm($timeout);
6869 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6870 my ($dev_id, $size, $devname) = ($1, $2, $3);
6871 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6872 } elsif ($line =~ m/^CTIME: /) {
6873 # we correctly received the vma config, so we can disable
6874 # the timeout now for disk allocation (set to 10 minutes, so
6875 # that we always timeout if something goes wrong)
6878 print $fifofh "done\n";
6879 my $tmp = $oldtimeout || 0;
6880 $oldtimeout = undef;
6887 print "restore vma archive: $dbg_cmdstring\n";
6888 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6892 alarm($oldtimeout) if $oldtimeout;
6894 $restore_deactivate_volumes->($cfg, $devinfo);
6896 close($fifofh) if $fifofh;
6901 $restore_destroy_volumes->($cfg, $devinfo);
6905 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6907 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6909 eval { rescan
($vmid, 1); };
6912 PVE
::AccessControl
::add_vm_to_pool
($vmid, $opts->{pool
}) if $opts->{pool
};
6915 sub restore_tar_archive
{
6916 my ($archive, $vmid, $user, $opts) = @_;
6918 if ($archive ne '-') {
6919 my $firstfile = tar_archive_read_firstfile
($archive);
6920 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
6921 if $firstfile ne 'qemu-server.conf';
6924 my $storecfg = PVE
::Storage
::config
();
6926 # avoid zombie disks when restoring over an existing VM -> cleanup first
6927 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6928 # skiplock=1 because qmrestore has set the 'create' lock itself already
6929 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6930 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6932 my $tocmd = "/usr/lib/qemu-server/qmextract";
6934 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6935 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6936 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6937 $tocmd .= ' --info' if $opts->{info
};
6939 # tar option "xf" does not autodetect compression when read from STDIN,
6940 # so we pipe to zcat
6941 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6942 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6944 my $tmpdir = "/var/tmp/vzdumptmp$$";
6947 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6948 local $ENV{VZDUMP_VMID
} = $vmid;
6949 local $ENV{VZDUMP_USER
} = $user;
6951 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6952 my $new_conf_raw = '';
6954 # disable interrupts (always do cleanups)
6958 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6966 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6968 if ($archive eq '-') {
6969 print "extracting archive from STDIN\n";
6970 run_command
($cmd, input
=> "<&STDIN");
6972 print "extracting archive '$archive'\n";
6976 return if $opts->{info
};
6980 my $statfile = "$tmpdir/qmrestore.stat";
6981 if (my $fd = IO
::File-
>new($statfile, "r")) {
6982 while (defined (my $line = <$fd>)) {
6983 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6984 $map->{$1} = $2 if $1;
6986 print STDERR
"unable to parse line in statfile - $line\n";
6992 my $confsrc = "$tmpdir/qemu-server.conf";
6994 my $srcfd = IO
::File-
>new($confsrc, "r") || die "unable to open file '$confsrc'\n";
6996 my $cookie = { netcount
=> 0 };
6997 while (defined (my $line = <$srcfd>)) {
6998 $new_conf_raw .= restore_update_config_line
(
7009 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
7015 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
7017 PVE
::Cluster
::cfs_update
(); # make sure we read new file
7019 eval { rescan
($vmid, 1); };
7023 sub foreach_storage_used_by_vm
{
7024 my ($conf, $func) = @_;
7028 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7029 my ($ds, $drive) = @_;
7030 return if drive_is_cdrom
($drive);
7032 my $volid = $drive->{file
};
7034 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
7035 $sidhash->{$sid} = $sid if $sid;
7038 foreach my $sid (sort keys %$sidhash) {
7043 my $qemu_snap_storage = {
7046 sub do_snapshots_with_qemu
{
7047 my ($storecfg, $volid, $deviceid) = @_;
7049 return if $deviceid =~ m/tpmstate0/;
7051 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
7052 my $scfg = $storecfg->{ids
}->{$storage_name};
7053 die "could not find storage '$storage_name'\n" if !defined($scfg);
7055 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
7059 if ($volid =~ m/\.(qcow2|qed)$/){
7066 sub qga_check_running
{
7067 my ($vmid, $nowarn) = @_;
7069 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
7071 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
7077 sub template_create
{
7078 my ($vmid, $conf, $disk) = @_;
7080 my $storecfg = PVE
::Storage
::config
();
7082 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7083 my ($ds, $drive) = @_;
7085 return if drive_is_cdrom
($drive);
7086 return if $disk && $ds ne $disk;
7088 my $volid = $drive->{file
};
7089 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
7091 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
7092 $drive->{file
} = $voliddst;
7093 $conf->{$ds} = print_drive
($drive);
7094 PVE
::QemuConfig-
>write_config($vmid, $conf);
7098 sub convert_iscsi_path
{
7101 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
7106 my $initiator_name = get_initiator_name
();
7108 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7109 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7112 die "cannot convert iscsi path '$path', unkown format\n";
7115 sub qemu_img_convert
{
7116 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
7118 my $storecfg = PVE
::Storage
::config
();
7119 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
7120 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
7122 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
7126 my $src_is_iscsi = 0;
7130 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
7131 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
7132 $src_format = qemu_img_format
($src_scfg, $src_volname);
7133 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
7134 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
7135 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
7136 } elsif (-f
$src_volid) {
7137 $src_path = $src_volid;
7138 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7143 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
7145 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7146 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
7147 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7148 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
7151 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
7152 push @$cmd, '-l', "snapshot.name=$snapname"
7153 if $snapname && $src_format && $src_format eq "qcow2";
7154 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
7155 push @$cmd, '-T', $cachemode if defined($cachemode);
7157 if ($src_is_iscsi) {
7158 push @$cmd, '--image-opts';
7159 $src_path = convert_iscsi_path
($src_path);
7160 } elsif ($src_format) {
7161 push @$cmd, '-f', $src_format;
7164 if ($dst_is_iscsi) {
7165 push @$cmd, '--target-image-opts';
7166 $dst_path = convert_iscsi_path
($dst_path);
7168 push @$cmd, '-O', $dst_format;
7171 push @$cmd, $src_path;
7173 if (!$dst_is_iscsi && $is_zero_initialized) {
7174 push @$cmd, "zeroinit:$dst_path";
7176 push @$cmd, $dst_path;
7181 if($line =~ m/\((\S+)\/100\
%\)/){
7183 my $transferred = int($size * $percent / 100);
7184 my $total_h = render_bytes
($size, 1);
7185 my $transferred_h = render_bytes
($transferred, 1);
7187 print "transferred $transferred_h of $total_h ($percent%)\n";
7192 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
7194 die "copy failed: $err" if $err;
7197 sub qemu_img_format
{
7198 my ($scfg, $volname) = @_;
7200 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7207 sub qemu_drive_mirror
{
7208 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
7210 $jobs = {} if !$jobs;
7214 $jobs->{"drive-$drive"} = {};
7216 if ($dst_volid =~ /^nbd:/) {
7217 $qemu_target = $dst_volid;
7220 my $storecfg = PVE
::Storage
::config
();
7221 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
7223 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7225 $format = qemu_img_format
($dst_scfg, $dst_volname);
7227 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7229 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
7232 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
7233 $opts->{format
} = $format if $format;
7235 if (defined($src_bitmap)) {
7236 $opts->{sync
} = 'incremental';
7237 $opts->{bitmap
} = $src_bitmap;
7238 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7241 if (defined($bwlimit)) {
7242 $opts->{speed
} = $bwlimit * 1024;
7243 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
7245 print "drive mirror is starting for drive-$drive\n";
7248 # if a job already runs for this device we get an error, catch it for cleanup
7249 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
7251 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7253 die "mirroring error: $err\n";
7256 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
7259 # $completion can be either
7260 # 'complete': wait until all jobs are ready, block-job-complete them (default)
7261 # 'cancel': wait until all jobs are ready, block-job-cancel them
7262 # 'skip': wait until all jobs are ready, return with block jobs in ready state
7263 # 'auto': wait until all jobs disappear, only use for jobs which complete automatically
7264 sub qemu_drive_mirror_monitor
{
7265 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
7267 $completion //= 'complete';
7271 my $err_complete = 0;
7273 my $starttime = time ();
7275 die "block job ('$op') timed out\n" if $err_complete > 300;
7277 my $stats = mon_cmd
($vmid, "query-block-jobs");
7280 my $running_jobs = {};
7281 for my $stat (@$stats) {
7282 next if $stat->{type
} ne $op;
7283 $running_jobs->{$stat->{device
}} = $stat;
7286 my $readycounter = 0;
7288 for my $job_id (sort keys %$jobs) {
7289 my $job = $running_jobs->{$job_id};
7291 my $vanished = !defined($job);
7292 my $complete = defined($jobs->{$job_id}->{complete
}) && $vanished;
7293 if($complete || ($vanished && $completion eq 'auto')) {
7294 print "$job_id: $op-job finished\n";
7295 delete $jobs->{$job_id};
7299 die "$job_id: '$op' has been cancelled\n" if !defined($job);
7301 my $busy = $job->{busy
};
7302 my $ready = $job->{ready
};
7303 if (my $total = $job->{len
}) {
7304 my $transferred = $job->{offset
} || 0;
7305 my $remaining = $total - $transferred;
7306 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
7308 my $duration = $ctime - $starttime;
7309 my $total_h = render_bytes
($total, 1);
7310 my $transferred_h = render_bytes
($transferred, 1);
7312 my $status = sprintf(
7313 "transferred $transferred_h of $total_h ($percent%%) in %s",
7314 render_duration
($duration),
7319 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7321 $status .= ", ready";
7324 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready
};
7325 $jobs->{$job_id}->{ready
} = $ready;
7328 $readycounter++ if $job->{ready
};
7331 last if scalar(keys %$jobs) == 0;
7333 if ($readycounter == scalar(keys %$jobs)) {
7334 print "all '$op' jobs are ready\n";
7336 # do the complete later (or has already been done)
7337 last if $completion eq 'skip' || $completion eq 'auto';
7339 if ($vmiddst && $vmiddst != $vmid) {
7340 my $agent_running = $qga && qga_check_running
($vmid);
7341 if ($agent_running) {
7342 print "freeze filesystem\n";
7343 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
7345 print "suspend vm\n";
7346 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
7349 # if we clone a disk for a new target vm, we don't switch the disk
7350 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
7352 if ($agent_running) {
7353 print "unfreeze filesystem\n";
7354 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
7356 print "resume vm\n";
7357 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
7363 for my $job_id (sort keys %$jobs) {
7364 # try to switch the disk if source and destination are on the same guest
7365 print "$job_id: Completing block job_id...\n";
7368 if ($completion eq 'complete') {
7369 $op = 'block-job-complete';
7370 } elsif ($completion eq 'cancel') {
7371 $op = 'block-job-cancel';
7373 die "invalid completion value: $completion\n";
7375 eval { mon_cmd
($vmid, $op, device
=> $job_id) };
7376 if ($@ =~ m/cannot be completed/) {
7377 print "$job_id: block job cannot be completed, trying again.\n";
7380 print "$job_id: Completed successfully.\n";
7381 $jobs->{$job_id}->{complete
} = 1;
7392 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7393 die "block job ($op) error: $err";
7397 sub qemu_blockjobs_cancel
{
7398 my ($vmid, $jobs) = @_;
7400 foreach my $job (keys %$jobs) {
7401 print "$job: Cancelling block job\n";
7402 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
7403 $jobs->{$job}->{cancel
} = 1;
7407 my $stats = mon_cmd
($vmid, "query-block-jobs");
7409 my $running_jobs = {};
7410 foreach my $stat (@$stats) {
7411 $running_jobs->{$stat->{device
}} = $stat;
7414 foreach my $job (keys %$jobs) {
7416 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
7417 print "$job: Done.\n";
7418 delete $jobs->{$job};
7422 last if scalar(keys %$jobs) == 0;
7429 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7430 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
7435 print "create linked clone of drive $drivename ($drive->{file})\n";
7436 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
7437 push @$newvollist, $newvolid;
7440 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7441 $storeid = $storage if $storage;
7443 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7445 print "create full clone of drive $drivename ($drive->{file})\n";
7448 if (drive_is_cloudinit
($drive)) {
7449 $name = "vm-$newvmid-cloudinit";
7450 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7451 if ($scfg->{path
}) {
7452 $name .= ".$dst_format";
7455 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
7456 } elsif ($drivename eq 'efidisk0') {
7457 $size = get_efivars_size
($conf);
7458 } elsif ($drivename eq 'tpmstate0') {
7459 $size = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
7461 ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 10);
7463 $newvolid = PVE
::Storage
::vdisk_alloc
(
7464 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7466 push @$newvollist, $newvolid;
7468 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7470 if (drive_is_cloudinit
($drive)) {
7471 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7472 # if this is the case, we have to complete any block-jobs still there from
7473 # previous drive-mirrors
7474 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7475 qemu_drive_mirror_monitor
($vmid, $newvmid, $jobs, $completion, $qga);
7480 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7481 if (!$running || $snapname) {
7482 # TODO: handle bwlimits
7483 if ($drivename eq 'efidisk0') {
7484 # the relevant data on the efidisk may be smaller than the source
7485 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7486 # that is given by the OVMF_VARS.fd
7487 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
7488 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
7490 # better for Ceph if block size is not too small, see bug #3324
7493 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=$bs", "osize=$size",
7494 "if=$src_path", "of=$dst_path"]);
7496 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7500 die "cannot move TPM state while VM is running\n" if $drivename eq 'tpmstate0';
7502 my $kvmver = get_running_qemu_version
($vmid);
7503 if (!min_version
($kvmver, 2, 7)) {
7504 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7505 if $drive->{iothread
};
7508 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7509 $completion, $qga, $bwlimit);
7514 my ($size) = eval { PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 10) };
7517 $disk->{format
} = undef;
7518 $disk->{file
} = $newvolid;
7519 $disk->{size
} = $size if defined($size);
7524 sub get_running_qemu_version
{
7526 my $res = mon_cmd
($vmid, "query-version");
7527 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7530 sub qemu_use_old_bios_files
{
7531 my ($machine_type) = @_;
7533 return if !$machine_type;
7535 my $use_old_bios_files = undef;
7537 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7539 $use_old_bios_files = 1;
7541 my $version = extract_version
($machine_type, kvm_user_version
());
7542 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7543 # load new efi bios files on migration. So this hack is required to allow
7544 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7545 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7546 $use_old_bios_files = !min_version
($version, 2, 4);
7549 return ($use_old_bios_files, $machine_type);
7552 sub get_efivars_size
{
7554 my $arch = get_vm_arch
($conf);
7555 my $efidisk = $conf->{efidisk0
} ? parse_drive
('efidisk0', $conf->{efidisk0
}) : undef;
7556 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk);
7557 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
7558 return -s
$ovmf_vars;
7561 sub update_efidisk_size
{
7564 return if !defined($conf->{efidisk0
});
7566 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
7567 $disk->{size
} = get_efivars_size
($conf);
7568 $conf->{efidisk0
} = print_drive
($disk);
7573 sub update_tpmstate_size
{
7576 my $disk = PVE
::QemuServer
::parse_drive
('tpmstate0', $conf->{tpmstate0
});
7577 $disk->{size
} = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
7578 $conf->{tpmstate0
} = print_drive
($disk);
7581 sub create_efidisk
($$$$$$) {
7582 my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk) = @_;
7584 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk);
7585 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7587 my $vars_size_b = -s
$ovmf_vars;
7588 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
7589 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7590 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7592 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
7593 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
7595 return ($volid, $size/1024);
7598 sub vm_iothreads_list
{
7601 my $res = mon_cmd
($vmid, 'query-iothreads');
7604 foreach my $iothread (@$res) {
7605 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7612 my ($conf, $drive) = @_;
7616 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7618 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7624 my $controller = int($drive->{index} / $maxdev);
7625 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single')
7629 return ($maxdev, $controller, $controller_prefix);
7632 sub windows_version
{
7635 return 0 if !$ostype;
7639 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7641 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7643 } elsif ($ostype =~ m/^win(\d+)$/) {
7650 sub resolve_dst_disk_format
{
7651 my ($storecfg, $storeid, $src_volname, $format) = @_;
7652 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7655 # if no target format is specified, use the source disk format as hint
7657 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7658 $format = qemu_img_format
($scfg, $src_volname);
7664 # test if requested format is supported - else use default
7665 my $supported = grep { $_ eq $format } @$validFormats;
7666 $format = $defFormat if !$supported;
7670 # NOTE: if this logic changes, please update docs & possibly gui logic
7671 sub find_vmstate_storage
{
7672 my ($conf, $storecfg) = @_;
7674 # first, return storage from conf if set
7675 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
7677 my ($target, $shared, $local);
7679 foreach_storage_used_by_vm
($conf, sub {
7681 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7682 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7683 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7686 # second, use shared storage where VM has at least one disk
7687 # third, use local storage where VM has at least one disk
7688 # fall back to local storage
7689 $target = $shared // $local // 'local';
7695 my ($uuid, $uuid_str);
7696 UUID
::generate
($uuid);
7697 UUID
::unparse
($uuid, $uuid_str);
7701 sub generate_smbios1_uuid
{
7702 return "uuid=".generate_uuid
();
7708 mon_cmd
($vmid, 'nbd-server-stop');
7711 sub create_reboot_request
{
7713 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7714 or die "failed to create reboot trigger file: $!\n";
7718 sub clear_reboot_request
{
7720 my $path = "/run/qemu-server/$vmid.reboot";
7723 $res = unlink($path);
7724 die "could not remove reboot request for $vmid: $!"
7725 if !$res && $! != POSIX
::ENOENT
;
7730 sub bootorder_from_legacy
{
7731 my ($conf, $bootcfg) = @_;
7733 my $boot = $bootcfg->{legacy
} || $boot_fmt->{legacy
}->{default};
7734 my $bootindex_hash = {};
7736 foreach my $o (split(//, $boot)) {
7737 $bootindex_hash->{$o} = $i*100;
7743 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7744 my ($ds, $drive) = @_;
7746 if (drive_is_cdrom
($drive, 1)) {
7747 if ($bootindex_hash->{d
}) {
7748 $bootorder->{$ds} = $bootindex_hash->{d
};
7749 $bootindex_hash->{d
} += 1;
7751 } elsif ($bootindex_hash->{c
}) {
7752 $bootorder->{$ds} = $bootindex_hash->{c
}
7753 if $conf->{bootdisk
} && $conf->{bootdisk
} eq $ds;
7754 $bootindex_hash->{c
} += 1;
7758 if ($bootindex_hash->{n
}) {
7759 for (my $i = 0; $i < $MAX_NETS; $i++) {
7760 my $netname = "net$i";
7761 next if !$conf->{$netname};
7762 $bootorder->{$netname} = $bootindex_hash->{n
};
7763 $bootindex_hash->{n
} += 1;
7770 # Generate default device list for 'boot: order=' property. Matches legacy
7771 # default boot order, but with explicit device names. This is important, since
7772 # the fallback for when neither 'order' nor the old format is specified relies
7773 # on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
7774 sub get_default_bootdevices
{
7780 my $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 0);
7781 push @ret, $first if $first;
7784 $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 1);
7785 push @ret, $first if $first;
7788 for (my $i = 0; $i < $MAX_NETS; $i++) {
7789 my $netname = "net$i";
7790 next if !$conf->{$netname};
7791 push @ret, $netname;
7798 sub device_bootorder
{
7801 return bootorder_from_legacy
($conf) if !defined($conf->{boot
});
7803 my $boot = parse_property_string
($boot_fmt, $conf->{boot
});
7806 if (!defined($boot) || $boot->{legacy
}) {
7807 $bootorder = bootorder_from_legacy
($conf, $boot);
7808 } elsif ($boot->{order
}) {
7809 my $i = 100; # start at 100 to allow user to insert devices before us with -args
7810 for my $dev (PVE
::Tools
::split_list
($boot->{order
})) {
7811 $bootorder->{$dev} = $i++;
7818 sub register_qmeventd_handle
{
7822 my $peer = "/var/run/qmeventd.sock";
7827 $fh = IO
::Socket
::UNIX-
>new(Peer
=> $peer, Blocking
=> 0, Timeout
=> 1);
7829 if ($! != EINTR
&& $! != EAGAIN
) {
7830 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
7833 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
7834 . "after $count retries\n";
7839 # send handshake to mark VM as backing up
7840 print $fh to_json
({vzdump
=> {vmid
=> "$vmid"}});
7842 # return handle to be closed later when inhibit is no longer required
7846 # bash completion helper
7848 sub complete_backup_archives
{
7849 my ($cmdname, $pname, $cvalue) = @_;
7851 my $cfg = PVE
::Storage
::config
();
7855 if ($cvalue =~ m/^([^:]+):/) {
7859 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7862 foreach my $id (keys %$data) {
7863 foreach my $item (@{$data->{$id}}) {
7864 next if $item->{format
} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
7865 push @$res, $item->{volid
} if defined($item->{volid
});
7872 my $complete_vmid_full = sub {
7875 my $idlist = vmstatus
();
7879 foreach my $id (keys %$idlist) {
7880 my $d = $idlist->{$id};
7881 if (defined($running)) {
7882 next if $d->{template
};
7883 next if $running && $d->{status
} ne 'running';
7884 next if !$running && $d->{status
} eq 'running';
7893 return &$complete_vmid_full();
7896 sub complete_vmid_stopped
{
7897 return &$complete_vmid_full(0);
7900 sub complete_vmid_running
{
7901 return &$complete_vmid_full(1);
7904 sub complete_storage
{
7906 my $cfg = PVE
::Storage
::config
();
7907 my $ids = $cfg->{ids
};
7910 foreach my $sid (keys %$ids) {
7911 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7912 next if !$ids->{$sid}->{content
}->{images
};
7919 sub complete_migration_storage
{
7920 my ($cmd, $param, $current_value, $all_args) = @_;
7922 my $targetnode = @$all_args[1];
7924 my $cfg = PVE
::Storage
::config
();
7925 my $ids = $cfg->{ids
};
7928 foreach my $sid (keys %$ids) {
7929 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7930 next if !$ids->{$sid}->{content
}->{images
};
7939 my $qmpstatus = eval {
7940 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid);
7941 mon_cmd
($vmid, "query-status");
7944 return $qmpstatus && $qmpstatus->{status
} eq "paused";
7947 sub check_volume_storage_type
{
7948 my ($storecfg, $vol) = @_;
7950 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($vol);
7951 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7952 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $vol);
7954 die "storage '$storeid' does not support content-type '$vtype'\n"
7955 if !$scfg->{content
}->{$vtype};