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 // '');
1847 if ($q35 && $vgaid eq 'vga') {
1848 # the first display uses pcie.0 bus on q35 machines
1849 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1851 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1854 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
1857 sub parse_number_sets
{
1860 foreach my $part (split(/;/, $set)) {
1861 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1862 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1863 push @$res, [ $1, $2 ];
1865 die "invalid range: $part\n";
1874 my $res = parse_property_string
($numa_fmt, $data);
1875 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1876 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1880 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1884 my $res = eval { parse_property_string
($net_fmt, $data) };
1889 if (!defined($res->{macaddr
})) {
1890 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1891 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1896 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1897 sub parse_ipconfig
{
1900 my $res = eval { parse_property_string
($ipconfig_fmt, $data) };
1906 if ($res->{gw
} && !$res->{ip
}) {
1907 warn 'gateway specified without specifying an IP address';
1910 if ($res->{gw6
} && !$res->{ip6
}) {
1911 warn 'IPv6 gateway specified without specifying an IPv6 address';
1914 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1915 warn 'gateway specified together with DHCP';
1918 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1920 warn "IPv6 gateway specified together with $res->{ip6} address";
1924 if (!$res->{ip
} && !$res->{ip6
}) {
1925 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1934 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1937 sub add_random_macs
{
1938 my ($settings) = @_;
1940 foreach my $opt (keys %$settings) {
1941 next if $opt !~ m/^net(\d+)$/;
1942 my $net = parse_net
($settings->{$opt});
1944 $settings->{$opt} = print_net
($net);
1948 sub vm_is_volid_owner
{
1949 my ($storecfg, $vmid, $volid) = @_;
1951 if ($volid !~ m
|^/|) {
1953 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1954 if ($owner && ($owner == $vmid)) {
1962 sub vmconfig_register_unused_drive
{
1963 my ($storecfg, $vmid, $conf, $drive) = @_;
1965 if (drive_is_cloudinit
($drive)) {
1966 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1968 } elsif (!drive_is_cdrom
($drive)) {
1969 my $volid = $drive->{file
};
1970 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1971 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1976 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1980 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1981 format_description
=> 'UUID',
1982 description
=> "Set SMBIOS1 UUID.",
1987 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1988 format_description
=> 'Base64 encoded string',
1989 description
=> "Set SMBIOS1 version.",
1994 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1995 format_description
=> 'Base64 encoded string',
1996 description
=> "Set SMBIOS1 serial number.",
2001 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2002 format_description
=> 'Base64 encoded string',
2003 description
=> "Set SMBIOS1 manufacturer.",
2008 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2009 format_description
=> 'Base64 encoded string',
2010 description
=> "Set SMBIOS1 product ID.",
2015 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2016 format_description
=> 'Base64 encoded string',
2017 description
=> "Set SMBIOS1 SKU string.",
2022 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2023 format_description
=> 'Base64 encoded string',
2024 description
=> "Set SMBIOS1 family string.",
2029 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
2037 my $res = eval { parse_property_string
($smbios1_fmt, $data) };
2044 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2047 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2049 sub parse_watchdog
{
2054 my $res = eval { parse_property_string
($watchdog_fmt, $value) };
2059 sub parse_guest_agent
{
2062 return {} if !defined($conf->{agent
});
2064 my $res = eval { parse_property_string
($agent_fmt, $conf->{agent
}) };
2067 # if the agent is disabled ignore the other potentially set properties
2068 return {} if !$res->{enabled
};
2073 my ($conf, $key) = @_;
2074 return undef if !defined($conf->{agent
});
2076 my $agent = parse_guest_agent
($conf);
2077 return $agent->{$key};
2083 return {} if !$value;
2084 my $res = eval { parse_property_string
($vga_fmt, $value) };
2094 my $res = eval { parse_property_string
($rng_fmt, $value) };
2099 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2100 sub verify_usb_device
{
2101 my ($value, $noerr) = @_;
2103 return $value if parse_usb_device
($value);
2107 die "unable to parse usb device\n";
2110 # add JSON properties for create and set function
2111 sub json_config_properties
{
2114 my $skip_json_config_opts = {
2118 runningmachine
=> 1,
2122 foreach my $opt (keys %$confdesc) {
2123 next if $skip_json_config_opts->{$opt};
2124 $prop->{$opt} = $confdesc->{$opt};
2130 # return copy of $confdesc_cloudinit to generate documentation
2131 sub cloudinit_config_properties
{
2133 return dclone
($confdesc_cloudinit);
2137 my ($key, $value) = @_;
2139 die "unknown setting '$key'\n" if !$confdesc->{$key};
2141 my $type = $confdesc->{$key}->{type
};
2143 if (!defined($value)) {
2144 die "got undefined value\n";
2147 if ($value =~ m/[\n\r]/) {
2148 die "property contains a line feed\n";
2151 if ($type eq 'boolean') {
2152 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2153 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2154 die "type check ('boolean') failed - got '$value'\n";
2155 } elsif ($type eq 'integer') {
2156 return int($1) if $value =~ m/^(\d+)$/;
2157 die "type check ('integer') failed - got '$value'\n";
2158 } elsif ($type eq 'number') {
2159 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2160 die "type check ('number') failed - got '$value'\n";
2161 } elsif ($type eq 'string') {
2162 if (my $fmt = $confdesc->{$key}->{format
}) {
2163 PVE
::JSONSchema
::check_format
($fmt, $value);
2166 $value =~ s/^\"(.*)\"$/$1/;
2169 die "internal error"
2174 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
2176 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2178 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2180 if ($conf->{template
}) {
2181 # check if any base image is still used by a linked clone
2182 PVE
::QemuConfig-
>foreach_volume_full($conf, { include_unused
=> 1 }, sub {
2183 my ($ds, $drive) = @_;
2184 return if drive_is_cdrom
($drive);
2186 my $volid = $drive->{file
};
2187 return if !$volid || $volid =~ m
|^/|;
2189 die "base volume '$volid' is still in use by linked cloned\n"
2190 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2196 my $remove_owned_drive = sub {
2197 my ($ds, $drive) = @_;
2198 return if drive_is_cdrom
($drive, 1);
2200 my $volid = $drive->{file
};
2201 return if !$volid || $volid =~ m
|^/|;
2202 return if $volids->{$volid};
2204 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2205 return if !$path || !$owner || ($owner != $vmid);
2207 $volids->{$volid} = 1;
2208 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2209 warn "Could not remove disk '$volid', check manually: $@" if $@;
2212 # only remove disks owned by this VM (referenced in the config)
2213 my $include_opts = {
2214 include_unused
=> 1,
2215 extra_keys
=> ['vmstate'],
2217 PVE
::QemuConfig-
>foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2219 for my $snap (values %{$conf->{snapshots
}}) {
2220 next if !defined($snap->{vmstate
});
2221 my $drive = PVE
::QemuConfig-
>parse_volume('vmstate', $snap->{vmstate
}, 1);
2222 next if !defined($drive);
2223 $remove_owned_drive->('vmstate', $drive);
2226 PVE
::QemuConfig-
>foreach_volume_full($conf->{pending
}, $include_opts, $remove_owned_drive);
2228 if ($purge_unreferenced) { # also remove unreferenced disk
2229 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid, undef, 'images');
2230 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2231 my ($volid, $sid, $volname, $d) = @_;
2232 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2237 if (defined $replacement_conf) {
2238 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2240 PVE
::QemuConfig-
>destroy_config($vmid);
2244 sub parse_vm_config
{
2245 my ($filename, $raw) = @_;
2247 return if !defined($raw);
2250 digest
=> Digest
::SHA
::sha1_hex
($raw),
2255 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2256 || die "got strange filename '$filename'";
2264 my @lines = split(/\n/, $raw);
2265 foreach my $line (@lines) {
2266 next if $line =~ m/^\s*$/;
2268 if ($line =~ m/^\[PENDING\]\s*$/i) {
2269 $section = 'pending';
2270 if (defined($descr)) {
2272 $conf->{description
} = $descr;
2275 $conf = $res->{$section} = {};
2278 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2280 if (defined($descr)) {
2282 $conf->{description
} = $descr;
2285 $conf = $res->{snapshots
}->{$section} = {};
2289 if ($line =~ m/^\#(.*)\s*$/) {
2290 $descr = '' if !defined($descr);
2291 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2295 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2296 $descr = '' if !defined($descr);
2297 $descr .= PVE
::Tools
::decode_text
($2);
2298 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2299 $conf->{snapstate
} = $1;
2300 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2303 $conf->{$key} = $value;
2304 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2306 if ($section eq 'pending') {
2307 $conf->{delete} = $value; # we parse this later
2309 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2311 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2314 eval { $value = check_type
($key, $value); };
2316 warn "vm $vmid - unable to parse value of '$key' - $@";
2318 $key = 'ide2' if $key eq 'cdrom';
2319 my $fmt = $confdesc->{$key}->{format
};
2320 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2321 my $v = parse_drive
($key, $value);
2322 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2323 $v->{file
} = $volid;
2324 $value = print_drive
($v);
2326 warn "vm $vmid - unable to parse value of '$key'\n";
2331 $conf->{$key} = $value;
2334 warn "vm $vmid - unable to parse config: $line\n";
2338 if (defined($descr)) {
2340 $conf->{description
} = $descr;
2342 delete $res->{snapstate
}; # just to be sure
2347 sub write_vm_config
{
2348 my ($filename, $conf) = @_;
2350 delete $conf->{snapstate
}; # just to be sure
2352 if ($conf->{cdrom
}) {
2353 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2354 $conf->{ide2
} = $conf->{cdrom
};
2355 delete $conf->{cdrom
};
2358 # we do not use 'smp' any longer
2359 if ($conf->{sockets
}) {
2360 delete $conf->{smp
};
2361 } elsif ($conf->{smp
}) {
2362 $conf->{sockets
} = $conf->{smp
};
2363 delete $conf->{cores
};
2364 delete $conf->{smp
};
2367 my $used_volids = {};
2369 my $cleanup_config = sub {
2370 my ($cref, $pending, $snapname) = @_;
2372 foreach my $key (keys %$cref) {
2373 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2374 $key eq 'snapstate' || $key eq 'pending';
2375 my $value = $cref->{$key};
2376 if ($key eq 'delete') {
2377 die "propertry 'delete' is only allowed in [PENDING]\n"
2379 # fixme: check syntax?
2382 eval { $value = check_type
($key, $value); };
2383 die "unable to parse value of '$key' - $@" if $@;
2385 $cref->{$key} = $value;
2387 if (!$snapname && is_valid_drivename
($key)) {
2388 my $drive = parse_drive
($key, $value);
2389 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2394 &$cleanup_config($conf);
2396 &$cleanup_config($conf->{pending
}, 1);
2398 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2399 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2400 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2403 # remove 'unusedX' settings if we re-add a volume
2404 foreach my $key (keys %$conf) {
2405 my $value = $conf->{$key};
2406 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2407 delete $conf->{$key};
2411 my $generate_raw_config = sub {
2412 my ($conf, $pending) = @_;
2416 # add description as comment to top of file
2417 if (defined(my $descr = $conf->{description
})) {
2419 foreach my $cl (split(/\n/, $descr)) {
2420 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2423 $raw .= "#\n" if $pending;
2427 foreach my $key (sort keys %$conf) {
2428 next if $key =~ /^(digest|description|pending|snapshots)$/;
2429 $raw .= "$key: $conf->{$key}\n";
2434 my $raw = &$generate_raw_config($conf);
2436 if (scalar(keys %{$conf->{pending
}})){
2437 $raw .= "\n[PENDING]\n";
2438 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2441 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2442 $raw .= "\n[$snapname]\n";
2443 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2453 # we use static defaults from our JSON schema configuration
2454 foreach my $key (keys %$confdesc) {
2455 if (defined(my $default = $confdesc->{$key}->{default})) {
2456 $res->{$key} = $default;
2464 my $vmlist = PVE
::Cluster
::get_vmlist
();
2466 return $res if !$vmlist || !$vmlist->{ids
};
2467 my $ids = $vmlist->{ids
};
2468 my $nodename = nodename
();
2470 foreach my $vmid (keys %$ids) {
2471 my $d = $ids->{$vmid};
2472 next if !$d->{node
} || $d->{node
} ne $nodename;
2473 next if !$d->{type
} || $d->{type
} ne 'qemu';
2474 $res->{$vmid}->{exists} = 1;
2479 # test if VM uses local resources (to prevent migration)
2480 sub check_local_resources
{
2481 my ($conf, $noerr) = @_;
2485 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2486 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2488 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2490 foreach my $k (keys %$conf) {
2491 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2492 # sockets are safe: they will recreated be on the target side post-migrate
2493 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2494 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2497 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2502 # check if used storages are available on all nodes (use by migrate)
2503 sub check_storage_availability
{
2504 my ($storecfg, $conf, $node) = @_;
2506 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2507 my ($ds, $drive) = @_;
2509 my $volid = $drive->{file
};
2512 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2515 # check if storage is available on both nodes
2516 my $scfg = PVE
::Storage
::storage_check_enabled
($storecfg, $sid);
2517 PVE
::Storage
::storage_check_enabled
($storecfg, $sid, $node);
2519 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $volid);
2521 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2522 if !$scfg->{content
}->{$vtype};
2526 # list nodes where all VM images are available (used by has_feature API)
2528 my ($conf, $storecfg) = @_;
2530 my $nodelist = PVE
::Cluster
::get_nodelist
();
2531 my $nodehash = { map { $_ => 1 } @$nodelist };
2532 my $nodename = nodename
();
2534 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2535 my ($ds, $drive) = @_;
2537 my $volid = $drive->{file
};
2540 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2542 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2543 if ($scfg->{disable
}) {
2545 } elsif (my $avail = $scfg->{nodes
}) {
2546 foreach my $node (keys %$nodehash) {
2547 delete $nodehash->{$node} if !$avail->{$node};
2549 } elsif (!$scfg->{shared
}) {
2550 foreach my $node (keys %$nodehash) {
2551 delete $nodehash->{$node} if $node ne $nodename
2560 sub check_local_storage_availability
{
2561 my ($conf, $storecfg) = @_;
2563 my $nodelist = PVE
::Cluster
::get_nodelist
();
2564 my $nodehash = { map { $_ => {} } @$nodelist };
2566 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2567 my ($ds, $drive) = @_;
2569 my $volid = $drive->{file
};
2572 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2574 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2576 if ($scfg->{disable
}) {
2577 foreach my $node (keys %$nodehash) {
2578 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2580 } elsif (my $avail = $scfg->{nodes
}) {
2581 foreach my $node (keys %$nodehash) {
2582 if (!$avail->{$node}) {
2583 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2590 foreach my $node (values %$nodehash) {
2591 if (my $unavail = $node->{unavailable_storages
}) {
2592 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2599 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2601 my ($vmid, $nocheck, $node) = @_;
2603 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2604 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2609 my $vzlist = config_list
();
2611 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2613 while (defined(my $de = $fd->read)) {
2614 next if $de !~ m/^(\d+)\.pid$/;
2616 next if !defined($vzlist->{$vmid});
2617 if (my $pid = check_running
($vmid)) {
2618 $vzlist->{$vmid}->{pid
} = $pid;
2625 our $vmstatus_return_properties = {
2626 vmid
=> get_standard_option
('pve-vmid'),
2628 description
=> "Qemu process status.",
2630 enum
=> ['stopped', 'running'],
2633 description
=> "Maximum memory in bytes.",
2636 renderer
=> 'bytes',
2639 description
=> "Root disk size in bytes.",
2642 renderer
=> 'bytes',
2645 description
=> "VM name.",
2650 description
=> "Qemu QMP agent status.",
2655 description
=> "PID of running qemu process.",
2660 description
=> "Uptime.",
2663 renderer
=> 'duration',
2666 description
=> "Maximum usable CPUs.",
2671 description
=> "The current config lock, if any.",
2676 description
=> "The current configured tags, if any",
2680 'running-machine' => {
2681 description
=> "The currently running machine type (if running).",
2686 description
=> "The currently running QEMU version (if running).",
2692 my $last_proc_pid_stat;
2694 # get VM status information
2695 # This must be fast and should not block ($full == false)
2696 # We only query KVM using QMP if $full == true (this can be slow)
2698 my ($opt_vmid, $full) = @_;
2702 my $storecfg = PVE
::Storage
::config
();
2704 my $list = vzlist
();
2705 my $defaults = load_defaults
();
2707 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2709 my $cpucount = $cpuinfo->{cpus
} || 1;
2711 foreach my $vmid (keys %$list) {
2712 next if $opt_vmid && ($vmid ne $opt_vmid);
2714 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2716 my $d = { vmid
=> int($vmid) };
2717 $d->{pid
} = int($list->{$vmid}->{pid
}) if $list->{$vmid}->{pid
};
2719 # fixme: better status?
2720 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2722 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2723 if (defined($size)) {
2724 $d->{disk
} = 0; # no info available
2725 $d->{maxdisk
} = $size;
2731 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2732 * ($conf->{cores
} || $defaults->{cores
});
2733 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2734 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2736 $d->{name
} = $conf->{name
} || "VM $vmid";
2737 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2738 : $defaults->{memory
}*(1024*1024);
2740 if ($conf->{balloon
}) {
2741 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2742 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2743 : $defaults->{shares
};
2754 $d->{diskwrite
} = 0;
2756 $d->{template
} = 1 if PVE
::QemuConfig-
>is_template($conf);
2758 $d->{serial
} = 1 if conf_has_serial
($conf);
2759 $d->{lock} = $conf->{lock} if $conf->{lock};
2760 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2765 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2766 foreach my $dev (keys %$netdev) {
2767 next if $dev !~ m/^tap([1-9]\d*)i/;
2769 my $d = $res->{$vmid};
2772 $d->{netout
} += $netdev->{$dev}->{receive
};
2773 $d->{netin
} += $netdev->{$dev}->{transmit
};
2776 $d->{nics
}->{$dev}->{netout
} = int($netdev->{$dev}->{receive
});
2777 $d->{nics
}->{$dev}->{netin
} = int($netdev->{$dev}->{transmit
});
2782 my $ctime = gettimeofday
;
2784 foreach my $vmid (keys %$list) {
2786 my $d = $res->{$vmid};
2787 my $pid = $d->{pid
};
2790 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2791 next if !$pstat; # not running
2793 my $used = $pstat->{utime} + $pstat->{stime
};
2795 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2797 if ($pstat->{vsize
}) {
2798 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2801 my $old = $last_proc_pid_stat->{$pid};
2803 $last_proc_pid_stat->{$pid} = {
2811 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2813 if ($dtime > 1000) {
2814 my $dutime = $used - $old->{used
};
2816 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2817 $last_proc_pid_stat->{$pid} = {
2823 $d->{cpu
} = $old->{cpu
};
2827 return $res if !$full;
2829 my $qmpclient = PVE
::QMPClient-
>new();
2831 my $ballooncb = sub {
2832 my ($vmid, $resp) = @_;
2834 my $info = $resp->{'return'};
2835 return if !$info->{max_mem
};
2837 my $d = $res->{$vmid};
2839 # use memory assigned to VM
2840 $d->{maxmem
} = $info->{max_mem
};
2841 $d->{balloon
} = $info->{actual
};
2843 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2844 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2845 $d->{freemem
} = $info->{free_mem
};
2848 $d->{ballooninfo
} = $info;
2851 my $blockstatscb = sub {
2852 my ($vmid, $resp) = @_;
2853 my $data = $resp->{'return'} || [];
2854 my $totalrdbytes = 0;
2855 my $totalwrbytes = 0;
2857 for my $blockstat (@$data) {
2858 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2859 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2861 $blockstat->{device
} =~ s/drive-//;
2862 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2864 $res->{$vmid}->{diskread
} = $totalrdbytes;
2865 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2868 my $machinecb = sub {
2869 my ($vmid, $resp) = @_;
2870 my $data = $resp->{'return'} || [];
2872 $res->{$vmid}->{'running-machine'} =
2873 PVE
::QemuServer
::Machine
::current_from_query_machines
($data);
2876 my $versioncb = sub {
2877 my ($vmid, $resp) = @_;
2878 my $data = $resp->{'return'} // {};
2879 my $version = 'unknown';
2881 if (my $v = $data->{qemu
}) {
2882 $version = $v->{major
} . "." . $v->{minor
} . "." . $v->{micro
};
2885 $res->{$vmid}->{'running-qemu'} = $version;
2888 my $statuscb = sub {
2889 my ($vmid, $resp) = @_;
2891 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2892 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
2893 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
2894 # this fails if ballon driver is not loaded, so this must be
2895 # the last commnand (following command are aborted if this fails).
2896 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2898 my $status = 'unknown';
2899 if (!defined($status = $resp->{'return'}->{status
})) {
2900 warn "unable to get VM status\n";
2904 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2907 foreach my $vmid (keys %$list) {
2908 next if $opt_vmid && ($vmid ne $opt_vmid);
2909 next if !$res->{$vmid}->{pid
}; # not running
2910 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2913 $qmpclient->queue_execute(undef, 2);
2915 foreach my $vmid (keys %$list) {
2916 next if $opt_vmid && ($vmid ne $opt_vmid);
2917 next if !$res->{$vmid}->{pid
}; #not running
2919 # we can't use the $qmpclient since it might have already aborted on
2920 # 'query-balloon', but this might also fail for older versions...
2921 my $qemu_support = eval { mon_cmd
($vmid, "query-proxmox-support") };
2922 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
2925 foreach my $vmid (keys %$list) {
2926 next if $opt_vmid && ($vmid ne $opt_vmid);
2927 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2933 sub conf_has_serial
{
2936 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2937 if ($conf->{"serial$i"}) {
2945 sub conf_has_audio
{
2946 my ($conf, $id) = @_;
2949 my $audio = $conf->{"audio$id"};
2950 return if !defined($audio);
2952 my $audioproperties = parse_property_string
($audio_fmt, $audio);
2953 my $audiodriver = $audioproperties->{driver
} // 'spice';
2956 dev
=> $audioproperties->{device
},
2957 dev_id
=> "audiodev$id",
2958 backend
=> $audiodriver,
2959 backend_id
=> "$audiodriver-backend${id}",
2964 my ($audio, $audiopciaddr, $machine_version) = @_;
2968 my $id = $audio->{dev_id
};
2970 if (min_version
($machine_version, 4, 2)) {
2971 $audiodev = ",audiodev=$audio->{backend_id}";
2974 if ($audio->{dev
} eq 'AC97') {
2975 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
2976 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
2977 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
2978 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
2979 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
2981 die "unkown audio device '$audio->{dev}', implement me!";
2984 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2992 socket => "/var/run/qemu-server/$vmid.swtpm",
2993 pid
=> "/var/run/qemu-server/$vmid.swtpm.pid",
2997 sub add_tpm_device
{
2998 my ($vmid, $devices, $conf) = @_;
3000 return if !$conf->{tpmstate0
};
3002 my $paths = get_tpm_paths
($vmid);
3004 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
3005 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
3006 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
3010 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
3012 return if !$tpmdrive;
3015 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
3016 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
3018 $state = PVE
::Storage
::map_volume
($storecfg, $tpm->{file
});
3020 $state = $tpm->{file
};
3023 my $paths = get_tpm_paths
($vmid);
3025 # during migration, we will get state from remote
3028 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3035 "--create-platform-cert",
3038 "/etc/swtpm_setup.conf", # do not use XDG configs
3040 "0", # force creation as root, error if not possible
3041 "--not-overwrite", # ignore existing state, do not modify
3044 push @$setup_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3045 # TPM 2.0 supports ECC crypto, use if possible
3046 push @$setup_cmd, "--ecc" if $tpm->{version
} eq 'v2.0';
3048 run_command
($setup_cmd, outfunc
=> sub {
3049 print "swtpm_setup: $1\n";
3053 my $emulator_cmd = [
3057 "backend-uri=file://$state,mode=0600",
3059 "type=unixio,path=$paths->{socket},mode=0600",
3061 "file=$paths->{pid}",
3062 "--terminate", # terminate on QEMU disconnect
3065 push @$emulator_cmd, "--tpm2" if $tpm->{version
} eq 'v2.0';
3066 run_command
($emulator_cmd, outfunc
=> sub { print $1; });
3068 my $tries = 100; # swtpm may take a bit to start before daemonizing, wait up to 5s for pid
3069 while (! -e
$paths->{pid
}) {
3070 die "failed to start swtpm: pid file '$paths->{pid}' wasn't created.\n" if --$tries == 0;
3074 # return untainted PID of swtpm daemon so it can be killed on error
3075 file_read_firstline
($paths->{pid
}) =~ m/(\d+)/;
3079 sub vga_conf_has_spice
{
3082 my $vgaconf = parse_vga
($vga);
3083 my $vgatype = $vgaconf->{type
};
3084 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3091 return get_host_arch
() eq $arch;
3096 return $conf->{arch
} // get_host_arch
();
3099 my $default_machines = {
3104 sub get_installed_machine_version
{
3105 my ($kvmversion) = @_;
3106 $kvmversion = kvm_user_version
() if !defined($kvmversion);
3107 $kvmversion =~ m/^(\d+\.\d+)/;
3111 sub windows_get_pinned_machine_version
{
3112 my ($machine, $base_version, $kvmversion) = @_;
3114 my $pin_version = $base_version;
3115 if (!defined($base_version) ||
3116 !PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($base_version, $kvmversion)
3118 $pin_version = get_installed_machine_version
($kvmversion);
3120 if (!$machine || $machine eq 'pc') {
3121 $machine = "pc-i440fx-$pin_version";
3122 } elsif ($machine eq 'q35') {
3123 $machine = "pc-q35-$pin_version";
3124 } elsif ($machine eq 'virt') {
3125 $machine = "virt-$pin_version";
3127 warn "unknown machine type '$machine', not touching that!\n";
3133 sub get_vm_machine
{
3134 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
3136 my $machine = $forcemachine || $conf->{machine
};
3138 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
3139 $kvmversion //= kvm_user_version
();
3140 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3141 # layout which confuses windows quite a bit and may result in various regressions..
3142 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3143 if (windows_version
($conf->{ostype
})) {
3144 $machine = windows_get_pinned_machine_version
($machine, '5.1', $kvmversion);
3147 $machine ||= $default_machines->{$arch};
3148 if ($add_pve_version) {
3149 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
3150 $machine .= "+pve$pvever";
3154 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3155 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3156 $machine = $1 if $is_pxe;
3158 # for version-pinned machines that do not include a pve-version (e.g.
3159 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3160 $machine .= '+pve0';
3162 $machine .= '.pxe' if $is_pxe;
3168 sub get_ovmf_files
($$) {
3169 my ($arch, $efidisk) = @_;
3171 my $types = $OVMF->{$arch}
3172 or die "no OVMF images known for architecture '$arch'\n";
3174 my $type = 'default';
3175 if (defined($efidisk->{efitype
}) && $efidisk->{efitype
} eq '4m') {
3176 $type = $efidisk->{'pre-enrolled-keys'} ?
"4m-ms" : "4m";
3179 return $types->{$type}->@*;
3183 aarch64
=> '/usr/bin/qemu-system-aarch64',
3184 x86_64
=> '/usr/bin/qemu-system-x86_64',
3186 sub get_command_for_arch
($) {
3188 return '/usr/bin/kvm' if is_native
($arch);
3190 my $cmd = $Arch2Qemu->{$arch}
3191 or die "don't know how to emulate architecture '$arch'\n";
3195 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3196 # to use in a QEMU command line (-cpu element), first array_intersect the result
3197 # of query_supported_ with query_understood_. This is necessary because:
3199 # a) query_understood_ returns flags the host cannot use and
3200 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
3201 # flags, but CPU settings - with most of them being flags. Those settings
3202 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
3204 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3205 # expensive. If you need the value returned from this, you can get it much
3206 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3207 # $accel being 'kvm' or 'tcg'.
3209 # pvestatd calls this function on startup and whenever the QEMU/KVM version
3210 # changes, automatically populating pmxcfs.
3212 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3213 # since kvm and tcg machines support different flags
3215 sub query_supported_cpu_flags
{
3218 $arch //= get_host_arch
();
3219 my $default_machine = $default_machines->{$arch};
3223 # FIXME: Once this is merged, the code below should work for ARM as well:
3224 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3225 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3228 my $kvm_supported = defined(kvm_version
());
3229 my $qemu_cmd = get_command_for_arch
($arch);
3231 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
3233 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3234 my $query_supported_run_qemu = sub {
3240 '-machine', $default_machine,
3242 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
3243 '-mon', 'chardev=qmp,mode=control',
3244 '-pidfile', $pidfile,
3249 push @$cmd, '-accel', 'tcg';
3252 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
3253 die "QEMU flag querying VM exited with code " . $rc if $rc;
3256 my $cmd_result = mon_cmd
(
3258 'query-cpu-model-expansion',
3260 model
=> { name
=> 'host' }
3263 my $props = $cmd_result->{model
}->{props
};
3264 foreach my $prop (keys %$props) {
3265 next if $props->{$prop} ne '1';
3266 # QEMU returns some flags multiple times, with '_', '.' or '-'
3267 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3268 # We only keep those with underscores, to match /proc/cpuinfo
3269 $prop =~ s/\.|-/_/g;
3270 $flags->{$prop} = 1;
3275 # force stop with 10 sec timeout and 'nocheck', always stop, even if QMP failed
3276 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
3280 return [ sort keys %$flags ];
3283 # We need to query QEMU twice, since KVM and TCG have different supported flags
3284 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
3285 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
3286 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3288 if ($kvm_supported) {
3289 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
3290 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3297 # Understood CPU flags are written to a file at 'pve-qemu' compile time
3298 my $understood_cpu_flag_dir = "/usr/share/kvm";
3299 sub query_understood_cpu_flags
{
3300 my $arch = get_host_arch
();
3301 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3303 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3306 my $raw = file_get_contents
($filepath);
3307 $raw =~ s/^\s+|\s+$//g;
3308 my @flags = split(/\s+/, $raw);
3313 my sub get_cpuunits
{
3315 return $conf->{cpuunits
} // (PVE
::CGroup
::cgroup_mode
() == 2 ?
100 : 1024);
3317 sub config_to_command
{
3318 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3322 my ($globalFlags, $machineFlags, $rtcFlags) = ([], [], []);
3325 my $ostype = $conf->{ostype
};
3326 my $winversion = windows_version
($ostype);
3327 my $kvm = $conf->{kvm
};
3328 my $nodename = nodename
();
3330 my $arch = get_vm_arch
($conf);
3331 my $kvm_binary = get_command_for_arch
($arch);
3332 my $kvmver = kvm_user_version
($kvm_binary);
3334 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3335 $kvmver //= "undefined";
3336 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3339 my $add_pve_version = min_version
($kvmver, 4, 1);
3341 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
3342 my $machine_version = extract_version
($machine_type, $kvmver);
3343 $kvm //= 1 if is_native
($arch);
3345 $machine_version =~ m/(\d+)\.(\d+)/;
3346 my ($machine_major, $machine_minor) = ($1, $2);
3348 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3349 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3350 } elsif (!min_version
($kvmver, $machine_major, $machine_minor)) {
3351 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3352 ." please upgrade node '$nodename'\n"
3353 } elsif (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
3354 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
3355 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3356 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3357 ." node '$nodename'\n";
3360 # if a specific +pve version is required for a feature, use $version_guard
3361 # instead of min_version to allow machines to be run with the minimum
3363 my $required_pve_version = 0;
3364 my $version_guard = sub {
3365 my ($major, $minor, $pve) = @_;
3366 return 0 if !min_version
($machine_version, $major, $minor, $pve);
3367 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
3368 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
3369 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3373 if ($kvm && !defined kvm_version
()) {
3374 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3375 ." or enable in BIOS.\n";
3378 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3379 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3380 my $use_old_bios_files = undef;
3381 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3383 my $cpuunits = get_cpuunits
($conf);
3385 push @$cmd, $kvm_binary;
3387 push @$cmd, '-id', $vmid;
3389 my $vmname = $conf->{name
} || "vm$vmid";
3391 push @$cmd, '-name', $vmname;
3393 push @$cmd, '-no-shutdown';
3397 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3398 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
3399 push @$cmd, '-mon', "chardev=qmp,mode=control";
3401 if (min_version
($machine_version, 2, 12)) {
3402 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3403 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3406 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3408 push @$cmd, '-daemonize';
3410 if ($conf->{smbios1
}) {
3411 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3412 if ($smbios_conf->{base64
}) {
3413 # Do not pass base64 flag to qemu
3414 delete $smbios_conf->{base64
};
3415 my $smbios_string = "";
3416 foreach my $key (keys %$smbios_conf) {
3418 if ($key eq "uuid") {
3419 $value = $smbios_conf->{uuid
}
3421 $value = decode_base64
($smbios_conf->{$key});
3423 # qemu accepts any binary data, only commas need escaping by double comma
3425 $smbios_string .= "," . $key . "=" . $value if $value;
3427 push @$cmd, '-smbios', "type=1" . $smbios_string;
3429 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3433 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3435 if (my $efidisk = $conf->{efidisk0
}) {
3436 $d = parse_drive
('efidisk0', $efidisk);
3439 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch, $d);
3440 die "uefi base image '$ovmf_code' not found\n" if ! -f
$ovmf_code;
3442 my ($path, $format);
3443 my $read_only_str = '';
3445 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3446 $format = $d->{format
};
3448 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3449 if (!defined($format)) {
3450 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3451 $format = qemu_img_format
($scfg, $volname);
3455 die "efidisk format must be specified\n"
3456 if !defined($format);
3459 $read_only_str = ',readonly=on' if drive_is_read_only
($conf, $d);
3461 warn "no efidisk configured! Using temporary efivars disk.\n";
3462 $path = "/tmp/$vmid-ovmf.fd";
3463 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3469 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3470 $size_str = ",size=" . (-s
$ovmf_vars);
3473 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3475 if ($path =~ m/^rbd:/) {
3476 $cache = ',cache=writeback';
3477 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3480 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
3481 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
3484 if ($q35) { # tell QEMU to load q35 config early
3485 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3486 if (min_version
($machine_version, 4, 0)) {
3487 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3489 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3493 if ($conf->{vmgenid
}) {
3494 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3497 # add usb controllers
3498 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
(
3499 $conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3500 push @$devices, @usbcontrollers if @usbcontrollers;
3501 my $vga = parse_vga
($conf->{vga
});
3503 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3504 $vga->{type
} = 'qxl' if $qxlnum;
3506 if (!$vga->{type
}) {
3507 if ($arch eq 'aarch64') {
3508 $vga->{type
} = 'virtio';
3509 } elsif (min_version
($machine_version, 2, 9)) {
3510 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3512 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3516 # enable absolute mouse coordinates (needed by vnc)
3517 my $tablet = $conf->{tablet
};
3518 if (!defined($tablet)) {
3519 $tablet = $defaults->{tablet
};
3520 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3521 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3525 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3526 my $kbd = print_keyboarddevice_full
($conf, $arch);
3527 push @$devices, '-device', $kbd if defined($kbd);
3530 my $bootorder = device_bootorder
($conf);
3532 # host pci device passthrough
3533 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE
::QemuServer
::PCI
::print_hostpci_devices
(
3534 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
3537 my $usb_dev_features = {};
3538 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3540 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
(
3541 $conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
3542 push @$devices, @usbdevices if @usbdevices;
3545 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3546 my $path = $conf->{"serial$i"} or next;
3547 if ($path eq 'socket') {
3548 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3549 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3550 # On aarch64, serial0 is the UART device. Qemu only allows
3551 # connecting UART devices via the '-serial' command line, as
3552 # the device has a fixed slot on the hardware...
3553 if ($arch eq 'aarch64' && $i == 0) {
3554 push @$devices, '-serial', "chardev:serial$i";
3556 push @$devices, '-device', "isa-serial,chardev=serial$i";
3559 die "no such serial device\n" if ! -c
$path;
3560 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3561 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 my $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 my $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 my $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 my $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};
3883 if (!$q35) { # add pci bridges
3884 if (min_version
($machine_version, 2, 3)) {
3888 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3891 for my $k (sort {$b cmp $a} keys %$bridges) {
3892 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3895 if ($k == 2 && $legacy_igd) {
3898 my $pciaddr = print_pci_addr
("pci.$k_name", undef, $arch, $machine_type);
3899 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3901 if ($q35) { # add after -readconfig pve-q35.cfg
3902 splice @$devices, 2, 0, '-device', $devstr;
3904 unshift @$devices, '-device', $devstr if $k > 0;
3909 push @$machineFlags, 'accel=tcg';
3912 my $machine_type_min = $machine_type;
3913 if ($add_pve_version) {
3914 $machine_type_min =~ s/\+pve\d+$//;
3915 $machine_type_min .= "+pve$required_pve_version";
3917 push @$machineFlags, "type=${machine_type_min}";
3919 push @$cmd, @$devices;
3920 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
3921 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
3922 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
3924 if (my $vmstate = $conf->{vmstate
}) {
3925 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3926 push @$vollist, $vmstate;
3927 push @$cmd, '-loadstate', $statepath;
3928 print "activating and using '$vmstate' as vmstate\n";
3931 if (PVE
::QemuConfig-
>is_template($conf)) {
3932 # needed to workaround base volumes being read-only
3933 push @$cmd, '-snapshot';
3937 if ($conf->{args
}) {
3938 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3942 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3945 sub check_rng_source
{
3948 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3949 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
3952 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
3953 if ($source eq '/dev/hwrng' && file_read_firstline
($rng_current) eq 'none') {
3954 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
3955 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
3956 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
3957 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
3965 my $res = mon_cmd
($vmid, 'query-spice');
3967 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3970 sub vm_devices_list
{
3973 my $res = mon_cmd
($vmid, 'query-pci');
3974 my $devices_to_check = [];
3976 foreach my $pcibus (@$res) {
3977 push @$devices_to_check, @{$pcibus->{devices
}},
3980 while (@$devices_to_check) {
3982 for my $d (@$devices_to_check) {
3983 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3984 next if !$d->{'pci_bridge'};
3986 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3987 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3989 $devices_to_check = $to_check;
3992 my $resblock = mon_cmd
($vmid, 'query-block');
3993 foreach my $block (@$resblock) {
3994 if($block->{device
} =~ m/^drive-(\S+)/){
3999 my $resmice = mon_cmd
($vmid, 'query-mice');
4000 foreach my $mice (@$resmice) {
4001 if ($mice->{name
} eq 'QEMU HID Tablet') {
4002 $devices->{tablet
} = 1;
4007 # for usb devices there is no query-usb
4008 # but we can iterate over the entries in
4009 # qom-list path=/machine/peripheral
4010 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4011 foreach my $per (@$resperipheral) {
4012 if ($per->{name
} =~ m/^usb\d+$/) {
4013 $devices->{$per->{name
}} = 1;
4021 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4023 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
4025 my $devices_list = vm_devices_list
($vmid);
4026 return 1 if defined($devices_list->{$deviceid});
4028 # add PCI bridge if we need it for the device
4029 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
4031 if ($deviceid eq 'tablet') {
4032 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4033 } elsif ($deviceid eq 'keyboard') {
4034 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4035 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4036 die "usb hotplug currently not reliable\n";
4037 # since we can't reliably hot unplug all added usb devices and usb
4038 # passthrough breaks live migration we disable usb hotplugging for now
4039 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
4040 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4041 qemu_iothread_add
($vmid, $deviceid, $device);
4043 qemu_driveadd
($storecfg, $vmid, $device);
4044 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4046 qemu_deviceadd
($vmid, $devicefull);
4047 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4049 eval { qemu_drivedel
($vmid, $deviceid); };
4053 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4054 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4055 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4056 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4058 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4060 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4061 qemu_iothread_add
($vmid, $deviceid, $device);
4062 $devicefull .= ",iothread=iothread-$deviceid";
4065 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4066 $devicefull .= ",num_queues=$device->{queues}";
4069 qemu_deviceadd
($vmid, $devicefull);
4070 qemu_deviceaddverify
($vmid, $deviceid);
4071 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4072 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4073 qemu_driveadd
($storecfg, $vmid, $device);
4075 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
4076 eval { qemu_deviceadd
($vmid, $devicefull); };
4078 eval { qemu_drivedel
($vmid, $deviceid); };
4082 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4083 return if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4085 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
4086 my $use_old_bios_files = undef;
4087 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4089 my $netdevicefull = print_netdevice_full
(
4090 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4091 qemu_deviceadd
($vmid, $netdevicefull);
4093 qemu_deviceaddverify
($vmid, $deviceid);
4094 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4097 eval { qemu_netdevdel
($vmid, $deviceid); };
4101 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4103 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4104 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4106 qemu_deviceadd
($vmid, $devicefull);
4107 qemu_deviceaddverify
($vmid, $deviceid);
4109 die "can't hotplug device '$deviceid'\n";
4115 # fixme: this should raise exceptions on error!
4116 sub vm_deviceunplug
{
4117 my ($vmid, $conf, $deviceid) = @_;
4119 my $devices_list = vm_devices_list
($vmid);
4120 return 1 if !defined($devices_list->{$deviceid});
4122 my $bootdisks = PVE
::QemuServer
::Drive
::get_bootdisks
($conf);
4123 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
4125 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4126 qemu_devicedel
($vmid, $deviceid);
4127 } elsif ($deviceid =~ m/^usb\d+$/) {
4128 die "usb hotplug currently not reliable\n";
4129 # when unplugging usb devices this way, there may be remaining usb
4130 # controllers/hubs so we disable it for now
4131 #qemu_devicedel($vmid, $deviceid);
4132 #qemu_devicedelverify($vmid, $deviceid);
4133 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4134 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4136 qemu_devicedel
($vmid, $deviceid);
4137 qemu_devicedelverify
($vmid, $deviceid);
4138 qemu_drivedel
($vmid, $deviceid);
4139 qemu_iothread_del
($vmid, $deviceid, $device);
4140 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4141 qemu_devicedel
($vmid, $deviceid);
4142 qemu_devicedelverify
($vmid, $deviceid);
4143 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4144 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4146 qemu_devicedel
($vmid, $deviceid);
4147 qemu_drivedel
($vmid, $deviceid);
4148 qemu_deletescsihw
($conf, $vmid, $deviceid);
4150 qemu_iothread_del
($vmid, "virtioscsi$device->{index}", $device)
4151 if $conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single');
4152 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4153 qemu_devicedel
($vmid, $deviceid);
4154 qemu_devicedelverify
($vmid, $deviceid);
4155 qemu_netdevdel
($vmid, $deviceid);
4157 die "can't unplug device '$deviceid'\n";
4163 sub qemu_deviceadd
{
4164 my ($vmid, $devicefull) = @_;
4166 $devicefull = "driver=".$devicefull;
4167 my %options = split(/[=,]/, $devicefull);
4169 mon_cmd
($vmid, "device_add" , %options);
4172 sub qemu_devicedel
{
4173 my ($vmid, $deviceid) = @_;
4175 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
4178 sub qemu_iothread_add
{
4179 my ($vmid, $deviceid, $device) = @_;
4181 if ($device->{iothread
}) {
4182 my $iothreads = vm_iothreads_list
($vmid);
4183 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4187 sub qemu_iothread_del
{
4188 my ($vmid, $deviceid, $device) = @_;
4190 if ($device->{iothread
}) {
4191 my $iothreads = vm_iothreads_list
($vmid);
4192 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4196 sub qemu_objectadd
{
4197 my ($vmid, $objectid, $qomtype) = @_;
4199 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4204 sub qemu_objectdel
{
4205 my ($vmid, $objectid) = @_;
4207 mon_cmd
($vmid, "object-del", id
=> $objectid);
4213 my ($storecfg, $vmid, $device) = @_;
4215 my $kvmver = get_running_qemu_version
($vmid);
4216 my $io_uring = min_version
($kvmver, 6, 0);
4217 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device, undef, $io_uring);
4218 $drive =~ s/\\/\\\\/g;
4219 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
4221 # If the command succeeds qemu prints: "OK
"
4222 return 1 if $ret =~ m/OK/s;
4224 die "adding drive failed
: $ret\n";
4228 my ($vmid, $deviceid) = @_;
4230 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
4233 return 1 if $ret eq "";
4235 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4236 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4238 die "deleting drive
$deviceid failed
: $ret\n";
4241 sub qemu_deviceaddverify {
4242 my ($vmid, $deviceid) = @_;
4244 for (my $i = 0; $i <= 5; $i++) {
4245 my $devices_list = vm_devices_list($vmid);
4246 return 1 if defined($devices_list->{$deviceid});
4250 die "error on hotplug device
'$deviceid'\n";
4254 sub qemu_devicedelverify {
4255 my ($vmid, $deviceid) = @_;
4257 # need to verify that the device is correctly removed as device_del
4258 # is async and empty return is not reliable
4260 for (my $i = 0; $i <= 5; $i++) {
4261 my $devices_list = vm_devices_list($vmid);
4262 return 1 if !defined($devices_list->{$deviceid});
4266 die "error on hot-unplugging device
'$deviceid'\n";
4269 sub qemu_findorcreatescsihw {
4270 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4272 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4274 my $scsihwid="$controller_prefix$controller";
4275 my $devices_list = vm_devices_list($vmid);
4277 if (!defined($devices_list->{$scsihwid})) {
4278 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4284 sub qemu_deletescsihw {
4285 my ($conf, $vmid, $opt) = @_;
4287 my $device = parse_drive($opt, $conf->{$opt});
4289 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4290 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4294 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4296 my $devices_list = vm_devices_list($vmid);
4297 foreach my $opt (keys %{$devices_list}) {
4298 if (is_valid_drivename($opt)) {
4299 my $drive = parse_drive($opt, $conf->{$opt});
4300 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4306 my $scsihwid="scsihw
$controller";
4308 vm_deviceunplug($vmid, $conf, $scsihwid);
4313 sub qemu_add_pci_bridge {
4314 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4320 print_pci_addr($device, $bridges, $arch, $machine_type);
4322 while (my ($k, $v) = each %$bridges) {
4325 return 1 if !defined($bridgeid) || $bridgeid < 1;
4327 my $bridge = "pci
.$bridgeid";
4328 my $devices_list = vm_devices_list($vmid);
4330 if (!defined($devices_list->{$bridge})) {
4331 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4337 sub qemu_set_link_status {
4338 my ($vmid, $device, $up) = @_;
4340 mon_cmd($vmid, "set_link
", name => $device,
4341 up => $up ? JSON::true : JSON::false);
4344 sub qemu_netdevadd {
4345 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4347 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4348 my %options = split(/[=,]/, $netdev);
4350 if (defined(my $vhost = $options{vhost})) {
4351 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4354 if (defined(my $queues = $options{queues})) {
4355 $options{queues} = $queues + 0;
4358 mon_cmd($vmid, "netdev_add
", %options);
4362 sub qemu_netdevdel {
4363 my ($vmid, $deviceid) = @_;
4365 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4368 sub qemu_usb_hotplug {
4369 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4373 # remove the old one first
4374 vm_deviceunplug($vmid, $conf, $deviceid);
4376 # check if xhci controller is necessary and available
4377 if ($device->{usb3}) {
4379 my $devicelist = vm_devices_list($vmid);
4381 if (!$devicelist->{xhci}) {
4382 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4383 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4386 my $d = parse_usb_device($device->{host});
4387 $d->{usb3} = $device->{usb3};
4390 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4393 sub qemu_cpu_hotplug {
4394 my ($vmid, $conf, $vcpus) = @_;
4396 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4399 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4400 $sockets = $conf->{sockets} if $conf->{sockets};
4401 my $cores = $conf->{cores} || 1;
4402 my $maxcpus = $sockets * $cores;
4404 $vcpus = $maxcpus if !$vcpus;
4406 die "you can
't add more vcpus than maxcpus\n"
4407 if $vcpus > $maxcpus;
4409 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4411 if ($vcpus < $currentvcpus) {
4413 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4415 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4416 qemu_devicedel($vmid, "cpu$i");
4418 my $currentrunningvcpus = undef;
4420 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4421 last if scalar(@{$currentrunningvcpus}) == $i-1;
4422 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4426 #update conf after each succesfull cpu unplug
4427 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4428 PVE::QemuConfig->write_config($vmid, $conf);
4431 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4437 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4438 die "vcpus in running vm does not match its configuration\n"
4439 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4441 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4443 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4444 my $cpustr = print_cpu_device($conf, $i);
4445 qemu_deviceadd($vmid, $cpustr);
4448 my $currentrunningvcpus = undef;
4450 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4451 last if scalar(@{$currentrunningvcpus}) == $i;
4452 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4456 #update conf after each succesfull cpu hotplug
4457 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4458 PVE::QemuConfig->write_config($vmid, $conf);
4462 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4463 mon_cmd($vmid, "cpu-add", id => int($i));
4468 sub qemu_block_set_io_throttle {
4469 my ($vmid, $deviceid,
4470 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4471 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4472 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4473 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4475 return if !check_running($vmid) ;
4477 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4479 bps_rd => int($bps_rd),
4480 bps_wr => int($bps_wr),
4482 iops_rd => int($iops_rd),
4483 iops_wr => int($iops_wr),
4484 bps_max => int($bps_max),
4485 bps_rd_max => int($bps_rd_max),
4486 bps_wr_max => int($bps_wr_max),
4487 iops_max => int($iops_max),
4488 iops_rd_max => int($iops_rd_max),
4489 iops_wr_max => int($iops_wr_max),
4490 bps_max_length => int($bps_max_length),
4491 bps_rd_max_length => int($bps_rd_max_length),
4492 bps_wr_max_length => int($bps_wr_max_length),
4493 iops_max_length => int($iops_max_length),
4494 iops_rd_max_length => int($iops_rd_max_length),
4495 iops_wr_max_length => int($iops_wr_max_length),
4500 sub qemu_block_resize {
4501 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4503 my $running = check_running($vmid);
4505 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4507 return if !$running;
4509 my $padding = (1024 - $size % 1024) % 1024;
4510 $size = $size + $padding;
4515 device => $deviceid,
4521 sub qemu_volume_snapshot {
4522 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4524 my $running = check_running($vmid);
4526 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4527 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4529 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4533 sub qemu_volume_snapshot_delete {
4534 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4536 my $running = check_running($vmid);
4541 my $conf = PVE::QemuConfig->load_config($vmid);
4542 PVE::QemuConfig->foreach_volume($conf, sub {
4543 my ($ds, $drive) = @_;
4544 $running = 1 if $drive->{file} eq $volid;
4548 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
4549 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4551 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4555 sub set_migration_caps {
4556 my ($vmid, $savevm) = @_;
4558 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4560 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm
' : 'pbs-dirty-bitmap-migration
';
4561 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4566 "auto-converge" => 1,
4568 "x-rdma-pin-all" => 0,
4571 "dirty-bitmaps" => $dirty_bitmaps,
4574 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4576 for my $supported_capability (@$supported_capabilities) {
4578 capability => $supported_capability->{capability},
4579 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4583 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4587 my ($conf, $func, @param) = @_;
4591 my $test_volid = sub {
4592 my ($key, $drive, $snapname) = @_;
4594 my $volid = $drive->{file};
4597 $volhash->{$volid}->{cdrom} //= 1;
4598 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
4600 my $replicate = $drive->{replicate} // 1;
4601 $volhash->{$volid}->{replicate} //= 0;
4602 $volhash->{$volid}->{replicate} = 1 if $replicate;
4604 $volhash->{$volid}->{shared} //= 0;
4605 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
4607 $volhash->{$volid}->{referenced_in_config} //= 0;
4608 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4610 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4611 if defined($snapname);
4613 my $size = $drive->{size};
4614 $volhash->{$volid}->{size} //= $size if $size;
4616 $volhash->{$volid}->{is_vmstate} //= 0;
4617 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate
';
4619 $volhash->{$volid}->{is_tpmstate} //= 0;
4620 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0
';
4622 $volhash->{$volid}->{is_unused} //= 0;
4623 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
4625 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
4628 my $include_opts = {
4629 extra_keys => ['vmstate
'],
4630 include_unused => 1,
4633 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
4634 foreach my $snapname (keys %{$conf->{snapshots}}) {
4635 my $snap = $conf->{snapshots}->{$snapname};
4636 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
4639 foreach my $volid (keys %$volhash) {
4640 &$func($volid, $volhash->{$volid}, @param);
4644 my $fast_plug_option = {
4652 'vmstatestorage
' => 1,
4657 # hotplug changes in [PENDING]
4658 # $selection hash can be used to only apply specified options, for
4659 # example: { cores => 1 } (only apply changed 'cores
')
4660 # $errors ref is used to return error messages
4661 sub vmconfig_hotplug_pending {
4662 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4664 my $defaults = load_defaults();
4665 my $arch = get_vm_arch($conf);
4666 my $machine_type = get_vm_machine($conf, undef, $arch);
4668 # commit values which do not have any impact on running VM first
4669 # Note: those option cannot raise errors, we we do not care about
4670 # $selection and always apply them.
4672 my $add_error = sub {
4673 my ($opt, $msg) = @_;
4674 $errors->{$opt} = "hotplug problem - $msg";
4678 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4679 if ($fast_plug_option->{$opt}) {
4680 $conf->{$opt} = $conf->{pending}->{$opt};
4681 delete $conf->{pending}->{$opt};
4687 PVE::QemuConfig->write_config($vmid, $conf);
4690 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4692 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
4693 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4694 foreach my $opt (sort keys %$pending_delete_hash) {
4695 next if $selection && !$selection->{$opt};
4696 my $force = $pending_delete_hash->{$opt}->{force};
4698 if ($opt eq 'hotplug
') {
4699 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4700 } elsif ($opt eq 'tablet
') {
4701 die "skip\n" if !$hotplug_features->{usb};
4702 if ($defaults->{tablet}) {
4703 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4704 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4705 if $arch eq 'aarch64
';
4707 vm_deviceunplug($vmid, $conf, 'tablet
');
4708 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4710 } elsif ($opt =~ m/^usb\d+/) {
4712 # since we cannot reliably hot unplug usb devices we are disabling it
4713 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4714 #vm_deviceunplug($vmid, $conf, $opt);
4715 } elsif ($opt eq 'vcpus
') {
4716 die "skip\n" if !$hotplug_features->{cpu};
4717 qemu_cpu_hotplug($vmid, $conf, undef);
4718 } elsif ($opt eq 'balloon
') {
4719 # enable balloon device is not hotpluggable
4720 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4721 # here we reset the ballooning value to memory
4722 my $balloon = $conf->{memory} || $defaults->{memory};
4723 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4724 } elsif ($fast_plug_option->{$opt}) {
4726 } elsif ($opt =~ m/^net(\d+)$/) {
4727 die "skip\n" if !$hotplug_features->{network};
4728 vm_deviceunplug($vmid, $conf, $opt);
4729 } elsif (is_valid_drivename($opt)) {
4730 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4731 vm_deviceunplug($vmid, $conf, $opt);
4732 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4733 } elsif ($opt =~ m/^memory$/) {
4734 die "skip\n" if !$hotplug_features->{memory};
4735 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4736 } elsif ($opt eq 'cpuunits
') {
4737 $cgroup->change_cpu_shares(undef, 1024);
4738 } elsif ($opt eq 'cpulimit
') {
4739 $cgroup->change_cpu_quota(-1, 100000);
4745 &$add_error($opt, $err) if $err ne "skip\n";
4747 delete $conf->{$opt};
4748 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4752 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4753 $apply_pending_cloudinit = sub {
4754 return if $apply_pending_cloudinit_done; # once is enough
4755 $apply_pending_cloudinit_done = 1; # once is enough
4757 my ($key, $value) = @_;
4759 my @cloudinit_opts = keys %$confdesc_cloudinit;
4760 foreach my $opt (keys %{$conf->{pending}}) {
4761 next if !grep { $_ eq $opt } @cloudinit_opts;
4762 $conf->{$opt} = delete $conf->{pending}->{$opt};
4765 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4766 foreach my $opt (sort keys %$pending_delete_hash) {
4767 next if !grep { $_ eq $opt } @cloudinit_opts;
4768 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4769 delete $conf->{$opt};
4772 my $new_conf = { %$conf };
4773 $new_conf->{$key} = $value;
4774 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4777 foreach my $opt (keys %{$conf->{pending}}) {
4778 next if $selection && !$selection->{$opt};
4779 my $value = $conf->{pending}->{$opt};
4781 if ($opt eq 'hotplug
') {
4782 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4783 } elsif ($opt eq 'tablet
') {
4784 die "skip\n" if !$hotplug_features->{usb};
4786 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4787 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4788 if $arch eq 'aarch64
';
4789 } elsif ($value == 0) {
4790 vm_deviceunplug($vmid, $conf, 'tablet
');
4791 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4793 } elsif ($opt =~ m/^usb\d+$/) {
4795 # since we cannot reliably hot unplug usb devices we disable it for now
4796 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4797 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4798 #die "skip\n" if !$d;
4799 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4800 } elsif ($opt eq 'vcpus
') {
4801 die "skip\n" if !$hotplug_features->{cpu};
4802 qemu_cpu_hotplug($vmid, $conf, $value);
4803 } elsif ($opt eq 'balloon
') {
4804 # enable/disable balloning device is not hotpluggable
4805 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4806 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4807 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4809 # allow manual ballooning if shares is set to zero
4810 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4811 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4812 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4814 } elsif ($opt =~ m/^net(\d+)$/) {
4815 # some changes can be done without hotplug
4816 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4817 $vmid, $opt, $value, $arch, $machine_type);
4818 } elsif (is_valid_drivename($opt)) {
4819 die "skip\n" if $opt eq 'efidisk0
' || $opt eq 'tpmstate0
';
4820 # some changes can be done without hotplug
4821 my $drive = parse_drive($opt, $value);
4822 if (drive_is_cloudinit($drive)) {
4823 &$apply_pending_cloudinit($opt, $value);
4825 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4826 $vmid, $opt, $value, $arch, $machine_type);
4827 } elsif ($opt =~ m/^memory$/) { #dimms
4828 die "skip\n" if !$hotplug_features->{memory};
4829 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4830 } elsif ($opt eq 'cpuunits
') {
4831 $cgroup->change_cpu_shares($conf->{pending}->{$opt}, 1024);
4832 } elsif ($opt eq 'cpulimit
') {
4833 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4834 $cgroup->change_cpu_quota($cpulimit, 100000);
4836 die "skip\n"; # skip non-hot-pluggable options
4840 &$add_error($opt, $err) if $err ne "skip\n";
4842 $conf->{$opt} = $value;
4843 delete $conf->{pending}->{$opt};
4847 PVE::QemuConfig->write_config($vmid, $conf);
4850 sub try_deallocate_drive {
4851 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4853 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4854 my $volid = $drive->{file};
4855 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4856 my $sid = PVE::Storage::parse_volume_id($volid);
4857 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4859 # check if the disk is really unused
4860 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4861 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4862 PVE::Storage::vdisk_free($storecfg, $volid);
4865 # If vm is not owner of this disk remove from config
4873 sub vmconfig_delete_or_detach_drive {
4874 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4876 my $drive = parse_drive($opt, $conf->{$opt});
4878 my $rpcenv = PVE::RPCEnvironment::get();
4879 my $authuser = $rpcenv->get_user();
4882 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4883 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4885 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4891 sub vmconfig_apply_pending {
4892 my ($vmid, $conf, $storecfg, $errors) = @_;
4894 my $add_apply_error = sub {
4895 my ($opt, $msg) = @_;
4896 my $err_msg = "unable to apply pending change $opt : $msg";
4897 $errors->{$opt} = $err_msg;
4903 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4904 foreach my $opt (sort keys %$pending_delete_hash) {
4905 my $force = $pending_delete_hash->{$opt}->{force};
4907 if ($opt =~ m/^unused/) {
4908 die "internal error";
4909 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4910 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4914 $add_apply_error->($opt, $err);
4916 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4917 delete $conf->{$opt};
4921 PVE::QemuConfig->cleanup_pending($conf);
4923 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4924 next if $opt eq 'delete'; # just to be sure
4926 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4927 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4931 $add_apply_error->($opt, $err);
4933 $conf->{$opt} = delete $conf->{pending}->{$opt};
4937 # write all changes at once to avoid unnecessary i/o
4938 PVE::QemuConfig->write_config($vmid, $conf);
4941 sub vmconfig_update_net {
4942 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4944 my $newnet = parse_net($value);
4946 if ($conf->{$opt}) {
4947 my $oldnet = parse_net($conf->{$opt});
4949 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4950 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4951 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4952 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4954 # for non online change, we try to hot-unplug
4955 die "skip\n" if !$hotplug;
4956 vm_deviceunplug($vmid, $conf, $opt);
4959 die "internal error" if $opt !~ m/net(\d+)/;
4960 my $iface = "tap${vmid}i$1";
4962 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4963 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4964 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4965 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4966 PVE::Network::tap_unplug($iface);
4969 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4971 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4973 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4974 # Rate can be applied on its own but any change above needs to
4975 # include the rate in tap_plug since OVS resets everything.
4976 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4979 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4980 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4988 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4994 sub vmconfig_update_disk {
4995 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4997 my $drive = parse_drive($opt, $value);
4999 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
5000 my $media = $drive->{media} || 'disk
';
5001 my $oldmedia = $old_drive->{media} || 'disk
';
5002 die "unable to change media type\n" if $media ne $oldmedia;
5004 if (!drive_is_cdrom($old_drive)) {
5006 if ($drive->{file} ne $old_drive->{file}) {
5008 die "skip\n" if !$hotplug;
5010 # unplug and register as unused
5011 vm_deviceunplug($vmid, $conf, $opt);
5012 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5015 # update existing disk
5017 # skip non hotpluggable value
5018 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5019 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5020 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5021 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
5022 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
5027 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5028 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5029 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5030 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5031 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5032 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5033 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5034 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5035 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5036 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5037 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5038 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5039 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5040 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5041 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5042 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5043 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5044 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5046 qemu_block_set_io_throttle(
5048 ($drive->{mbps} || 0)*1024*1024,
5049 ($drive->{mbps_rd} || 0)*1024*1024,
5050 ($drive->{mbps_wr} || 0)*1024*1024,
5051 $drive->{iops} || 0,
5052 $drive->{iops_rd} || 0,
5053 $drive->{iops_wr} || 0,
5054 ($drive->{mbps_max} || 0)*1024*1024,
5055 ($drive->{mbps_rd_max} || 0)*1024*1024,
5056 ($drive->{mbps_wr_max} || 0)*1024*1024,
5057 $drive->{iops_max} || 0,
5058 $drive->{iops_rd_max} || 0,
5059 $drive->{iops_wr_max} || 0,
5060 $drive->{bps_max_length} || 1,
5061 $drive->{bps_rd_max_length} || 1,
5062 $drive->{bps_wr_max_length} || 1,
5063 $drive->{iops_max_length} || 1,
5064 $drive->{iops_rd_max_length} || 1,
5065 $drive->{iops_wr_max_length} || 1,
5075 if ($drive->{file} eq 'none
') {
5076 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5077 if (drive_is_cloudinit($old_drive)) {
5078 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5081 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5083 # force eject if locked
5084 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5087 mon_cmd($vmid, "blockdev-change-medium",
5088 id => "$opt", filename => "$path");
5096 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5098 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5099 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5102 # called in locked context by incoming migration
5103 sub vm_migrate_get_nbd_disks {
5104 my ($storecfg, $conf, $replicated_volumes) = @_;
5106 my $local_volumes = {};
5107 PVE::QemuConfig->foreach_volume($conf, sub {
5108 my ($ds, $drive) = @_;
5110 return if drive_is_cdrom($drive);
5112 my $volid = $drive->{file};
5116 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5118 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5119 return if $scfg->{shared};
5121 # replicated disks re-use existing state via bitmap
5122 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5123 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
5125 return $local_volumes;
5128 # called in locked context by incoming migration
5129 sub vm_migrate_alloc_nbd_disks {
5130 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
5135 foreach my $opt (sort keys %$source_volumes) {
5136 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
5138 if ($use_existing) {
5139 $nbd->{$opt}->{drivestr} = print_drive($drive);
5140 $nbd->{$opt}->{volid} = $volid;
5141 $nbd->{$opt}->{replicated} = 1;
5145 # If a remote storage is specified and the format of the original
5146 # volume is not available there, fall back to the default format.
5147 # Otherwise use the same format as the original.
5148 if (!$storagemap->{identity}) {
5149 $storeid = map_storage($storagemap, $storeid);
5150 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5151 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5152 my $fileFormat = qemu_img_format($scfg, $volname);
5153 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
5155 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5156 $format = qemu_img_format($scfg, $volname);
5159 my $size = $drive->{size} / 1024;
5160 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
5161 my $newdrive = $drive;
5162 $newdrive->{format} = $format;
5163 $newdrive->{file} = $newvolid;
5164 my $drivestr = print_drive($newdrive);
5165 $nbd->{$opt}->{drivestr} = $drivestr;
5166 $nbd->{$opt}->{volid} = $newvolid;
5172 # see vm_start_nolock for parameters, additionally:
5174 # storagemap = parsed storage map for allocating NBD disks
5176 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5178 return PVE::QemuConfig->lock_config($vmid, sub {
5179 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5181 die "you can't start a vm
if it
's a template\n"
5182 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
5184 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended
');
5185 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup
');
5187 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5189 if ($has_backup_lock && $running) {
5190 # a backup is currently running, attempt to start the guest in the
5191 # existing QEMU instance
5192 return vm_resume($vmid);
5195 PVE::QemuConfig->check_lock($conf)
5196 if !($params->{skiplock} || $has_suspended_lock);
5198 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
5200 die "VM $vmid already running\n" if $running;
5202 if (my $storagemap = $migrate_opts->{storagemap}) {
5203 my $replicated = $migrate_opts->{replicated_volumes};
5204 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5205 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5207 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5208 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5212 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
5218 # statefile => 'tcp
', 'unix
' for migration or path/volid for RAM state
5219 # skiplock => 0/1, skip checking for config lock
5220 # skiptemplate => 0/1, skip checking whether VM is template
5221 # forcemachine => to force Qemu machine (rollback/migration)
5222 # forcecpu => a QEMU '-cpu
' argument string to override get_cpu_options
5223 # timeout => in seconds
5224 # paused => start VM in paused state (backup)
5225 # resume => resume from hibernation
5236 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
5237 # migratedfrom => source node
5238 # spice_ticket => used for spice migration, passed via tunnel/stdin
5239 # network => CIDR of migration network
5240 # type => secure/insecure - tunnel over encrypted connection or plain-text
5241 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
5242 # replicated_volumes = which volids should be re-used with bitmaps for nbd migration
5243 sub vm_start_nolock {
5244 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
5246 my $statefile = $params->{statefile};
5247 my $resume = $params->{resume};
5249 my $migratedfrom = $migrate_opts->{migratedfrom};
5250 my $migration_type = $migrate_opts->{type};
5254 # clean up leftover reboot request files
5255 eval { clear_reboot_request($vmid); };
5258 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5259 vmconfig_apply_pending($vmid, $conf, $storecfg);
5260 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5263 # don't regenerate the ISO
if the VM
is started as part of a live migration
5264 # this way we can reuse the old ISO with the correct config
5265 PVE
::QemuServer
::Cloudinit
::generate_cloudinitconfig
($conf, $vmid) if !$migratedfrom;
5267 my $defaults = load_defaults
();
5269 # set environment variable useful inside network script
5270 $ENV{PVE_MIGRATED_FROM
} = $migratedfrom if $migratedfrom;
5272 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-start', 1);
5274 my $forcemachine = $params->{forcemachine
};
5275 my $forcecpu = $params->{forcecpu
};
5277 # enforce machine and CPU type on suspended vm to ensure HW compatibility
5278 $forcemachine = $conf->{runningmachine
};
5279 $forcecpu = $conf->{runningcpu
};
5280 print "Resuming suspended VM\n";
5283 my ($cmd, $vollist, $spice_port) = config_to_command
($storecfg, $vmid,
5284 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
5287 my $get_migration_ip = sub {
5288 my ($nodename) = @_;
5290 return $migration_ip if defined($migration_ip);
5292 my $cidr = $migrate_opts->{network
};
5294 if (!defined($cidr)) {
5295 my $dc_conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5296 $cidr = $dc_conf->{migration
}->{network
};
5299 if (defined($cidr)) {
5300 my $ips = PVE
::Network
::get_local_ip_from_cidr
($cidr);
5302 die "could not get IP: no address configured on local " .
5303 "node for network '$cidr'\n" if scalar(@$ips) == 0;
5305 die "could not get IP: multiple addresses configured on local " .
5306 "node for network '$cidr'\n" if scalar(@$ips) > 1;
5308 $migration_ip = @$ips[0];
5311 $migration_ip = PVE
::Cluster
::remote_node_ip
($nodename, 1)
5312 if !defined($migration_ip);
5314 return $migration_ip;
5319 if ($statefile eq 'tcp') {
5320 my $localip = "localhost";
5321 my $datacenterconf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5322 my $nodename = nodename
();
5324 if (!defined($migration_type)) {
5325 if (defined($datacenterconf->{migration
}->{type
})) {
5326 $migration_type = $datacenterconf->{migration
}->{type
};
5328 $migration_type = 'secure';
5332 if ($migration_type eq 'insecure') {
5333 $localip = $get_migration_ip->($nodename);
5334 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5337 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5338 my $migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5339 $migrate_uri = "tcp:${localip}:${migrate_port}";
5340 push @$cmd, '-incoming', $migrate_uri;
5343 } elsif ($statefile eq 'unix') {
5344 # should be default for secure migrations as a ssh TCP forward
5345 # tunnel is not deterministic reliable ready and fails regurarly
5346 # to set up in time, so use UNIX socket forwards
5347 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5348 unlink $socket_addr;
5350 $migrate_uri = "unix:$socket_addr";
5352 push @$cmd, '-incoming', $migrate_uri;
5355 } elsif (-e
$statefile) {
5356 push @$cmd, '-loadstate', $statefile;
5358 my $statepath = PVE
::Storage
::path
($storecfg, $statefile);
5359 push @$vollist, $statefile;
5360 push @$cmd, '-loadstate', $statepath;
5362 } elsif ($params->{paused
}) {
5366 my $start_timeout = $params->{timeout
} // config_aware_timeout
($conf, $resume);
5368 my $pci_devices = {}; # host pci devices
5369 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
5370 my $dev = $conf->{"hostpci$i"} or next;
5371 $pci_devices->{$i} = parse_hostpci
($dev);
5374 my $pci_id_list = [ map { $_->{id
} } map { $_->{pciid
}->@* } values $pci_devices->%* ];
5375 # reserve all PCI IDs before actually doing anything with them
5376 PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_id_list, $vmid, $start_timeout);
5379 for my $id (sort keys %$pci_devices) {
5380 my $d = $pci_devices->{$id};
5381 for my $dev ($d->{pciid
}->@*) {
5382 PVE
::QemuServer
::PCI
::prepare_pci_device
($vmid, $dev->{id
}, $id, $d->{mdev
});
5387 eval { PVE
::QemuServer
::PCI
::remove_pci_reservation
($pci_id_list) };
5392 PVE
::Storage
::activate_volumes
($storecfg, $vollist);
5395 run_command
(['/bin/systemctl', 'stop', "$vmid.scope"], outfunc
=> sub{}, errfunc
=> sub{});
5397 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5398 # timeout should be more than enough here...
5399 PVE
::Systemd
::wait_for_unit_removed
("$vmid.scope", 5);
5401 my $cpuunits = get_cpuunits
($conf);
5404 timeout
=> $statefile ?
undef : $start_timeout,
5409 # when migrating, prefix QEMU output so other side can pick up any
5410 # errors that might occur and show the user
5411 if ($migratedfrom) {
5412 $run_params{quiet
} = 1;
5413 $run_params{logfunc
} = sub { print "QEMU: $_[0]\n" };
5416 my %systemd_properties = (
5417 Slice
=> 'qemu.slice',
5418 KillMode
=> 'process',
5420 TimeoutStopUSec
=> ULONG_MAX
, # infinity
5423 if (PVE
::CGroup
::cgroup_mode
() == 2) {
5424 $cpuunits = 10000 if $cpuunits >= 10000; # else we get an error
5425 $systemd_properties{CPUWeight
} = $cpuunits;
5427 $systemd_properties{CPUShares
} = $cpuunits;
5430 if (my $cpulimit = $conf->{cpulimit
}) {
5431 $systemd_properties{CPUQuota
} = int($cpulimit * 100);
5433 $systemd_properties{timeout
} = 10 if $statefile; # setting up the scope shoul be quick
5435 my $run_qemu = sub {
5436 PVE
::Tools
::run_fork
sub {
5437 PVE
::Systemd
::enter_systemd_scope
($vmid, "Proxmox VE VM $vmid", %systemd_properties);
5440 if (my $tpm = $conf->{tpmstate0
}) {
5441 # start the TPM emulator so QEMU can connect on start
5442 $tpmpid = start_swtpm
($storecfg, $vmid, $tpm, $migratedfrom);
5445 my $exitcode = run_command
($cmd, %run_params);
5447 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
5448 kill 'TERM', $tpmpid if $tpmpid;
5449 die "QEMU exited with code $exitcode\n";
5454 if ($conf->{hugepages
}) {
5457 my $hugepages_topology = PVE
::QemuServer
::Memory
::hugepages_topology
($conf);
5458 my $hugepages_host_topology = PVE
::QemuServer
::Memory
::hugepages_host_topology
();
5460 PVE
::QemuServer
::Memory
::hugepages_mount
();
5461 PVE
::QemuServer
::Memory
::hugepages_allocate
($hugepages_topology, $hugepages_host_topology);
5463 eval { $run_qemu->() };
5465 PVE
::QemuServer
::Memory
::hugepages_reset
($hugepages_host_topology)
5466 if !$conf->{keephugepages
};
5470 PVE
::QemuServer
::Memory
::hugepages_pre_deallocate
($hugepages_topology)
5471 if !$conf->{keephugepages
};
5473 eval { PVE
::QemuServer
::Memory
::hugepages_update_locked
($code); };
5476 eval { $run_qemu->() };
5480 # deactivate volumes if start fails
5481 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
5482 eval { PVE
::QemuServer
::PCI
::remove_pci_reservation
($pci_id_list) };
5484 die "start failed: $err";
5487 # re-reserve all PCI IDs now that we can know the actual VM PID
5488 my $pid = PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
5489 eval { PVE
::QemuServer
::PCI
::reserve_pci_usage
($pci_id_list, $vmid, undef, $pid) };
5492 print "migration listens on $migrate_uri\n" if $migrate_uri;
5493 $res->{migrate_uri
} = $migrate_uri;
5495 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5496 eval { mon_cmd
($vmid, "cont"); };
5500 #start nbd server for storage migration
5501 if (my $nbd = $migrate_opts->{nbd
}) {
5502 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version
} // 0;
5504 my $migrate_storage_uri;
5505 # nbd_protocol_version > 0 for unix socket support
5506 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5507 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5508 mon_cmd
($vmid, "nbd-server-start", addr
=> { type
=> 'unix', data
=> { path
=> $socket_path } } );
5509 $migrate_storage_uri = "nbd:unix:$socket_path";
5511 my $nodename = nodename
();
5512 my $localip = $get_migration_ip->($nodename);
5513 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5514 my $storage_migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5516 mon_cmd
($vmid, "nbd-server-start", addr
=> {
5519 host
=> "${localip}",
5520 port
=> "${storage_migrate_port}",
5523 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5524 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5527 $res->{migrate_storage_uri
} = $migrate_storage_uri;
5529 foreach my $opt (sort keys %$nbd) {
5530 my $drivestr = $nbd->{$opt}->{drivestr
};
5531 my $volid = $nbd->{$opt}->{volid
};
5532 mon_cmd
($vmid, "nbd-server-add", device
=> "drive-$opt", writable
=> JSON
::true
);
5533 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5534 print "storage migration listens on $nbd_uri volume:$drivestr\n";
5535 print "re-using replicated volume: $opt - $volid\n"
5536 if $nbd->{$opt}->{replicated
};
5538 $res->{drives
}->{$opt} = $nbd->{$opt};
5539 $res->{drives
}->{$opt}->{nbd_uri
} = $nbd_uri;
5543 if ($migratedfrom) {
5545 set_migration_caps
($vmid);
5550 print "spice listens on port $spice_port\n";
5551 $res->{spice_port
} = $spice_port;
5552 if ($migrate_opts->{spice_ticket
}) {
5553 mon_cmd
($vmid, "set_password", protocol
=> 'spice', password
=>
5554 $migrate_opts->{spice_ticket
});
5555 mon_cmd
($vmid, "expire_password", protocol
=> 'spice', time => "+30");
5560 mon_cmd
($vmid, "balloon", value
=> $conf->{balloon
}*1024*1024)
5561 if !$statefile && $conf->{balloon
};
5563 foreach my $opt (keys %$conf) {
5564 next if $opt !~ m/^net\d+$/;
5565 my $nicconf = parse_net
($conf->{$opt});
5566 qemu_set_link_status
($vmid, $opt, 0) if $nicconf->{link_down
};
5570 mon_cmd
($vmid, 'qom-set',
5571 path
=> "machine/peripheral/balloon0",
5572 property
=> "guest-stats-polling-interval",
5573 value
=> 2) if (!defined($conf->{balloon
}) || $conf->{balloon
});
5576 print "Resumed VM, removing state\n";
5577 if (my $vmstate = $conf->{vmstate
}) {
5578 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5579 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5581 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
5582 PVE
::QemuConfig-
>write_config($vmid, $conf);
5585 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5590 sub vm_commandline
{
5591 my ($storecfg, $vmid, $snapname) = @_;
5593 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5598 my $snapshot = $conf->{snapshots
}->{$snapname};
5599 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5601 # check for machine or CPU overrides in snapshot
5602 $forcemachine = $snapshot->{runningmachine
};
5603 $forcecpu = $snapshot->{runningcpu
};
5605 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5610 my $defaults = load_defaults
();
5612 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults,
5613 $forcemachine, $forcecpu);
5615 return PVE
::Tools
::cmd2string
($cmd);
5619 my ($vmid, $skiplock) = @_;
5621 PVE
::QemuConfig-
>lock_config($vmid, sub {
5623 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5625 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5627 mon_cmd
($vmid, "system_reset");
5631 sub get_vm_volumes
{
5635 foreach_volid
($conf, sub {
5636 my ($volid, $attr) = @_;
5638 return if $volid =~ m
|^/|;
5640 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5643 push @$vollist, $volid;
5649 sub vm_stop_cleanup
{
5650 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5655 my $vollist = get_vm_volumes
($conf);
5656 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5658 if (my $tpmdrive = $conf->{tpmstate0
}) {
5659 my $tpm = parse_drive
("tpmstate0", $tpmdrive);
5660 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($tpm->{file
}, 1);
5662 PVE
::Storage
::unmap_volume
($storecfg, $tpm->{file
});
5667 foreach my $ext (qw(mon qmp pid vnc qga)) {
5668 unlink "/var/run/qemu-server/${vmid}.$ext";
5671 if ($conf->{ivshmem
}) {
5672 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5673 # just delete it for now, VMs which have this already open do not
5674 # are affected, but new VMs will get a separated one. If this
5675 # becomes an issue we either add some sort of ref-counting or just
5676 # add a "don't delete on stop" flag to the ivshmem format.
5677 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5681 foreach my $key (keys %$conf) {
5682 next if $key !~ m/^hostpci(\d+)$/;
5683 my $hostpciindex = $1;
5684 my $d = parse_hostpci
($conf->{$key});
5685 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5687 foreach my $pci (@{$d->{pciid
}}) {
5688 my $pciid = $pci->{id
};
5689 push @$ids, $pci->{id
};
5690 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5693 PVE
::QemuServer
::PCI
::remove_pci_reservation
($ids);
5695 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5697 warn $@ if $@; # avoid errors - just warn
5700 # call only in locked context
5702 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5704 my $pid = check_running
($vmid, $nocheck);
5709 $conf = PVE
::QemuConfig-
>load_config($vmid);
5710 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5711 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5712 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5713 $timeout = $opts->{down
} if $opts->{down
};
5715 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5720 if (defined($conf) && get_qga_key
($conf, 'enabled')) {
5721 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5723 mon_cmd
($vmid, "system_powerdown");
5726 mon_cmd
($vmid, "quit");
5732 $timeout = 60 if !defined($timeout);
5735 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5740 if ($count >= $timeout) {
5742 warn "VM still running - terminating now with SIGTERM\n";
5745 die "VM quit/powerdown failed - got timeout\n";
5748 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5752 if (!check_running
($vmid, $nocheck)) {
5753 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5757 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5760 die "VM quit/powerdown failed\n";
5768 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5773 if ($count >= $timeout) {
5774 warn "VM still running - terminating now with SIGKILL\n";
5779 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5782 # Note: use $nocheck to skip tests if VM configuration file exists.
5783 # We need that when migration VMs to other nodes (files already moved)
5784 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5786 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5788 $force = 1 if !defined($force) && !$shutdown;
5791 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5792 kill 15, $pid if $pid;
5793 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5794 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5798 PVE
::QemuConfig-
>lock_config($vmid, sub {
5799 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5804 my ($vmid, $timeout) = @_;
5806 PVE
::QemuConfig-
>lock_config($vmid, sub {
5809 # only reboot if running, as qmeventd starts it again on a stop event
5810 return if !check_running
($vmid);
5812 create_reboot_request
($vmid);
5814 my $storecfg = PVE
::Storage
::config
();
5815 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5819 # avoid that the next normal shutdown will be confused for a reboot
5820 clear_reboot_request
($vmid);
5826 # note: if using the statestorage parameter, the caller has to check privileges
5828 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5835 PVE
::QemuConfig-
>lock_config($vmid, sub {
5837 $conf = PVE
::QemuConfig-
>load_config($vmid);
5839 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5840 PVE
::QemuConfig-
>check_lock($conf)
5841 if !($skiplock || $is_backing_up);
5843 die "cannot suspend to disk during backup\n"
5844 if $is_backing_up && $includestate;
5846 if ($includestate) {
5847 $conf->{lock} = 'suspending';
5848 my $date = strftime
("%Y-%m-%d", localtime(time()));
5849 $storecfg = PVE
::Storage
::config
();
5850 if (!$statestorage) {
5851 $statestorage = find_vmstate_storage
($conf, $storecfg);
5852 # check permissions for the storage
5853 my $rpcenv = PVE
::RPCEnvironment
::get
();
5854 if ($rpcenv->{type
} ne 'cli') {
5855 my $authuser = $rpcenv->get_user();
5856 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5861 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate(
5862 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5863 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5864 PVE
::QemuConfig-
>write_config($vmid, $conf);
5866 mon_cmd
($vmid, "stop");
5870 if ($includestate) {
5872 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5875 set_migration_caps
($vmid, 1);
5876 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5878 my $state = mon_cmd
($vmid, "query-savevm");
5879 if (!$state->{status
}) {
5880 die "savevm not active\n";
5881 } elsif ($state->{status
} eq 'active') {
5884 } elsif ($state->{status
} eq 'completed') {
5885 print "State saved, quitting\n";
5887 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5888 die "query-savevm failed with error '$state->{error}'\n"
5890 die "query-savevm returned status '$state->{status}'\n";
5896 PVE
::QemuConfig-
>lock_config($vmid, sub {
5897 $conf = PVE
::QemuConfig-
>load_config($vmid);
5899 # cleanup, but leave suspending lock, to indicate something went wrong
5901 mon_cmd
($vmid, "savevm-end");
5902 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5903 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5904 delete $conf->@{qw(vmstate runningmachine runningcpu)};
5905 PVE
::QemuConfig-
>write_config($vmid, $conf);
5911 die "lock changed unexpectedly\n"
5912 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5914 mon_cmd
($vmid, "quit");
5915 $conf->{lock} = 'suspended';
5916 PVE
::QemuConfig-
>write_config($vmid, $conf);
5922 my ($vmid, $skiplock, $nocheck) = @_;
5924 PVE
::QemuConfig-
>lock_config($vmid, sub {
5925 my $res = mon_cmd
($vmid, 'query-status');
5926 my $resume_cmd = 'cont';
5929 if ($res->{status
}) {
5930 return if $res->{status
} eq 'running'; # job done, go home
5931 $resume_cmd = 'system_wakeup' if $res->{status
} eq 'suspended';
5932 $reset = 1 if $res->{status
} eq 'shutdown';
5937 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5939 PVE
::QemuConfig-
>check_lock($conf)
5940 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5944 # required if a VM shuts down during a backup and we get a resume
5945 # request before the backup finishes for example
5946 mon_cmd
($vmid, "system_reset");
5948 mon_cmd
($vmid, $resume_cmd);
5953 my ($vmid, $skiplock, $key) = @_;
5955 PVE
::QemuConfig-
>lock_config($vmid, sub {
5957 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5959 # there is no qmp command, so we use the human monitor command
5960 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5961 die $res if $res ne '';
5965 # vzdump restore implementaion
5967 sub tar_archive_read_firstfile
{
5968 my $archive = shift;
5970 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5972 # try to detect archive type first
5973 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5974 die "unable to open file '$archive'\n";
5975 my $firstfile = <$fh>;
5979 die "ERROR: archive contaions no data\n" if !$firstfile;
5985 sub tar_restore_cleanup
{
5986 my ($storecfg, $statfile) = @_;
5988 print STDERR
"starting cleanup\n";
5990 if (my $fd = IO
::File-
>new($statfile, "r")) {
5991 while (defined(my $line = <$fd>)) {
5992 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5995 if ($volid =~ m
|^/|) {
5996 unlink $volid || die 'unlink failed\n';
5998 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6000 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6002 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6004 print STDERR
"unable to parse line in statfile - $line";
6011 sub restore_file_archive
{
6012 my ($archive, $vmid, $user, $opts) = @_;
6014 return restore_vma_archive
($archive, $vmid, $user, $opts)
6017 my $info = PVE
::Storage
::archive_info
($archive);
6018 my $format = $opts->{format
} // $info->{format
};
6019 my $comp = $info->{compression
};
6021 # try to detect archive format
6022 if ($format eq 'tar') {
6023 return restore_tar_archive
($archive, $vmid, $user, $opts);
6025 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
6029 # hepler to remove disks that will not be used after restore
6030 my $restore_cleanup_oldconf = sub {
6031 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6033 PVE
::QemuConfig-
>foreach_volume($oldconf, sub {
6034 my ($ds, $drive) = @_;
6036 return if drive_is_cdrom
($drive, 1);
6038 my $volid = $drive->{file
};
6039 return if !$volid || $volid =~ m
|^/|;
6041 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
6042 return if !$path || !$owner || ($owner != $vmid);
6044 # Note: only delete disk we want to restore
6045 # other volumes will become unused
6046 if ($virtdev_hash->{$ds}) {
6047 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
6054 # delete vmstate files, after the restore we have no snapshots anymore
6055 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6056 my $snap = $oldconf->{snapshots
}->{$snapname};
6057 if ($snap->{vmstate
}) {
6058 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
6066 # Helper to parse vzdump backup device hints
6068 # $rpcenv: Environment, used to ckeck storage permissions
6069 # $user: User ID, to check storage permissions
6070 # $storecfg: Storage configuration
6071 # $fh: the file handle for reading the configuration
6072 # $devinfo: should contain device sizes for all backu-up'ed devices
6073 # $options: backup options (pool, default storage)
6075 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6076 my $parse_backup_hints = sub {
6077 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
6079 my $virtdev_hash = {};
6081 while (defined(my $line = <$fh>)) {
6082 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6083 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6084 die "archive does not contain data for drive '$virtdev'\n"
6085 if !$devinfo->{$devname};
6087 if (defined($options->{storage
})) {
6088 $storeid = $options->{storage
} || 'local';
6089 } elsif (!$storeid) {
6092 $format = 'raw' if !$format;
6093 $devinfo->{$devname}->{devname
} = $devname;
6094 $devinfo->{$devname}->{virtdev
} = $virtdev;
6095 $devinfo->{$devname}->{format
} = $format;
6096 $devinfo->{$devname}->{storeid
} = $storeid;
6098 # check permission on storage
6099 my $pool = $options->{pool
}; # todo: do we need that?
6100 if ($user ne 'root@pam') {
6101 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6104 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6105 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6107 my $drive = parse_drive
($virtdev, $2);
6108 if (drive_is_cloudinit
($drive)) {
6109 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6110 $storeid = $options->{storage
} if defined ($options->{storage
});
6111 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6112 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
6114 $virtdev_hash->{$virtdev} = {
6116 storeid
=> $storeid,
6117 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6124 return $virtdev_hash;
6127 # Helper to allocate and activate all volumes required for a restore
6129 # $storecfg: Storage configuration
6130 # $virtdev_hash: as returned by parse_backup_hints()
6132 # Returns: { $virtdev => $volid }
6133 my $restore_allocate_devices = sub {
6134 my ($storecfg, $virtdev_hash, $vmid) = @_;
6137 foreach my $virtdev (sort keys %$virtdev_hash) {
6138 my $d = $virtdev_hash->{$virtdev};
6139 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6140 my $storeid = $d->{storeid
};
6141 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6143 # test if requested format is supported
6144 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6145 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6146 $d->{format
} = $defFormat if !$supported;
6149 if ($d->{is_cloudinit
}) {
6150 $name = "vm-$vmid-cloudinit";
6151 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6152 if ($scfg->{path
}) {
6153 $name .= ".$d->{format}";
6157 my $volid = PVE
::Storage
::vdisk_alloc
(
6158 $storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6160 print STDERR
"new volume ID is '$volid'\n";
6161 $d->{volid
} = $volid;
6163 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6165 $map->{$virtdev} = $volid;
6171 sub restore_update_config_line
{
6172 my ($cookie, $map, $line, $unique) = @_;
6174 return '' if $line =~ m/^\#qmdump\#/;
6175 return '' if $line =~ m/^\#vzdump\#/;
6176 return '' if $line =~ m/^lock:/;
6177 return '' if $line =~ m/^unused\d+:/;
6178 return '' if $line =~ m/^parent:/;
6182 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
6183 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6184 # try to convert old 1.X settings
6185 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6186 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
6187 my ($model, $macaddr) = split(/\=/, $devconfig);
6188 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
6191 bridge
=> "vmbr$ind",
6192 macaddr
=> $macaddr,
6194 my $netstr = print_net
($net);
6196 $res .= "net$cookie->{netcount}: $netstr\n";
6197 $cookie->{netcount
}++;
6199 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6200 my ($id, $netstr) = ($1, $2);
6201 my $net = parse_net
($netstr);
6202 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
6203 $netstr = print_net
($net);
6204 $res .= "$id: $netstr\n";
6205 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
6208 my $di = parse_drive
($virtdev, $value);
6209 if (defined($di->{backup
}) && !$di->{backup
}) {
6211 } elsif ($map->{$virtdev}) {
6212 delete $di->{format
}; # format can change on restore
6213 $di->{file
} = $map->{$virtdev};
6214 $value = print_drive
($di);
6215 $res .= "$virtdev: $value\n";
6219 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6221 if ($vmgenid ne '0') {
6222 # always generate a new vmgenid if there was a valid one setup
6223 $vmgenid = generate_uuid
();
6225 $res .= "vmgenid: $vmgenid\n";
6226 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6227 my ($uuid, $uuid_str);
6228 UUID
::generate
($uuid);
6229 UUID
::unparse
($uuid, $uuid_str);
6230 my $smbios1 = parse_smbios1
($2);
6231 $smbios1->{uuid
} = $uuid_str;
6232 $res .= $1.print_smbios1
($smbios1)."\n";
6240 my $restore_deactivate_volumes = sub {
6241 my ($storecfg, $devinfo) = @_;
6244 foreach my $devname (keys %$devinfo) {
6245 my $volid = $devinfo->{$devname}->{volid
};
6246 push @$vollist, $volid if $volid;
6249 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
6252 my $restore_destroy_volumes = sub {
6253 my ($storecfg, $devinfo) = @_;
6255 foreach my $devname (keys %$devinfo) {
6256 my $volid = $devinfo->{$devname}->{volid
};
6259 if ($volid =~ m
|^/|) {
6260 unlink $volid || die 'unlink failed\n';
6262 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6264 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6266 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6271 my ($cfg, $vmid) = @_;
6273 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid, undef, 'images');
6275 my $volid_hash = {};
6276 foreach my $storeid (keys %$info) {
6277 foreach my $item (@{$info->{$storeid}}) {
6278 next if !($item->{volid
} && $item->{size
});
6279 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6280 $volid_hash->{$item->{volid
}} = $item;
6287 sub update_disk_config
{
6288 my ($vmid, $conf, $volid_hash) = @_;
6291 my $prefix = "VM $vmid";
6293 # used and unused disks
6294 my $referenced = {};
6296 # Note: it is allowed to define multiple storages with same path (alias), so
6297 # we need to check both 'volid' and real 'path' (two different volid can point
6298 # to the same path).
6300 my $referencedpath = {};
6303 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6304 my ($opt, $drive) = @_;
6306 my $volid = $drive->{file
};
6308 my $volume = $volid_hash->{$volid};
6310 # mark volid as "in-use" for next step
6311 $referenced->{$volid} = 1;
6312 if ($volume && (my $path = $volume->{path
})) {
6313 $referencedpath->{$path} = 1;
6316 return if drive_is_cdrom
($drive);
6319 my ($updated, $msg) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volume->{size
});
6320 if (defined($updated)) {
6322 $conf->{$opt} = print_drive
($updated);
6323 print "$prefix ($opt): $msg\n";
6327 # remove 'unusedX' entry if volume is used
6328 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
6329 my ($opt, $drive) = @_;
6331 my $volid = $drive->{file
};
6335 $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6336 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6337 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
6339 delete $conf->{$opt};
6342 $referenced->{$volid} = 1;
6343 $referencedpath->{$path} = 1 if $path;
6346 foreach my $volid (sort keys %$volid_hash) {
6347 next if $volid =~ m/vm-$vmid-state-/;
6348 next if $referenced->{$volid};
6349 my $path = $volid_hash->{$volid}->{path
};
6350 next if !$path; # just to be sure
6351 next if $referencedpath->{$path};
6353 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6354 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
6355 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6362 my ($vmid, $nolock, $dryrun) = @_;
6364 my $cfg = PVE
::Storage
::config
();
6366 print "rescan volumes...\n";
6367 my $volid_hash = scan_volids
($cfg, $vmid);
6369 my $updatefn = sub {
6372 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6374 PVE
::QemuConfig-
>check_lock($conf);
6377 foreach my $volid (keys %$volid_hash) {
6378 my $info = $volid_hash->{$volid};
6379 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6382 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
6384 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6387 if (defined($vmid)) {
6391 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6394 my $vmlist = config_list
();
6395 foreach my $vmid (keys %$vmlist) {
6399 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6405 sub restore_proxmox_backup_archive
{
6406 my ($archive, $vmid, $user, $options) = @_;
6408 my $storecfg = PVE
::Storage
::config
();
6410 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
6411 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6413 my $fingerprint = $scfg->{fingerprint
};
6414 my $keyfile = PVE
::Storage
::PBSPlugin
::pbs_encryption_key_file_name
($storecfg, $storeid);
6416 my $repo = PVE
::PBSClient
::get_repository
($scfg);
6418 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
6419 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
6420 local $ENV{PBS_PASSWORD
} = $password;
6421 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
6423 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6424 PVE
::Storage
::parse_volname
($storecfg, $archive);
6426 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6428 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6430 my $tmpdir = "/var/tmp/vzdumptmp$$";
6434 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6435 # disable interrupts (always do cleanups)
6439 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6441 # Note: $oldconf is undef if VM does not exists
6442 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6443 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6444 my $new_conf_raw = '';
6446 my $rpcenv = PVE
::RPCEnvironment
::get
();
6455 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6457 my $cfgfn = "$tmpdir/qemu-server.conf";
6458 my $firewall_config_fn = "$tmpdir/fw.conf";
6459 my $index_fn = "$tmpdir/index.json";
6461 my $cmd = "restore";
6463 my $param = [$pbs_backup_name, "index.json", $index_fn];
6464 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6465 my $index = PVE
::Tools
::file_get_contents
($index_fn);
6466 $index = decode_json
($index);
6468 # print Dumper($index);
6469 foreach my $info (@{$index->{files
}}) {
6470 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
6472 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
6473 $devinfo->{$devname}->{size
} = $1;
6475 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6480 my $is_qemu_server_backup = scalar(
6481 grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}}
6483 if (!$is_qemu_server_backup) {
6484 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6486 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
6488 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6489 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6491 if ($has_firewall_config) {
6492 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6493 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6495 my $pve_firewall_dir = '/etc/pve/firewall';
6496 mkdir $pve_firewall_dir; # make sure the dir exists
6497 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6500 my $fh = IO
::File-
>new($cfgfn, "r") ||
6501 die "unable to read qemu-server.conf - $!\n";
6503 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6505 # fixme: rate limit?
6507 # create empty/temp config
6508 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6510 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6513 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6515 foreach my $virtdev (sort keys %$virtdev_hash) {
6516 my $d = $virtdev_hash->{$virtdev};
6517 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6519 # this fails if storage is unavailable
6520 my $volid = $d->{volid
};
6521 my $path = PVE
::Storage
::path
($storecfg, $volid);
6523 # for live-restore we only want to preload the efidisk and TPM state
6524 next if $options->{live
} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
6526 my $pbs_restore_cmd = [
6527 '/usr/bin/pbs-restore',
6528 '--repository', $repo,
6530 "$d->{devname}.img.fidx",
6535 push @$pbs_restore_cmd, '--format', $d->{format
} if $d->{format
};
6536 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e
$keyfile;
6538 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6539 push @$pbs_restore_cmd, '--skip-zero';
6542 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6543 print "restore proxmox backup image: $dbg_cmdstring\n";
6544 run_command
($pbs_restore_cmd);
6547 $fh->seek(0, 0) || die "seek failed - $!\n";
6549 my $cookie = { netcount
=> 0 };
6550 while (defined(my $line = <$fh>)) {
6551 $new_conf_raw .= restore_update_config_line
(
6563 if ($err || !$options->{live
}) {
6564 $restore_deactivate_volumes->($storecfg, $devinfo);
6570 $restore_destroy_volumes->($storecfg, $devinfo);
6574 if ($options->{live
}) {
6575 # keep lock during live-restore
6576 $new_conf_raw .= "\nlock: create";
6579 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6581 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6583 eval { rescan
($vmid, 1); };
6586 PVE
::AccessControl
::add_vm_to_pool
($vmid, $options->{pool
}) if $options->{pool
};
6588 if ($options->{live
}) {
6594 local $SIG{PIPE
} = sub { die "got signal ($!) - abort\n"; };
6596 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6597 die "cannot do live-restore for template\n" if PVE
::QemuConfig-
>is_template($conf);
6599 # these special drives are already restored before start
6600 delete $devinfo->{'drive-efidisk0'};
6601 delete $devinfo->{'drive-tpmstate0-backup'};
6602 pbs_live_restore
($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
6604 PVE
::QemuConfig-
>remove_lock($vmid, "create");
6608 sub pbs_live_restore
{
6609 my ($vmid, $conf, $storecfg, $restored_disks, $repo, $keyfile, $snap) = @_;
6611 print "starting VM for live-restore\n";
6612 print "repository: '$repo', snapshot: '$snap'\n";
6614 my $pbs_backing = {};
6615 for my $ds (keys %$restored_disks) {
6616 $ds =~ m/^drive-(.*)$/;
6618 $pbs_backing->{$confname} = {
6619 repository
=> $repo,
6621 archive
=> "$ds.img.fidx",
6623 $pbs_backing->{$confname}->{keyfile
} = $keyfile if -e
$keyfile;
6625 my $drive = parse_drive
($confname, $conf->{$confname});
6626 print "restoring '$ds' to '$drive->{file}'\n";
6629 my $drives_streamed = 0;
6631 # make sure HA doesn't interrupt our restore by stopping the VM
6632 if (PVE
::HA
::Config
::vm_is_ha_managed
($vmid)) {
6633 run_command
(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
6636 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6637 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
6638 vm_start_nolock
($storecfg, $vmid, $conf, {paused
=> 1, 'pbs-backing' => $pbs_backing}, {});
6640 my $qmeventd_fd = register_qmeventd_handle
($vmid);
6642 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6643 # this will effectively collapse the backing image chain consisting of
6644 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6645 # removes itself once all backing images vanish with 'auto-remove=on')
6647 for my $ds (sort keys %$restored_disks) {
6648 my $job_id = "restore-$ds";
6649 mon_cmd
($vmid, 'block-stream',
6650 'job-id' => $job_id,
6653 $jobs->{$job_id} = {};
6656 mon_cmd
($vmid, 'cont');
6657 qemu_drive_mirror_monitor
($vmid, undef, $jobs, 'auto', 0, 'stream');
6659 print "restore-drive jobs finished successfully, removing all tracking block devices"
6660 ." to disconnect from Proxmox Backup Server\n";
6662 for my $ds (sort keys %$restored_disks) {
6663 mon_cmd
($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6666 close($qmeventd_fd);
6672 warn "An error occured during live-restore: $err\n";
6673 _do_vm_stop
($storecfg, $vmid, 1, 1, 10, 0, 1);
6674 die "live-restore failed\n";
6678 sub restore_vma_archive
{
6679 my ($archive, $vmid, $user, $opts, $comp) = @_;
6681 my $readfrom = $archive;
6683 my $cfg = PVE
::Storage
::config
();
6685 my $bwlimit = $opts->{bwlimit
};
6687 my $dbg_cmdstring = '';
6688 my $add_pipe = sub {
6690 push @$commands, $cmd;
6691 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6692 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6697 if ($archive eq '-') {
6700 # If we use a backup from a PVE defined storage we also consider that
6701 # storage's rate limit:
6702 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6703 if (defined($volid)) {
6704 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6705 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6707 print STDERR
"applying read rate limit: $readlimit\n";
6708 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6709 $add_pipe->($cstream);
6715 my $info = PVE
::Storage
::decompressor_info
('vma', $comp);
6716 my $cmd = $info->{decompressor
};
6717 push @$cmd, $readfrom;
6721 my $tmpdir = "/var/tmp/vzdumptmp$$";
6724 # disable interrupts (always do cleanups)
6728 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6730 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6731 POSIX
::mkfifo
($mapfifo, 0600);
6733 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
6735 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6742 my $rpcenv = PVE
::RPCEnvironment
::get
();
6744 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6746 # Note: $oldconf is undef if VM does not exist
6747 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6748 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6749 my $new_conf_raw = '';
6753 my $print_devmap = sub {
6754 my $cfgfn = "$tmpdir/qemu-server.conf";
6756 # we can read the config - that is already extracted
6757 my $fh = IO
::File-
>new($cfgfn, "r") ||
6758 die "unable to read qemu-server.conf - $!\n";
6760 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6762 my $pve_firewall_dir = '/etc/pve/firewall';
6763 mkdir $pve_firewall_dir; # make sure the dir exists
6764 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6767 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6769 foreach my $info (values %{$virtdev_hash}) {
6770 my $storeid = $info->{storeid
};
6771 next if defined($storage_limits{$storeid});
6773 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$storeid], $bwlimit) // 0;
6774 print STDERR
"rate limit for storage $storeid: $limit KiB/s\n" if $limit;
6775 $storage_limits{$storeid} = $limit * 1024;
6778 foreach my $devname (keys %$devinfo) {
6779 die "found no device mapping information for device '$devname'\n"
6780 if !$devinfo->{$devname}->{virtdev
};
6783 # create empty/temp config
6785 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6786 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6790 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6792 # print restore information to $fifofh
6793 foreach my $virtdev (sort keys %$virtdev_hash) {
6794 my $d = $virtdev_hash->{$virtdev};
6795 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6797 my $storeid = $d->{storeid
};
6798 my $volid = $d->{volid
};
6801 if (my $limit = $storage_limits{$storeid}) {
6802 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6805 my $write_zeros = 1;
6806 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6810 my $path = PVE
::Storage
::path
($cfg, $volid);
6812 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6814 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6817 $fh->seek(0, 0) || die "seek failed - $!\n";
6819 my $cookie = { netcount
=> 0 };
6820 while (defined(my $line = <$fh>)) {
6821 $new_conf_raw .= restore_update_config_line
(
6838 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6839 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6841 $oldtimeout = alarm($timeout);
6848 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6849 my ($dev_id, $size, $devname) = ($1, $2, $3);
6850 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6851 } elsif ($line =~ m/^CTIME: /) {
6852 # we correctly received the vma config, so we can disable
6853 # the timeout now for disk allocation (set to 10 minutes, so
6854 # that we always timeout if something goes wrong)
6857 print $fifofh "done\n";
6858 my $tmp = $oldtimeout || 0;
6859 $oldtimeout = undef;
6866 print "restore vma archive: $dbg_cmdstring\n";
6867 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6871 alarm($oldtimeout) if $oldtimeout;
6873 $restore_deactivate_volumes->($cfg, $devinfo);
6875 close($fifofh) if $fifofh;
6880 $restore_destroy_volumes->($cfg, $devinfo);
6884 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6886 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6888 eval { rescan
($vmid, 1); };
6891 PVE
::AccessControl
::add_vm_to_pool
($vmid, $opts->{pool
}) if $opts->{pool
};
6894 sub restore_tar_archive
{
6895 my ($archive, $vmid, $user, $opts) = @_;
6897 if ($archive ne '-') {
6898 my $firstfile = tar_archive_read_firstfile
($archive);
6899 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
6900 if $firstfile ne 'qemu-server.conf';
6903 my $storecfg = PVE
::Storage
::config
();
6905 # avoid zombie disks when restoring over an existing VM -> cleanup first
6906 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6907 # skiplock=1 because qmrestore has set the 'create' lock itself already
6908 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6909 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6911 my $tocmd = "/usr/lib/qemu-server/qmextract";
6913 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6914 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6915 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6916 $tocmd .= ' --info' if $opts->{info
};
6918 # tar option "xf" does not autodetect compression when read from STDIN,
6919 # so we pipe to zcat
6920 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6921 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6923 my $tmpdir = "/var/tmp/vzdumptmp$$";
6926 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6927 local $ENV{VZDUMP_VMID
} = $vmid;
6928 local $ENV{VZDUMP_USER
} = $user;
6930 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6931 my $new_conf_raw = '';
6933 # disable interrupts (always do cleanups)
6937 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6945 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6947 if ($archive eq '-') {
6948 print "extracting archive from STDIN\n";
6949 run_command
($cmd, input
=> "<&STDIN");
6951 print "extracting archive '$archive'\n";
6955 return if $opts->{info
};
6959 my $statfile = "$tmpdir/qmrestore.stat";
6960 if (my $fd = IO
::File-
>new($statfile, "r")) {
6961 while (defined (my $line = <$fd>)) {
6962 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6963 $map->{$1} = $2 if $1;
6965 print STDERR
"unable to parse line in statfile - $line\n";
6971 my $confsrc = "$tmpdir/qemu-server.conf";
6973 my $srcfd = IO
::File-
>new($confsrc, "r") || die "unable to open file '$confsrc'\n";
6975 my $cookie = { netcount
=> 0 };
6976 while (defined (my $line = <$srcfd>)) {
6977 $new_conf_raw .= restore_update_config_line
(
6988 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6994 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6996 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6998 eval { rescan
($vmid, 1); };
7002 sub foreach_storage_used_by_vm
{
7003 my ($conf, $func) = @_;
7007 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7008 my ($ds, $drive) = @_;
7009 return if drive_is_cdrom
($drive);
7011 my $volid = $drive->{file
};
7013 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
7014 $sidhash->{$sid} = $sid if $sid;
7017 foreach my $sid (sort keys %$sidhash) {
7022 my $qemu_snap_storage = {
7025 sub do_snapshots_with_qemu
{
7026 my ($storecfg, $volid, $deviceid) = @_;
7028 return if $deviceid =~ m/tpmstate0/;
7030 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
7031 my $scfg = $storecfg->{ids
}->{$storage_name};
7032 die "could not find storage '$storage_name'\n" if !defined($scfg);
7034 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
7038 if ($volid =~ m/\.(qcow2|qed)$/){
7045 sub qga_check_running
{
7046 my ($vmid, $nowarn) = @_;
7048 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
7050 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
7056 sub template_create
{
7057 my ($vmid, $conf, $disk) = @_;
7059 my $storecfg = PVE
::Storage
::config
();
7061 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7062 my ($ds, $drive) = @_;
7064 return if drive_is_cdrom
($drive);
7065 return if $disk && $ds ne $disk;
7067 my $volid = $drive->{file
};
7068 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
7070 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
7071 $drive->{file
} = $voliddst;
7072 $conf->{$ds} = print_drive
($drive);
7073 PVE
::QemuConfig-
>write_config($vmid, $conf);
7077 sub convert_iscsi_path
{
7080 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
7085 my $initiator_name = get_initiator_name
();
7087 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7088 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7091 die "cannot convert iscsi path '$path', unkown format\n";
7094 sub qemu_img_convert
{
7095 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
7097 my $storecfg = PVE
::Storage
::config
();
7098 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
7099 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
7101 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
7105 my $src_is_iscsi = 0;
7109 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
7110 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
7111 $src_format = qemu_img_format
($src_scfg, $src_volname);
7112 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
7113 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
7114 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
7115 } elsif (-f
$src_volid) {
7116 $src_path = $src_volid;
7117 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7122 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
7124 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7125 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
7126 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7127 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
7130 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
7131 push @$cmd, '-l', "snapshot.name=$snapname"
7132 if $snapname && $src_format && $src_format eq "qcow2";
7133 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
7134 push @$cmd, '-T', $cachemode if defined($cachemode);
7136 if ($src_is_iscsi) {
7137 push @$cmd, '--image-opts';
7138 $src_path = convert_iscsi_path
($src_path);
7139 } elsif ($src_format) {
7140 push @$cmd, '-f', $src_format;
7143 if ($dst_is_iscsi) {
7144 push @$cmd, '--target-image-opts';
7145 $dst_path = convert_iscsi_path
($dst_path);
7147 push @$cmd, '-O', $dst_format;
7150 push @$cmd, $src_path;
7152 if (!$dst_is_iscsi && $is_zero_initialized) {
7153 push @$cmd, "zeroinit:$dst_path";
7155 push @$cmd, $dst_path;
7160 if($line =~ m/\((\S+)\/100\
%\)/){
7162 my $transferred = int($size * $percent / 100);
7163 my $total_h = render_bytes
($size, 1);
7164 my $transferred_h = render_bytes
($transferred, 1);
7166 print "transferred $transferred_h of $total_h ($percent%)\n";
7171 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
7173 die "copy failed: $err" if $err;
7176 sub qemu_img_format
{
7177 my ($scfg, $volname) = @_;
7179 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7186 sub qemu_drive_mirror
{
7187 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
7189 $jobs = {} if !$jobs;
7193 $jobs->{"drive-$drive"} = {};
7195 if ($dst_volid =~ /^nbd:/) {
7196 $qemu_target = $dst_volid;
7199 my $storecfg = PVE
::Storage
::config
();
7200 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
7202 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7204 $format = qemu_img_format
($dst_scfg, $dst_volname);
7206 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7208 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
7211 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
7212 $opts->{format
} = $format if $format;
7214 if (defined($src_bitmap)) {
7215 $opts->{sync
} = 'incremental';
7216 $opts->{bitmap
} = $src_bitmap;
7217 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7220 if (defined($bwlimit)) {
7221 $opts->{speed
} = $bwlimit * 1024;
7222 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
7224 print "drive mirror is starting for drive-$drive\n";
7227 # if a job already runs for this device we get an error, catch it for cleanup
7228 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
7230 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7232 die "mirroring error: $err\n";
7235 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
7238 # $completion can be either
7239 # 'complete': wait until all jobs are ready, block-job-complete them (default)
7240 # 'cancel': wait until all jobs are ready, block-job-cancel them
7241 # 'skip': wait until all jobs are ready, return with block jobs in ready state
7242 # 'auto': wait until all jobs disappear, only use for jobs which complete automatically
7243 sub qemu_drive_mirror_monitor
{
7244 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
7246 $completion //= 'complete';
7250 my $err_complete = 0;
7252 my $starttime = time ();
7254 die "block job ('$op') timed out\n" if $err_complete > 300;
7256 my $stats = mon_cmd
($vmid, "query-block-jobs");
7259 my $running_jobs = {};
7260 for my $stat (@$stats) {
7261 next if $stat->{type
} ne $op;
7262 $running_jobs->{$stat->{device
}} = $stat;
7265 my $readycounter = 0;
7267 for my $job_id (sort keys %$jobs) {
7268 my $job = $running_jobs->{$job_id};
7270 my $vanished = !defined($job);
7271 my $complete = defined($jobs->{$job_id}->{complete
}) && $vanished;
7272 if($complete || ($vanished && $completion eq 'auto')) {
7273 print "$job_id: $op-job finished\n";
7274 delete $jobs->{$job_id};
7278 die "$job_id: '$op' has been cancelled\n" if !defined($job);
7280 my $busy = $job->{busy
};
7281 my $ready = $job->{ready
};
7282 if (my $total = $job->{len
}) {
7283 my $transferred = $job->{offset
} || 0;
7284 my $remaining = $total - $transferred;
7285 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
7287 my $duration = $ctime - $starttime;
7288 my $total_h = render_bytes
($total, 1);
7289 my $transferred_h = render_bytes
($transferred, 1);
7291 my $status = sprintf(
7292 "transferred $transferred_h of $total_h ($percent%%) in %s",
7293 render_duration
($duration),
7298 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7300 $status .= ", ready";
7303 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready
};
7304 $jobs->{$job_id}->{ready
} = $ready;
7307 $readycounter++ if $job->{ready
};
7310 last if scalar(keys %$jobs) == 0;
7312 if ($readycounter == scalar(keys %$jobs)) {
7313 print "all '$op' jobs are ready\n";
7315 # do the complete later (or has already been done)
7316 last if $completion eq 'skip' || $completion eq 'auto';
7318 if ($vmiddst && $vmiddst != $vmid) {
7319 my $agent_running = $qga && qga_check_running
($vmid);
7320 if ($agent_running) {
7321 print "freeze filesystem\n";
7322 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
7324 print "suspend vm\n";
7325 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
7328 # if we clone a disk for a new target vm, we don't switch the disk
7329 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
7331 if ($agent_running) {
7332 print "unfreeze filesystem\n";
7333 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
7335 print "resume vm\n";
7336 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
7342 for my $job_id (sort keys %$jobs) {
7343 # try to switch the disk if source and destination are on the same guest
7344 print "$job_id: Completing block job_id...\n";
7347 if ($completion eq 'complete') {
7348 $op = 'block-job-complete';
7349 } elsif ($completion eq 'cancel') {
7350 $op = 'block-job-cancel';
7352 die "invalid completion value: $completion\n";
7354 eval { mon_cmd
($vmid, $op, device
=> $job_id) };
7355 if ($@ =~ m/cannot be completed/) {
7356 print "$job_id: block job cannot be completed, trying again.\n";
7359 print "$job_id: Completed successfully.\n";
7360 $jobs->{$job_id}->{complete
} = 1;
7371 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7372 die "block job ($op) error: $err";
7376 sub qemu_blockjobs_cancel
{
7377 my ($vmid, $jobs) = @_;
7379 foreach my $job (keys %$jobs) {
7380 print "$job: Cancelling block job\n";
7381 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
7382 $jobs->{$job}->{cancel
} = 1;
7386 my $stats = mon_cmd
($vmid, "query-block-jobs");
7388 my $running_jobs = {};
7389 foreach my $stat (@$stats) {
7390 $running_jobs->{$stat->{device
}} = $stat;
7393 foreach my $job (keys %$jobs) {
7395 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
7396 print "$job: Done.\n";
7397 delete $jobs->{$job};
7401 last if scalar(keys %$jobs) == 0;
7408 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7409 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
7414 print "create linked clone of drive $drivename ($drive->{file})\n";
7415 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
7416 push @$newvollist, $newvolid;
7419 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7420 $storeid = $storage if $storage;
7422 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7424 print "create full clone of drive $drivename ($drive->{file})\n";
7427 if (drive_is_cloudinit
($drive)) {
7428 $name = "vm-$newvmid-cloudinit";
7429 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7430 if ($scfg->{path
}) {
7431 $name .= ".$dst_format";
7434 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
7435 } elsif ($drivename eq 'efidisk0') {
7436 $size = get_efivars_size
($conf);
7437 } elsif ($drivename eq 'tpmstate0') {
7438 $size = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
7440 ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 10);
7442 $newvolid = PVE
::Storage
::vdisk_alloc
(
7443 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7445 push @$newvollist, $newvolid;
7447 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7449 if (drive_is_cloudinit
($drive)) {
7450 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7451 # if this is the case, we have to complete any block-jobs still there from
7452 # previous drive-mirrors
7453 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7454 qemu_drive_mirror_monitor
($vmid, $newvmid, $jobs, $completion, $qga);
7459 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7460 if (!$running || $snapname) {
7461 # TODO: handle bwlimits
7462 if ($drivename eq 'efidisk0') {
7463 # the relevant data on the efidisk may be smaller than the source
7464 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7465 # that is given by the OVMF_VARS.fd
7466 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
7467 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
7469 # better for Ceph if block size is not too small, see bug #3324
7472 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=$bs", "osize=$size",
7473 "if=$src_path", "of=$dst_path"]);
7475 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7479 die "cannot move TPM state while VM is running\n" if $drivename eq 'tpmstate0';
7481 my $kvmver = get_running_qemu_version
($vmid);
7482 if (!min_version
($kvmver, 2, 7)) {
7483 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7484 if $drive->{iothread
};
7487 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7488 $completion, $qga, $bwlimit);
7493 my ($size) = eval { PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 10) };
7496 $disk->{format
} = undef;
7497 $disk->{file
} = $newvolid;
7498 $disk->{size
} = $size if defined($size);
7503 sub get_running_qemu_version
{
7505 my $res = mon_cmd
($vmid, "query-version");
7506 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7509 sub qemu_use_old_bios_files
{
7510 my ($machine_type) = @_;
7512 return if !$machine_type;
7514 my $use_old_bios_files = undef;
7516 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7518 $use_old_bios_files = 1;
7520 my $version = extract_version
($machine_type, kvm_user_version
());
7521 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7522 # load new efi bios files on migration. So this hack is required to allow
7523 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7524 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7525 $use_old_bios_files = !min_version
($version, 2, 4);
7528 return ($use_old_bios_files, $machine_type);
7531 sub get_efivars_size
{
7533 my $arch = get_vm_arch
($conf);
7534 my $efidisk = $conf->{efidisk0
} ? parse_drive
('efidisk0', $conf->{efidisk0
}) : undef;
7535 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk);
7536 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
7537 return -s
$ovmf_vars;
7540 sub update_efidisk_size
{
7543 return if !defined($conf->{efidisk0
});
7545 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
7546 $disk->{size
} = get_efivars_size
($conf);
7547 $conf->{efidisk0
} = print_drive
($disk);
7552 sub update_tpmstate_size
{
7555 my $disk = PVE
::QemuServer
::parse_drive
('tpmstate0', $conf->{tpmstate0
});
7556 $disk->{size
} = PVE
::QemuServer
::Drive
::TPMSTATE_DISK_SIZE
;
7557 $conf->{tpmstate0
} = print_drive
($disk);
7560 sub create_efidisk
($$$$$$) {
7561 my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk) = @_;
7563 my (undef, $ovmf_vars) = get_ovmf_files
($arch, $efidisk);
7564 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7566 my $vars_size_b = -s
$ovmf_vars;
7567 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
7568 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7569 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7571 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
7572 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
7574 return ($volid, $size/1024);
7577 sub vm_iothreads_list
{
7580 my $res = mon_cmd
($vmid, 'query-iothreads');
7583 foreach my $iothread (@$res) {
7584 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7591 my ($conf, $drive) = @_;
7595 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7597 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7603 my $controller = int($drive->{index} / $maxdev);
7604 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single')
7608 return ($maxdev, $controller, $controller_prefix);
7611 sub windows_version
{
7614 return 0 if !$ostype;
7618 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7620 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7622 } elsif ($ostype =~ m/^win(\d+)$/) {
7629 sub resolve_dst_disk_format
{
7630 my ($storecfg, $storeid, $src_volname, $format) = @_;
7631 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7634 # if no target format is specified, use the source disk format as hint
7636 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7637 $format = qemu_img_format
($scfg, $src_volname);
7643 # test if requested format is supported - else use default
7644 my $supported = grep { $_ eq $format } @$validFormats;
7645 $format = $defFormat if !$supported;
7649 # NOTE: if this logic changes, please update docs & possibly gui logic
7650 sub find_vmstate_storage
{
7651 my ($conf, $storecfg) = @_;
7653 # first, return storage from conf if set
7654 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
7656 my ($target, $shared, $local);
7658 foreach_storage_used_by_vm
($conf, sub {
7660 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7661 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7662 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7665 # second, use shared storage where VM has at least one disk
7666 # third, use local storage where VM has at least one disk
7667 # fall back to local storage
7668 $target = $shared // $local // 'local';
7674 my ($uuid, $uuid_str);
7675 UUID
::generate
($uuid);
7676 UUID
::unparse
($uuid, $uuid_str);
7680 sub generate_smbios1_uuid
{
7681 return "uuid=".generate_uuid
();
7687 mon_cmd
($vmid, 'nbd-server-stop');
7690 sub create_reboot_request
{
7692 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7693 or die "failed to create reboot trigger file: $!\n";
7697 sub clear_reboot_request
{
7699 my $path = "/run/qemu-server/$vmid.reboot";
7702 $res = unlink($path);
7703 die "could not remove reboot request for $vmid: $!"
7704 if !$res && $! != POSIX
::ENOENT
;
7709 sub bootorder_from_legacy
{
7710 my ($conf, $bootcfg) = @_;
7712 my $boot = $bootcfg->{legacy
} || $boot_fmt->{legacy
}->{default};
7713 my $bootindex_hash = {};
7715 foreach my $o (split(//, $boot)) {
7716 $bootindex_hash->{$o} = $i*100;
7722 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7723 my ($ds, $drive) = @_;
7725 if (drive_is_cdrom
($drive, 1)) {
7726 if ($bootindex_hash->{d
}) {
7727 $bootorder->{$ds} = $bootindex_hash->{d
};
7728 $bootindex_hash->{d
} += 1;
7730 } elsif ($bootindex_hash->{c
}) {
7731 $bootorder->{$ds} = $bootindex_hash->{c
}
7732 if $conf->{bootdisk
} && $conf->{bootdisk
} eq $ds;
7733 $bootindex_hash->{c
} += 1;
7737 if ($bootindex_hash->{n
}) {
7738 for (my $i = 0; $i < $MAX_NETS; $i++) {
7739 my $netname = "net$i";
7740 next if !$conf->{$netname};
7741 $bootorder->{$netname} = $bootindex_hash->{n
};
7742 $bootindex_hash->{n
} += 1;
7749 # Generate default device list for 'boot: order=' property. Matches legacy
7750 # default boot order, but with explicit device names. This is important, since
7751 # the fallback for when neither 'order' nor the old format is specified relies
7752 # on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
7753 sub get_default_bootdevices
{
7759 my $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 0);
7760 push @ret, $first if $first;
7763 $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 1);
7764 push @ret, $first if $first;
7767 for (my $i = 0; $i < $MAX_NETS; $i++) {
7768 my $netname = "net$i";
7769 next if !$conf->{$netname};
7770 push @ret, $netname;
7777 sub device_bootorder
{
7780 return bootorder_from_legacy
($conf) if !defined($conf->{boot
});
7782 my $boot = parse_property_string
($boot_fmt, $conf->{boot
});
7785 if (!defined($boot) || $boot->{legacy
}) {
7786 $bootorder = bootorder_from_legacy
($conf, $boot);
7787 } elsif ($boot->{order
}) {
7788 my $i = 100; # start at 100 to allow user to insert devices before us with -args
7789 for my $dev (PVE
::Tools
::split_list
($boot->{order
})) {
7790 $bootorder->{$dev} = $i++;
7797 sub register_qmeventd_handle
{
7801 my $peer = "/var/run/qmeventd.sock";
7806 $fh = IO
::Socket
::UNIX-
>new(Peer
=> $peer, Blocking
=> 0, Timeout
=> 1);
7808 if ($! != EINTR
&& $! != EAGAIN
) {
7809 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
7812 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
7813 . "after $count retries\n";
7818 # send handshake to mark VM as backing up
7819 print $fh to_json
({vzdump
=> {vmid
=> "$vmid"}});
7821 # return handle to be closed later when inhibit is no longer required
7825 # bash completion helper
7827 sub complete_backup_archives
{
7828 my ($cmdname, $pname, $cvalue) = @_;
7830 my $cfg = PVE
::Storage
::config
();
7834 if ($cvalue =~ m/^([^:]+):/) {
7838 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7841 foreach my $id (keys %$data) {
7842 foreach my $item (@{$data->{$id}}) {
7843 next if $item->{format
} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
7844 push @$res, $item->{volid
} if defined($item->{volid
});
7851 my $complete_vmid_full = sub {
7854 my $idlist = vmstatus
();
7858 foreach my $id (keys %$idlist) {
7859 my $d = $idlist->{$id};
7860 if (defined($running)) {
7861 next if $d->{template
};
7862 next if $running && $d->{status
} ne 'running';
7863 next if !$running && $d->{status
} eq 'running';
7872 return &$complete_vmid_full();
7875 sub complete_vmid_stopped
{
7876 return &$complete_vmid_full(0);
7879 sub complete_vmid_running
{
7880 return &$complete_vmid_full(1);
7883 sub complete_storage
{
7885 my $cfg = PVE
::Storage
::config
();
7886 my $ids = $cfg->{ids
};
7889 foreach my $sid (keys %$ids) {
7890 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7891 next if !$ids->{$sid}->{content
}->{images
};
7898 sub complete_migration_storage
{
7899 my ($cmd, $param, $current_value, $all_args) = @_;
7901 my $targetnode = @$all_args[1];
7903 my $cfg = PVE
::Storage
::config
();
7904 my $ids = $cfg->{ids
};
7907 foreach my $sid (keys %$ids) {
7908 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7909 next if !$ids->{$sid}->{content
}->{images
};
7918 my $qmpstatus = eval {
7919 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid);
7920 mon_cmd
($vmid, "query-status");
7923 return $qmpstatus && $qmpstatus->{status
} eq "paused";
7926 sub check_volume_storage_type
{
7927 my ($storecfg, $vol) = @_;
7929 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($vol);
7930 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7931 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $vol);
7933 die "storage '$storeid' does not support content-type '$vtype'\n"
7934 if !$scfg->{content
}->{$vtype};