1 package PVE
::QemuServer
;
11 use File
::Copy
qw(copy);
24 use Storable
qw(dclone);
25 use Time
::HiRes
qw(gettimeofday);
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/';
67 "$EDK2_FW_BASE/OVMF_CODE.fd",
68 "$EDK2_FW_BASE/OVMF_VARS.fd"
71 "$EDK2_FW_BASE/AAVMF_CODE.fd",
72 "$EDK2_FW_BASE/AAVMF_VARS.fd"
76 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
78 # Note about locking: we use flock on the config file protect
79 # against concurent actions.
80 # Aditionaly, we have a 'lock' setting in the config file. This
81 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
82 # allowed when such lock is set. But you can ignore this kind of
83 # lock with the --skiplock flag.
85 cfs_register_file
('/qemu-server/',
89 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
90 description
=> "Some command save/restore state from this location.",
96 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
97 description
=> "Specifies the Qemu machine type.",
99 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
106 my ($map, $source) = @_;
108 return $source if !defined($map);
110 return $map->{entries
}->{$source}
111 if $map->{entries
} && defined($map->{entries
}->{$source});
113 return $map->{default} if $map->{default};
115 # identity (fallback)
119 PVE
::JSONSchema
::register_standard_option
('pve-targetstorage', {
120 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.",
122 format
=> 'storagepair-list',
126 #no warnings 'redefine';
130 $nodename_cache //= PVE
::INotify
::nodename
();
131 return $nodename_cache;
138 enum
=> [qw(i6300esb ib700)],
139 description
=> "Watchdog type to emulate.",
140 default => 'i6300esb',
145 enum
=> [qw(reset shutdown poweroff pause debug none)],
146 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
150 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
154 description
=> "Enable/disable Qemu GuestAgent.",
159 fstrim_cloned_disks
=> {
160 description
=> "Run fstrim after moving a disk or migrating the VM.",
166 description
=> "Select the agent type",
170 enum
=> [qw(virtio isa)],
176 description
=> "Select the VGA type.",
181 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
184 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
196 description
=> "The size of the file in MB.",
200 pattern
=> '[a-zA-Z0-9\-]+',
202 format_description
=> 'string',
203 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
210 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
211 description
=> "Configure an audio device."
215 enum
=> ['spice', 'none'],
218 description
=> "Driver backend for the audio device."
222 my $spice_enhancements_fmt = {
227 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
231 enum
=> ['off', 'all', 'filter'],
234 description
=> "Enable video streaming. Uses compression for detected video streams."
241 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
243 description
=> "The file on the host to gather entropy from. In most"
244 . " cases /dev/urandom should be preferred over /dev/random"
245 . " to avoid entropy-starvation issues on the host. Using"
246 . " urandom does *not* decrease security in any meaningful"
247 . " way, as it's still seeded from real entropy, and the"
248 . " bytes provided will most likely be mixed with real"
249 . " entropy on the guest as well. /dev/hwrng can be used"
250 . " to pass through a hardware RNG from the host.",
254 description
=> "Maximum bytes of entropy injected into the guest every"
255 . " 'period' milliseconds. Prefer a lower value when using"
256 . " /dev/random as source. Use 0 to disable limiting"
257 . " (potentially dangerous!).",
260 # default is 1 KiB/s, provides enough entropy to the guest to avoid
261 # boot-starvation issues (e.g. systemd etc...) while allowing no chance
262 # of overwhelming the host, provided we're reading from /dev/urandom
267 description
=> "Every 'period' milliseconds the entropy-injection quota"
268 . " is reset, allowing the guest to retrieve another"
269 . " 'max_bytes' of entropy.",
279 description
=> "Specifies whether a VM will be started during system bootup.",
285 description
=> "Automatic restart after crash (currently ignored).",
290 type
=> 'string', format
=> 'pve-hotplug-features',
291 description
=> "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
292 default => 'network,disk,usb',
297 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
303 description
=> "Lock/unlock the VM.",
304 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
309 description
=> "Limit of CPU usage.",
310 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
318 description
=> "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
319 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler."
320 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
321 ." weights of all the other running VMs.",
324 default => 'cgroup v1: 1024, cgroup v2: 100',
329 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
336 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
342 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
350 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
351 "It should not be necessary to set it.",
352 enum
=> PVE
::Tools
::kvmkeymaplist
(),
357 type
=> 'string', format
=> 'dns-name',
358 description
=> "Set a name for the VM. Only used on the configuration web interface.",
363 description
=> "SCSI controller model",
364 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
370 description
=> "Description for the VM. Shown in the web-interface VM's summary."
371 ." This is saved as comment inside the configuration file.",
372 maxLength
=> 1024 * 8,
377 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
378 description
=> "Specify guest operating system.",
379 verbose_description
=> <<EODESC,
380 Specify guest operating system. This is used to enable special
381 optimization/features for specific operating systems:
384 other;; unspecified OS
385 wxp;; Microsoft Windows XP
386 w2k;; Microsoft Windows 2000
387 w2k3;; Microsoft Windows 2003
388 w2k8;; Microsoft Windows 2008
389 wvista;; Microsoft Windows Vista
390 win7;; Microsoft Windows 7
391 win8;; Microsoft Windows 8/2012/2012r2
392 win10;; Microsoft Windows 10/2016/2019
393 l24;; Linux 2.4 Kernel
394 l26;; Linux 2.6 - 5.X Kernel
395 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
400 type
=> 'string', format
=> 'pve-qm-boot',
401 description
=> "Specify guest boot order. Use with 'order=', usage with"
402 . " no key or 'legacy=' is deprecated.",
406 type
=> 'string', format
=> 'pve-qm-bootdisk',
407 description
=> "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
408 pattern
=> '(ide|sata|scsi|virtio)\d+',
413 description
=> "The number of CPUs. Please use option -sockets instead.",
420 description
=> "The number of CPU sockets.",
427 description
=> "The number of cores per socket.",
434 description
=> "Enable/disable NUMA.",
440 description
=> "Enable/disable hugepages memory.",
441 enum
=> [qw(any 2 1024)],
447 description
=> "Use together with hugepages. If enabled, hugepages will not not be deleted"
448 ." after VM shutdown and can be used for subsequent starts.",
453 description
=> "Number of hotplugged vcpus.",
460 description
=> "Enable/disable ACPI.",
465 description
=> "Enable/disable Qemu GuestAgent and its properties.",
467 format
=> $agent_fmt,
472 description
=> "Enable/disable KVM hardware virtualization.",
478 description
=> "Enable/disable time drift fix.",
484 description
=> "Set the real time clock to local time. This is enabled by default if ostype"
485 ." indicates a Microsoft OS.",
490 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
494 type
=> 'string', format
=> $vga_fmt,
495 description
=> "Configure the VGA hardware.",
496 verbose_description
=> "Configure the VGA Hardware. If you want to use high resolution"
497 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
498 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
499 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
500 ." display server. For win* OS you can select how many independent displays you want,"
501 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
502 ." using a serial device as terminal.",
506 type
=> 'string', format
=> 'pve-qm-watchdog',
507 description
=> "Create a virtual hardware watchdog device.",
508 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled (by a guest"
509 ." action), the watchdog must be periodically polled by an agent inside the guest or"
510 ." else the watchdog will reset the guest (or execute the respective action specified)",
515 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
516 description
=> "Set the initial date of the real time clock. Valid format for date are:"
517 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
518 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
521 startup
=> get_standard_option
('pve-startup-order'),
525 description
=> "Enable/disable Template.",
531 description
=> "Arbitrary arguments passed to kvm.",
532 verbose_description
=> <<EODESCR,
533 Arbitrary arguments passed to kvm, for example:
535 args: -no-reboot -no-hpet
537 NOTE: this option is for experts only.
544 description
=> "Enable/disable the USB tablet device.",
545 verbose_description
=> "Enable/disable the USB tablet device. This device is usually needed"
546 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
547 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
548 ." may consider disabling this to save some context switches. This is turned off by"
549 ." default if you use spice (`qm set <vmid> --vga qxl`).",
554 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
558 migrate_downtime
=> {
561 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
567 type
=> 'string', format
=> 'pve-qm-ide',
568 typetext
=> '<volume>',
569 description
=> "This is an alias for option -ide2",
573 description
=> "Emulated CPU type.",
575 format
=> 'pve-vm-cpu-conf',
577 parent
=> get_standard_option
('pve-snapshot-name', {
579 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
583 description
=> "Timestamp for snapshots.",
589 type
=> 'string', format
=> 'pve-volume-id',
590 description
=> "Reference to a volume which stores the VM state. This is used internally"
593 vmstatestorage
=> get_standard_option
('pve-storage-id', {
594 description
=> "Default storage for VM state volumes/files.",
597 runningmachine
=> get_standard_option
('pve-qemu-machine', {
598 description
=> "Specifies the QEMU machine type of the running vm. This is used internally"
602 description
=> "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
603 ." internally for snapshots.",
606 pattern
=> $PVE::QemuServer
::CPUConfig
::qemu_cmdline_cpu_re
,
607 format_description
=> 'QEMU -cpu parameter'
609 machine
=> get_standard_option
('pve-qemu-machine'),
611 description
=> "Virtual processor architecture. Defaults to the host.",
614 enum
=> [qw(x86_64 aarch64)],
617 description
=> "Specify SMBIOS type 1 fields.",
618 type
=> 'string', format
=> 'pve-qm-smbios1',
625 description
=> "Sets the protection flag of the VM. This will disable the remove VM and"
626 ." remove disk operations.",
632 enum
=> [ qw(seabios ovmf) ],
633 description
=> "Select BIOS implementation.",
634 default => 'seabios',
638 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
639 format_description
=> 'UUID',
640 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
641 ." to disable explicitly.",
642 verbose_description
=> "The VM generation ID (vmgenid) device exposes a 128-bit integer"
643 ." value identifier to the guest OS. This allows to notify the guest operating system"
644 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
645 ." execution or creation from a template). The guest operating system notices the"
646 ." change, and is then able to react as appropriate by marking its copies of"
647 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
648 ."Note that auto-creation only works when done through API/CLI create or update methods"
649 .", but not when manually editing the config file.",
650 default => "1 (autogenerated)",
655 format
=> 'pve-volume-id',
657 description
=> "Script that will be executed during various steps in the vms lifetime.",
661 format
=> $ivshmem_fmt,
662 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to"
668 format
=> $audio_fmt,
669 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
672 spice_enhancements
=> {
674 format
=> $spice_enhancements_fmt,
675 description
=> "Configure additional enhancements for SPICE.",
679 type
=> 'string', format
=> 'pve-tag-list',
680 description
=> 'Tags of the VM. This is only meta information.',
686 description
=> "Configure a VirtIO-based Random Number Generator.",
695 description
=> 'Specify a custom file containing all meta data passed to the VM via"
696 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
697 format
=> 'pve-volume-id',
698 format_description
=> 'volume',
703 description
=> 'Specify a custom file containing all network data passed to the VM via'
705 format
=> 'pve-volume-id',
706 format_description
=> 'volume',
711 description
=> 'Specify a custom file containing all user data passed to the VM via'
713 format
=> 'pve-volume-id',
714 format_description
=> 'volume',
717 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
719 my $confdesc_cloudinit = {
723 description
=> 'Specifies the cloud-init configuration format. The default depends on the'
724 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
725 .' and `configdrive2` for windows.',
726 enum
=> ['configdrive2', 'nocloud', 'opennebula'],
731 description
=> "cloud-init: User name to change ssh keys and password for instead of the"
732 ." image's configured default user.",
737 description
=> 'cloud-init: Password to assign the user. Using this is generally not'
738 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
739 .' support hashed passwords.',
744 description
=> 'cloud-init: Specify custom files to replace the automatically generated'
746 format
=> 'pve-qm-cicustom',
751 description
=> "cloud-init: Sets DNS search domains for a container. Create will'
752 .' automatically use the setting from the host if neither searchdomain nor nameserver'
757 type
=> 'string', format
=> 'address-list',
758 description
=> "cloud-init: Sets DNS server IP address for a container. Create will'
759 .' automatically use the setting from the host if neither searchdomain nor nameserver'
765 format
=> 'urlencoded',
766 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
770 # what about other qemu settings ?
772 #machine => 'string',
785 ##soundhw => 'string',
787 while (my ($k, $v) = each %$confdesc) {
788 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
791 my $MAX_USB_DEVICES = 5;
793 my $MAX_SERIAL_PORTS = 4;
794 my $MAX_PARALLEL_PORTS = 3;
800 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
801 description
=> "CPUs accessing this NUMA node.",
802 format_description
=> "id[-id];...",
806 description
=> "Amount of memory this NUMA node provides.",
811 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
812 description
=> "Host NUMA nodes to use.",
813 format_description
=> "id[-id];...",
818 enum
=> [qw(preferred bind interleave)],
819 description
=> "NUMA allocation policy.",
823 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
826 type
=> 'string', format
=> $numa_fmt,
827 description
=> "NUMA topology.",
829 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
831 for (my $i = 0; $i < $MAX_NUMA; $i++) {
832 $confdesc->{"numa$i"} = $numadesc;
835 my $nic_model_list = [
851 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
853 my $net_fmt_bridge_descr = <<__EOD__;
854 Bridge to attach the network device to. The Proxmox VE standard bridge
857 If you do not specify a bridge, we create a kvm user (NATed) network
858 device, which provides DHCP and DNS services. The following addresses
865 The DHCP server assign addresses to the guest starting from 10.0.2.15.
869 macaddr
=> get_standard_option
('mac-addr', {
870 description
=> "MAC address. That address must be unique withing your network. This is"
871 ." automatically generated if not specified.",
875 description
=> "Network Card Model. The 'virtio' model provides the best performance with"
876 ." very low CPU overhead. If your guest does not support this driver, it is usually"
877 ." best to use 'e1000'.",
878 enum
=> $nic_model_list,
881 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
884 description
=> $net_fmt_bridge_descr,
885 format_description
=> 'bridge',
886 pattern
=> '[-_.\w\d]+',
891 minimum
=> 0, maximum
=> 16,
892 description
=> 'Number of packet queues to be used on the device.',
898 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
903 minimum
=> 1, maximum
=> 4094,
904 description
=> 'VLAN tag to apply to packets on this interface.',
909 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
910 description
=> 'VLAN trunks to pass through this interface.',
911 format_description
=> 'vlanid[;vlanid...]',
916 description
=> 'Whether this interface should be protected by the firewall.',
921 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
926 minimum
=> 1, maximum
=> 65520,
927 description
=> "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
934 type
=> 'string', format
=> $net_fmt,
935 description
=> "Specify network devices.",
938 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
943 format
=> 'pve-ipv4-config',
944 format_description
=> 'IPv4Format/CIDR',
945 description
=> 'IPv4 address in CIDR format.',
952 format_description
=> 'GatewayIPv4',
953 description
=> 'Default gateway for IPv4 traffic.',
959 format
=> 'pve-ipv6-config',
960 format_description
=> 'IPv6Format/CIDR',
961 description
=> 'IPv6 address in CIDR format.',
968 format_description
=> 'GatewayIPv6',
969 description
=> 'Default gateway for IPv6 traffic.',
974 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
977 type
=> 'string', format
=> 'pve-qm-ipconfig',
978 description
=> <<'EODESCR',
979 cloud-init: Specify IP addresses and gateways for the corresponding interface.
981 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
983 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
984 gateway should be provided.
985 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
986 cloud-init 19.4 or newer.
988 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
992 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
994 for (my $i = 0; $i < $MAX_NETS; $i++) {
995 $confdesc->{"net$i"} = $netdesc;
996 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
999 foreach my $key (keys %$confdesc_cloudinit) {
1000 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1003 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
1004 sub verify_volume_id_or_qm_path
{
1005 my ($volid, $noerr) = @_;
1007 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
1011 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
1012 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
1023 type
=> 'string', format
=> 'pve-qm-usb-device',
1024 format_description
=> 'HOSTUSBDEVICE|spice',
1025 description
=> <<EODESCR,
1026 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1028 'bus-port(.port)*' (decimal numbers) or
1029 'vendor_id:product_id' (hexadeciaml numbers) or
1032 You can use the 'lsusb -t' command to list existing usb devices.
1034 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1035 machines - use with special care.
1037 The value 'spice' can be used to add a usb redirection devices for spice.
1043 description
=> "Specifies whether if given host option is a USB3 device or port.",
1050 type
=> 'string', format
=> $usb_fmt,
1051 description
=> "Configure an USB device (n is 0 to 4).",
1053 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1058 pattern
=> '(/dev/.+|socket)',
1059 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1060 verbose_description
=> <<EODESCR,
1061 Create a serial device inside the VM (n is 0 to 3), and pass through a
1062 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1063 host side (use 'qm terminal' to open a terminal connection).
1065 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1066 use with special care.
1068 CAUTION: Experimental! User reported problems with this option.
1075 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1076 description
=> "Map host parallel devices (n is 0 to 2).",
1077 verbose_description
=> <<EODESCR,
1078 Map host parallel devices (n is 0 to 2).
1080 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1081 machines - use with special care.
1083 CAUTION: Experimental! User reported problems with this option.
1087 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1088 $confdesc->{"parallel$i"} = $paralleldesc;
1091 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1092 $confdesc->{"serial$i"} = $serialdesc;
1095 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
1096 $confdesc->{"hostpci$i"} = $PVE::QemuServer
::PCI
::hostpcidesc
;
1099 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1100 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1103 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1104 $confdesc->{"usb$i"} = $usbdesc;
1112 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1113 . " Deprecated, use 'order=' instead.",
1114 pattern
=> '[acdn]{1,4}',
1115 format_description
=> "[acdn]{1,4}",
1117 # note: this is also the fallback if boot: is not given at all
1123 format
=> 'pve-qm-bootdev-list',
1124 format_description
=> "device[;device...]",
1125 description
=> <<EODESC,
1126 The guest will attempt to boot from devices in the order they appear here.
1128 Disks, optical drives and passed-through storage USB devices will be directly
1129 booted from, NICs will load PXE, and PCIe devices will either behave like disks
1130 (e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1132 Note that only devices in this list will be marked as bootable and thus loaded
1133 by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1134 (e.g. software-raid), you need to specify all of them here.
1136 Overrides the deprecated 'legacy=[acdn]*' value when given.
1140 PVE
::JSONSchema
::register_format
('pve-qm-boot', $boot_fmt);
1142 PVE
::JSONSchema
::register_format
('pve-qm-bootdev', \
&verify_bootdev
);
1143 sub verify_bootdev
{
1144 my ($dev, $noerr) = @_;
1146 return $dev if PVE
::QemuServer
::Drive
::is_valid_drivename
($dev) && $dev !~ m/^efidisk/;
1150 return 0 if $dev !~ m/^$base\d+$/;
1151 return 0 if !$confdesc->{$dev};
1155 return $dev if $check->("net");
1156 return $dev if $check->("usb");
1157 return $dev if $check->("hostpci");
1160 die "invalid boot device '$dev'\n";
1163 sub print_bootorder
{
1165 return "" if !@$devs;
1166 my $data = { order
=> join(';', @$devs) };
1167 return PVE
::JSONSchema
::print_property_string
($data, $boot_fmt);
1170 my $kvm_api_version = 0;
1173 return $kvm_api_version if $kvm_api_version;
1175 open my $fh, '<', '/dev/kvm' or return;
1177 # 0xae00 => KVM_GET_API_VERSION
1178 $kvm_api_version = ioctl($fh, 0xae00, 0);
1181 return $kvm_api_version;
1184 my $kvm_user_version = {};
1187 sub kvm_user_version
{
1190 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1191 my $st = stat($binary);
1193 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1194 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1195 $cachedmtime == $st->mtime;
1197 $kvm_user_version->{$binary} = 'unknown';
1198 $kvm_mtime->{$binary} = $st->mtime;
1202 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1203 $kvm_user_version->{$binary} = $2;
1207 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1210 return $kvm_user_version->{$binary};
1213 my sub extract_version
{
1214 my ($machine_type, $version) = @_;
1215 $version = kvm_user_version
() if !defined($version);
1216 PVE
::QemuServer
::Machine
::extract_version
($machine_type, $version)
1219 sub kernel_has_vhost_net
{
1220 return -c
'/dev/vhost-net';
1225 return defined($confdesc->{$key});
1229 sub get_cdrom_path
{
1231 return $cdrom_path if $cdrom_path;
1233 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1234 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1235 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1239 my ($storecfg, $vmid, $cdrom) = @_;
1241 if ($cdrom eq 'cdrom') {
1242 return get_cdrom_path
();
1243 } elsif ($cdrom eq 'none') {
1245 } elsif ($cdrom =~ m
|^/|) {
1248 return PVE
::Storage
::path
($storecfg, $cdrom);
1252 # try to convert old style file names to volume IDs
1253 sub filename_to_volume_id
{
1254 my ($vmid, $file, $media) = @_;
1256 if (!($file eq 'none' || $file eq 'cdrom' ||
1257 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1259 return if $file =~ m
|/|;
1261 if ($media && $media eq 'cdrom') {
1262 $file = "local:iso/$file";
1264 $file = "local:$vmid/$file";
1271 sub verify_media_type
{
1272 my ($opt, $vtype, $media) = @_;
1277 if ($media eq 'disk') {
1279 } elsif ($media eq 'cdrom') {
1282 die "internal error";
1285 return if ($vtype eq $etype);
1287 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1290 sub cleanup_drive_path
{
1291 my ($opt, $storecfg, $drive) = @_;
1293 # try to convert filesystem paths to volume IDs
1295 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1296 ($drive->{file
} !~ m
|^/dev/.+|) &&
1297 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1298 ($drive->{file
} !~ m/^\d+$/)) {
1299 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1300 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1302 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1303 verify_media_type
($opt, $vtype, $drive->{media
});
1304 $drive->{file
} = $volid;
1307 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1310 sub parse_hotplug_features
{
1315 return $res if $data eq '0';
1317 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1319 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1320 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1323 die "invalid hotplug feature '$feature'\n";
1329 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1330 sub pve_verify_hotplug_features
{
1331 my ($value, $noerr) = @_;
1333 return $value if parse_hotplug_features
($value);
1337 die "unable to parse hotplug option\n";
1341 my($fh, $noerr) = @_;
1344 my $SG_GET_VERSION_NUM = 0x2282;
1346 my $versionbuf = "\x00" x
8;
1347 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1349 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1352 my $version = unpack("I", $versionbuf);
1353 if ($version < 30000) {
1354 die "scsi generic interface too old\n" if !$noerr;
1358 my $buf = "\x00" x
36;
1359 my $sensebuf = "\x00" x
8;
1360 my $cmd = pack("C x3 C x1", 0x12, 36);
1362 # see /usr/include/scsi/sg.h
1363 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";
1365 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1366 length($sensebuf), 0, length($buf), $buf,
1367 $cmd, $sensebuf, 6000);
1369 $ret = ioctl($fh, $SG_IO, $packet);
1371 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1375 my @res = unpack($sg_io_hdr_t, $packet);
1376 if ($res[17] || $res[18]) {
1377 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1382 (my $byte0, my $byte1, $res->{vendor
},
1383 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1385 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1386 $res->{type
} = $byte0 & 31;
1394 my $fh = IO
::File-
>new("+<$path") || return;
1395 my $res = scsi_inquiry
($fh, 1);
1401 sub print_tabletdevice_full
{
1402 my ($conf, $arch) = @_;
1404 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1406 # we use uhci for old VMs because tablet driver was buggy in older qemu
1408 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1414 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1417 sub print_keyboarddevice_full
{
1418 my ($conf, $arch, $machine) = @_;
1420 return if $arch ne 'aarch64';
1422 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1425 my sub get_drive_id
{
1427 return "$drive->{interface}$drive->{index}";
1430 sub print_drivedevice_full
{
1431 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1436 my $drive_id = get_drive_id
($drive);
1437 if ($drive->{interface
} eq 'virtio') {
1438 my $pciaddr = print_pci_addr
("$drive_id", $bridges, $arch, $machine_type);
1439 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1440 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread
};
1441 } elsif ($drive->{interface
} eq 'scsi') {
1443 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1444 my $unit = $drive->{index} % $maxdev;
1445 my $devicetype = 'hd';
1447 if (drive_is_cdrom
($drive)) {
1450 if ($drive->{file
} =~ m
|^/|) {
1451 $path = $drive->{file
};
1452 if (my $info = path_is_scsi
($path)) {
1453 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1454 $devicetype = 'block';
1455 } elsif ($info->{type
} == 1) { # tape
1456 $devicetype = 'generic';
1460 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1463 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1464 my $version = extract_version
($machine_type, kvm_user_version
());
1465 if ($path =~ m/^iscsi\:\/\
// &&
1466 !min_version
($version, 4, 1)) {
1467 $devicetype = 'generic';
1471 if (!$conf->{scsihw
} || $conf->{scsihw
} =~ m/^lsi/ || $conf->{scsihw
} eq 'pvscsi') {
1472 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
1474 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1475 .",lun=$drive->{index}";
1477 $device .= ",drive=drive-$drive_id,id=$drive_id";
1479 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1480 $device .= ",rotation_rate=1";
1482 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1484 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1485 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1486 my $controller = int($drive->{index} / $maxdev);
1487 my $unit = $drive->{index} % $maxdev;
1488 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1490 $device = "ide-$devicetype";
1491 if ($drive->{interface
} eq 'ide') {
1492 $device .= ",bus=ide.$controller,unit=$unit";
1494 $device .= ",bus=ahci$controller.$unit";
1496 $device .= ",drive=drive-$drive_id,id=$drive_id";
1498 if ($devicetype eq 'hd') {
1499 if (my $model = $drive->{model
}) {
1500 $model = URI
::Escape
::uri_unescape
($model);
1501 $device .= ",model=$model";
1503 if ($drive->{ssd
}) {
1504 $device .= ",rotation_rate=1";
1507 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1508 } elsif ($drive->{interface
} eq 'usb') {
1510 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1512 die "unsupported interface type";
1515 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1517 if (my $serial = $drive->{serial
}) {
1518 $serial = URI
::Escape
::uri_unescape
($serial);
1519 $device .= ",serial=$serial";
1526 sub get_initiator_name
{
1529 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return;
1530 while (defined(my $line = <$fh>)) {
1531 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1540 sub print_drive_commandline_full
{
1541 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1544 my $volid = $drive->{file
};
1545 my $format = $drive->{format
};
1546 my $drive_id = get_drive_id
($drive);
1548 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1549 my $scfg = $storeid ? PVE
::Storage
::storage_config
($storecfg, $storeid) : undef;
1551 if (drive_is_cdrom
($drive)) {
1552 $path = get_iso_path
($storecfg, $vmid, $volid);
1553 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
1556 $path = PVE
::Storage
::path
($storecfg, $volid);
1557 $format //= qemu_img_format
($scfg, $volname);
1564 my $is_rbd = $path =~ m/^rbd:/;
1567 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1568 foreach my $o (@qemu_drive_options) {
1569 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1572 # snapshot only accepts on|off
1573 if (defined($drive->{snapshot
})) {
1574 my $v = $drive->{snapshot
} ?
'on' : 'off';
1575 $opts .= ",snapshot=$v";
1578 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1579 my ($dir, $qmpname) = @$type;
1580 if (my $v = $drive->{"mbps$dir"}) {
1581 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1583 if (my $v = $drive->{"mbps${dir}_max"}) {
1584 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1586 if (my $v = $drive->{"bps${dir}_max_length"}) {
1587 $opts .= ",throttling.bps$qmpname-max-length=$v";
1589 if (my $v = $drive->{"iops${dir}"}) {
1590 $opts .= ",throttling.iops$qmpname=$v";
1592 if (my $v = $drive->{"iops${dir}_max"}) {
1593 $opts .= ",throttling.iops$qmpname-max=$v";
1595 if (my $v = $drive->{"iops${dir}_max_length"}) {
1596 $opts .= ",throttling.iops$qmpname-max-length=$v";
1601 $format = "rbd" if $is_rbd;
1602 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1604 $opts .= ",format=alloc-track,file.driver=$format";
1606 $opts .= ",format=$format";
1609 my $cache_direct = 0;
1611 if (my $cache = $drive->{cache
}) {
1612 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1613 } elsif (!drive_is_cdrom
($drive) && !($scfg && $scfg->{type
} eq 'btrfs' && !$scfg->{nocow
})) {
1614 $opts .= ",cache=none";
1618 # io_uring with cache mode writeback or writethrough on krbd will hang...
1619 my $rbd_no_io_uring = $scfg && $scfg->{type
} eq 'rbd' && $scfg->{krbd
} && !$cache_direct;
1621 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1622 # sometimes, just plain disable...
1623 my $lvm_no_io_uring = $scfg && $scfg->{type
} eq 'lvm';
1625 if (!$drive->{aio
}) {
1626 if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring) {
1627 # io_uring supports all cache modes
1628 $opts .= ",aio=io_uring";
1630 # aio native works only with O_DIRECT
1632 $opts .= ",aio=native";
1634 $opts .= ",aio=threads";
1639 if (!drive_is_cdrom
($drive)) {
1641 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1642 $detectzeroes = 'off';
1643 } elsif ($drive->{discard
}) {
1644 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1646 # This used to be our default with discard not being specified:
1647 $detectzeroes = 'on';
1650 # note: 'detect-zeroes' works per blockdev and we want it to persist
1651 # after the alloc-track is removed, so put it on 'file' directly
1652 my $dz_param = $pbs_name ?
"file.detect-zeroes" : "detect-zeroes";
1653 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
1657 $opts .= ",backing=$pbs_name";
1658 $opts .= ",auto-remove=on";
1661 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1662 my $file_param = "file";
1664 # non-rbd drivers require the underlying file to be a seperate block
1665 # node, so add a second .file indirection
1666 $file_param .= ".file" if !$is_rbd;
1667 $file_param .= ".filename";
1669 my $pathinfo = $path ?
"$file_param=$path," : '';
1671 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1674 sub print_pbs_blockdev
{
1675 my ($pbs_conf, $pbs_name) = @_;
1676 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1677 $blockdev .= ",repository=$pbs_conf->{repository}";
1678 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1679 $blockdev .= ",archive=$pbs_conf->{archive}";
1680 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile
};
1684 sub print_netdevice_full
{
1685 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1687 my $device = $net->{model
};
1688 if ($net->{model
} eq 'virtio') {
1689 $device = 'virtio-net-pci';
1692 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1693 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1694 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1695 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1696 # and out of each queue plus one config interrupt and control vector queue
1697 my $vectors = $net->{queues
} * 2 + 2;
1698 $tmpstr .= ",vectors=$vectors,mq=on";
1700 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1702 if (my $mtu = $net->{mtu
}) {
1703 if ($net->{model
} eq 'virtio' && $net->{bridge
}) {
1704 my $bridge_mtu = PVE
::Network
::read_bridge_mtu
($net->{bridge
});
1707 } elsif ($mtu < 576) {
1708 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1709 } elsif ($mtu > $bridge_mtu) {
1710 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1712 $tmpstr .= ",host_mtu=$mtu";
1714 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
1718 if ($use_old_bios_files) {
1720 if ($device eq 'virtio-net-pci') {
1721 $romfile = 'pxe-virtio.rom';
1722 } elsif ($device eq 'e1000') {
1723 $romfile = 'pxe-e1000.rom';
1724 } elsif ($device eq 'e1000e') {
1725 $romfile = 'pxe-e1000e.rom';
1726 } elsif ($device eq 'ne2k') {
1727 $romfile = 'pxe-ne2k_pci.rom';
1728 } elsif ($device eq 'pcnet') {
1729 $romfile = 'pxe-pcnet.rom';
1730 } elsif ($device eq 'rtl8139') {
1731 $romfile = 'pxe-rtl8139.rom';
1733 $tmpstr .= ",romfile=$romfile" if $romfile;
1739 sub print_netdev_full
{
1740 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1743 if ($netid =~ m/^net(\d+)$/) {
1747 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1749 my $ifname = "tap${vmid}i$i";
1751 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1752 die "interface name '$ifname' is too long (max 15 character)\n"
1753 if length($ifname) >= 16;
1755 my $vhostparam = '';
1756 if (is_native
($arch)) {
1757 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1760 my $vmname = $conf->{name
} || "vm$vmid";
1763 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1765 if ($net->{bridge
}) {
1766 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1767 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1769 $netdev = "type=user,id=$netid,hostname=$vmname";
1772 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1778 'cirrus' => 'cirrus-vga',
1780 'vmware' => 'vmware-svga',
1781 'virtio' => 'virtio-vga',
1784 sub print_vga_device
{
1785 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1787 my $type = $vga_map->{$vga->{type
}};
1788 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1789 $type = 'virtio-gpu';
1791 my $vgamem_mb = $vga->{memory
};
1793 my $max_outputs = '';
1795 $type = $id ?
'qxl' : 'qxl-vga';
1797 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1798 # set max outputs so linux can have up to 4 qxl displays with one device
1799 if (min_version
($machine_version, 4, 1)) {
1800 $max_outputs = ",max_outputs=4";
1805 die "no devicetype for $vga->{type}\n" if !$type;
1809 if ($vga->{type
} eq 'virtio') {
1810 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1811 $memory = ",max_hostmem=$bytes";
1813 # from https://www.spice-space.org/multiple-monitors.html
1814 $memory = ",vgamem_mb=$vga->{memory}";
1815 my $ram = $vgamem_mb * 4;
1816 my $vram = $vgamem_mb * 2;
1817 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1819 $memory = ",vgamem_mb=$vga->{memory}";
1821 } elsif ($qxlnum && $id) {
1822 $memory = ",ram_size=67108864,vram_size=33554432";
1826 if ($type eq 'VGA' && windows_version
($conf->{ostype
})) {
1827 $edidoff=",edid=off" if (!defined($conf->{bios
}) || $conf->{bios
} ne 'ovmf');
1830 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1831 my $vgaid = "vga" . ($id // '');
1834 if ($q35 && $vgaid eq 'vga') {
1835 # the first display uses pcie.0 bus on q35 machines
1836 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1838 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1841 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
1844 sub parse_number_sets
{
1847 foreach my $part (split(/;/, $set)) {
1848 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1849 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1850 push @$res, [ $1, $2 ];
1852 die "invalid range: $part\n";
1861 my $res = parse_property_string
($numa_fmt, $data);
1862 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1863 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1867 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1871 my $res = eval { parse_property_string
($net_fmt, $data) };
1876 if (!defined($res->{macaddr
})) {
1877 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1878 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1883 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1884 sub parse_ipconfig
{
1887 my $res = eval { parse_property_string
($ipconfig_fmt, $data) };
1893 if ($res->{gw
} && !$res->{ip
}) {
1894 warn 'gateway specified without specifying an IP address';
1897 if ($res->{gw6
} && !$res->{ip6
}) {
1898 warn 'IPv6 gateway specified without specifying an IPv6 address';
1901 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1902 warn 'gateway specified together with DHCP';
1905 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1907 warn "IPv6 gateway specified together with $res->{ip6} address";
1911 if (!$res->{ip
} && !$res->{ip6
}) {
1912 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1921 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1924 sub add_random_macs
{
1925 my ($settings) = @_;
1927 foreach my $opt (keys %$settings) {
1928 next if $opt !~ m/^net(\d+)$/;
1929 my $net = parse_net
($settings->{$opt});
1931 $settings->{$opt} = print_net
($net);
1935 sub vm_is_volid_owner
{
1936 my ($storecfg, $vmid, $volid) = @_;
1938 if ($volid !~ m
|^/|) {
1940 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1941 if ($owner && ($owner == $vmid)) {
1949 sub vmconfig_register_unused_drive
{
1950 my ($storecfg, $vmid, $conf, $drive) = @_;
1952 if (drive_is_cloudinit
($drive)) {
1953 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1955 } elsif (!drive_is_cdrom
($drive)) {
1956 my $volid = $drive->{file
};
1957 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1958 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1963 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1967 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1968 format_description
=> 'UUID',
1969 description
=> "Set SMBIOS1 UUID.",
1974 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1975 format_description
=> 'Base64 encoded string',
1976 description
=> "Set SMBIOS1 version.",
1981 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1982 format_description
=> 'Base64 encoded string',
1983 description
=> "Set SMBIOS1 serial number.",
1988 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1989 format_description
=> 'Base64 encoded string',
1990 description
=> "Set SMBIOS1 manufacturer.",
1995 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1996 format_description
=> 'Base64 encoded string',
1997 description
=> "Set SMBIOS1 product ID.",
2002 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2003 format_description
=> 'Base64 encoded string',
2004 description
=> "Set SMBIOS1 SKU string.",
2009 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2010 format_description
=> 'Base64 encoded string',
2011 description
=> "Set SMBIOS1 family string.",
2016 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
2024 my $res = eval { parse_property_string
($smbios1_fmt, $data) };
2031 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2034 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2036 sub parse_watchdog
{
2041 my $res = eval { parse_property_string
($watchdog_fmt, $value) };
2046 sub parse_guest_agent
{
2049 return {} if !defined($conf->{agent
});
2051 my $res = eval { parse_property_string
($agent_fmt, $conf->{agent
}) };
2054 # if the agent is disabled ignore the other potentially set properties
2055 return {} if !$res->{enabled
};
2060 my ($conf, $key) = @_;
2061 return undef if !defined($conf->{agent
});
2063 my $agent = parse_guest_agent
($conf);
2064 return $agent->{$key};
2070 return {} if !$value;
2071 my $res = eval { parse_property_string
($vga_fmt, $value) };
2081 my $res = eval { parse_property_string
($rng_fmt, $value) };
2086 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2087 sub verify_usb_device
{
2088 my ($value, $noerr) = @_;
2090 return $value if parse_usb_device
($value);
2094 die "unable to parse usb device\n";
2097 # add JSON properties for create and set function
2098 sub json_config_properties
{
2101 foreach my $opt (keys %$confdesc) {
2102 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' ||
2103 $opt eq 'runningmachine' || $opt eq 'runningcpu';
2104 $prop->{$opt} = $confdesc->{$opt};
2110 # return copy of $confdesc_cloudinit to generate documentation
2111 sub cloudinit_config_properties
{
2113 return dclone
($confdesc_cloudinit);
2117 my ($key, $value) = @_;
2119 die "unknown setting '$key'\n" if !$confdesc->{$key};
2121 my $type = $confdesc->{$key}->{type
};
2123 if (!defined($value)) {
2124 die "got undefined value\n";
2127 if ($value =~ m/[\n\r]/) {
2128 die "property contains a line feed\n";
2131 if ($type eq 'boolean') {
2132 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2133 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2134 die "type check ('boolean') failed - got '$value'\n";
2135 } elsif ($type eq 'integer') {
2136 return int($1) if $value =~ m/^(\d+)$/;
2137 die "type check ('integer') failed - got '$value'\n";
2138 } elsif ($type eq 'number') {
2139 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2140 die "type check ('number') failed - got '$value'\n";
2141 } elsif ($type eq 'string') {
2142 if (my $fmt = $confdesc->{$key}->{format
}) {
2143 PVE
::JSONSchema
::check_format
($fmt, $value);
2146 $value =~ s/^\"(.*)\"$/$1/;
2149 die "internal error"
2154 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
2156 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2158 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2160 if ($conf->{template
}) {
2161 # check if any base image is still used by a linked clone
2162 PVE
::QemuConfig-
>foreach_volume_full($conf, { include_unused
=> 1 }, sub {
2163 my ($ds, $drive) = @_;
2164 return if drive_is_cdrom
($drive);
2166 my $volid = $drive->{file
};
2167 return if !$volid || $volid =~ m
|^/|;
2169 die "base volume '$volid' is still in use by linked cloned\n"
2170 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2176 my $remove_owned_drive = sub {
2177 my ($ds, $drive) = @_;
2178 return if drive_is_cdrom
($drive, 1);
2180 my $volid = $drive->{file
};
2181 return if !$volid || $volid =~ m
|^/|;
2182 return if $volids->{$volid};
2184 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2185 return if !$path || !$owner || ($owner != $vmid);
2187 $volids->{$volid} = 1;
2188 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2189 warn "Could not remove disk '$volid', check manually: $@" if $@;
2192 # only remove disks owned by this VM (referenced in the config)
2193 my $include_opts = {
2194 include_unused
=> 1,
2195 extra_keys
=> ['vmstate'],
2197 PVE
::QemuConfig-
>foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2199 for my $snap (values %{$conf->{snapshots
}}) {
2200 next if !defined($snap->{vmstate
});
2201 my $drive = PVE
::QemuConfig-
>parse_volume('vmstate', $snap->{vmstate
}, 1);
2202 next if !defined($drive);
2203 $remove_owned_drive->('vmstate', $drive);
2206 PVE
::QemuConfig-
>foreach_volume_full($conf->{pending
}, $include_opts, $remove_owned_drive);
2208 if ($purge_unreferenced) { # also remove unreferenced disk
2209 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid, undef, 'images');
2210 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2211 my ($volid, $sid, $volname, $d) = @_;
2212 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2217 if (defined $replacement_conf) {
2218 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2220 PVE
::QemuConfig-
>destroy_config($vmid);
2224 sub parse_vm_config
{
2225 my ($filename, $raw) = @_;
2227 return if !defined($raw);
2230 digest
=> Digest
::SHA
::sha1_hex
($raw),
2235 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2236 || die "got strange filename '$filename'";
2244 my @lines = split(/\n/, $raw);
2245 foreach my $line (@lines) {
2246 next if $line =~ m/^\s*$/;
2248 if ($line =~ m/^\[PENDING\]\s*$/i) {
2249 $section = 'pending';
2250 if (defined($descr)) {
2252 $conf->{description
} = $descr;
2255 $conf = $res->{$section} = {};
2258 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2260 if (defined($descr)) {
2262 $conf->{description
} = $descr;
2265 $conf = $res->{snapshots
}->{$section} = {};
2269 if ($line =~ m/^\#(.*)\s*$/) {
2270 $descr = '' if !defined($descr);
2271 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2275 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2276 $descr = '' if !defined($descr);
2277 $descr .= PVE
::Tools
::decode_text
($2);
2278 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2279 $conf->{snapstate
} = $1;
2280 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2283 $conf->{$key} = $value;
2284 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2286 if ($section eq 'pending') {
2287 $conf->{delete} = $value; # we parse this later
2289 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2291 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2294 eval { $value = check_type
($key, $value); };
2296 warn "vm $vmid - unable to parse value of '$key' - $@";
2298 $key = 'ide2' if $key eq 'cdrom';
2299 my $fmt = $confdesc->{$key}->{format
};
2300 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2301 my $v = parse_drive
($key, $value);
2302 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2303 $v->{file
} = $volid;
2304 $value = print_drive
($v);
2306 warn "vm $vmid - unable to parse value of '$key'\n";
2311 $conf->{$key} = $value;
2314 warn "vm $vmid - unable to parse config: $line\n";
2318 if (defined($descr)) {
2320 $conf->{description
} = $descr;
2322 delete $res->{snapstate
}; # just to be sure
2327 sub write_vm_config
{
2328 my ($filename, $conf) = @_;
2330 delete $conf->{snapstate
}; # just to be sure
2332 if ($conf->{cdrom
}) {
2333 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2334 $conf->{ide2
} = $conf->{cdrom
};
2335 delete $conf->{cdrom
};
2338 # we do not use 'smp' any longer
2339 if ($conf->{sockets
}) {
2340 delete $conf->{smp
};
2341 } elsif ($conf->{smp
}) {
2342 $conf->{sockets
} = $conf->{smp
};
2343 delete $conf->{cores
};
2344 delete $conf->{smp
};
2347 my $used_volids = {};
2349 my $cleanup_config = sub {
2350 my ($cref, $pending, $snapname) = @_;
2352 foreach my $key (keys %$cref) {
2353 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2354 $key eq 'snapstate' || $key eq 'pending';
2355 my $value = $cref->{$key};
2356 if ($key eq 'delete') {
2357 die "propertry 'delete' is only allowed in [PENDING]\n"
2359 # fixme: check syntax?
2362 eval { $value = check_type
($key, $value); };
2363 die "unable to parse value of '$key' - $@" if $@;
2365 $cref->{$key} = $value;
2367 if (!$snapname && is_valid_drivename
($key)) {
2368 my $drive = parse_drive
($key, $value);
2369 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2374 &$cleanup_config($conf);
2376 &$cleanup_config($conf->{pending
}, 1);
2378 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2379 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2380 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2383 # remove 'unusedX' settings if we re-add a volume
2384 foreach my $key (keys %$conf) {
2385 my $value = $conf->{$key};
2386 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2387 delete $conf->{$key};
2391 my $generate_raw_config = sub {
2392 my ($conf, $pending) = @_;
2396 # add description as comment to top of file
2397 if (defined(my $descr = $conf->{description
})) {
2399 foreach my $cl (split(/\n/, $descr)) {
2400 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2403 $raw .= "#\n" if $pending;
2407 foreach my $key (sort keys %$conf) {
2408 next if $key =~ /^(digest|description|pending|snapshots)$/;
2409 $raw .= "$key: $conf->{$key}\n";
2414 my $raw = &$generate_raw_config($conf);
2416 if (scalar(keys %{$conf->{pending
}})){
2417 $raw .= "\n[PENDING]\n";
2418 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2421 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2422 $raw .= "\n[$snapname]\n";
2423 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2433 # we use static defaults from our JSON schema configuration
2434 foreach my $key (keys %$confdesc) {
2435 if (defined(my $default = $confdesc->{$key}->{default})) {
2436 $res->{$key} = $default;
2444 my $vmlist = PVE
::Cluster
::get_vmlist
();
2446 return $res if !$vmlist || !$vmlist->{ids
};
2447 my $ids = $vmlist->{ids
};
2448 my $nodename = nodename
();
2450 foreach my $vmid (keys %$ids) {
2451 my $d = $ids->{$vmid};
2452 next if !$d->{node
} || $d->{node
} ne $nodename;
2453 next if !$d->{type
} || $d->{type
} ne 'qemu';
2454 $res->{$vmid}->{exists} = 1;
2459 # test if VM uses local resources (to prevent migration)
2460 sub check_local_resources
{
2461 my ($conf, $noerr) = @_;
2465 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2466 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2468 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2470 foreach my $k (keys %$conf) {
2471 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2472 # sockets are safe: they will recreated be on the target side post-migrate
2473 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2474 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2477 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2482 # check if used storages are available on all nodes (use by migrate)
2483 sub check_storage_availability
{
2484 my ($storecfg, $conf, $node) = @_;
2486 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2487 my ($ds, $drive) = @_;
2489 my $volid = $drive->{file
};
2492 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2495 # check if storage is available on both nodes
2496 my $scfg = PVE
::Storage
::storage_check_enabled
($storecfg, $sid);
2497 PVE
::Storage
::storage_check_enabled
($storecfg, $sid, $node);
2499 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $volid);
2501 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2502 if !$scfg->{content
}->{$vtype};
2506 # list nodes where all VM images are available (used by has_feature API)
2508 my ($conf, $storecfg) = @_;
2510 my $nodelist = PVE
::Cluster
::get_nodelist
();
2511 my $nodehash = { map { $_ => 1 } @$nodelist };
2512 my $nodename = nodename
();
2514 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2515 my ($ds, $drive) = @_;
2517 my $volid = $drive->{file
};
2520 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2522 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2523 if ($scfg->{disable
}) {
2525 } elsif (my $avail = $scfg->{nodes
}) {
2526 foreach my $node (keys %$nodehash) {
2527 delete $nodehash->{$node} if !$avail->{$node};
2529 } elsif (!$scfg->{shared
}) {
2530 foreach my $node (keys %$nodehash) {
2531 delete $nodehash->{$node} if $node ne $nodename
2540 sub check_local_storage_availability
{
2541 my ($conf, $storecfg) = @_;
2543 my $nodelist = PVE
::Cluster
::get_nodelist
();
2544 my $nodehash = { map { $_ => {} } @$nodelist };
2546 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2547 my ($ds, $drive) = @_;
2549 my $volid = $drive->{file
};
2552 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2554 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2556 if ($scfg->{disable
}) {
2557 foreach my $node (keys %$nodehash) {
2558 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2560 } elsif (my $avail = $scfg->{nodes
}) {
2561 foreach my $node (keys %$nodehash) {
2562 if (!$avail->{$node}) {
2563 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2570 foreach my $node (values %$nodehash) {
2571 if (my $unavail = $node->{unavailable_storages
}) {
2572 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2579 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2581 my ($vmid, $nocheck, $node) = @_;
2583 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2584 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2589 my $vzlist = config_list
();
2591 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2593 while (defined(my $de = $fd->read)) {
2594 next if $de !~ m/^(\d+)\.pid$/;
2596 next if !defined($vzlist->{$vmid});
2597 if (my $pid = check_running
($vmid)) {
2598 $vzlist->{$vmid}->{pid
} = $pid;
2605 our $vmstatus_return_properties = {
2606 vmid
=> get_standard_option
('pve-vmid'),
2608 description
=> "Qemu process status.",
2610 enum
=> ['stopped', 'running'],
2613 description
=> "Maximum memory in bytes.",
2616 renderer
=> 'bytes',
2619 description
=> "Root disk size in bytes.",
2622 renderer
=> 'bytes',
2625 description
=> "VM name.",
2630 description
=> "Qemu QMP agent status.",
2635 description
=> "PID of running qemu process.",
2640 description
=> "Uptime.",
2643 renderer
=> 'duration',
2646 description
=> "Maximum usable CPUs.",
2651 description
=> "The current config lock, if any.",
2656 description
=> "The current configured tags, if any",
2660 'running-machine' => {
2661 description
=> "The currently running machine type (if running).",
2666 description
=> "The currently running QEMU version (if running).",
2672 my $last_proc_pid_stat;
2674 # get VM status information
2675 # This must be fast and should not block ($full == false)
2676 # We only query KVM using QMP if $full == true (this can be slow)
2678 my ($opt_vmid, $full) = @_;
2682 my $storecfg = PVE
::Storage
::config
();
2684 my $list = vzlist
();
2685 my $defaults = load_defaults
();
2687 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2689 my $cpucount = $cpuinfo->{cpus
} || 1;
2691 foreach my $vmid (keys %$list) {
2692 next if $opt_vmid && ($vmid ne $opt_vmid);
2694 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2696 my $d = { vmid
=> int($vmid) };
2697 $d->{pid
} = int($list->{$vmid}->{pid
}) if $list->{$vmid}->{pid
};
2699 # fixme: better status?
2700 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2702 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2703 if (defined($size)) {
2704 $d->{disk
} = 0; # no info available
2705 $d->{maxdisk
} = $size;
2711 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2712 * ($conf->{cores
} || $defaults->{cores
});
2713 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2714 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2716 $d->{name
} = $conf->{name
} || "VM $vmid";
2717 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2718 : $defaults->{memory
}*(1024*1024);
2720 if ($conf->{balloon
}) {
2721 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2722 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2723 : $defaults->{shares
};
2734 $d->{diskwrite
} = 0;
2736 $d->{template
} = 1 if PVE
::QemuConfig-
>is_template($conf);
2738 $d->{serial
} = 1 if conf_has_serial
($conf);
2739 $d->{lock} = $conf->{lock} if $conf->{lock};
2740 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2745 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2746 foreach my $dev (keys %$netdev) {
2747 next if $dev !~ m/^tap([1-9]\d*)i/;
2749 my $d = $res->{$vmid};
2752 $d->{netout
} += $netdev->{$dev}->{receive
};
2753 $d->{netin
} += $netdev->{$dev}->{transmit
};
2756 $d->{nics
}->{$dev}->{netout
} = int($netdev->{$dev}->{receive
});
2757 $d->{nics
}->{$dev}->{netin
} = int($netdev->{$dev}->{transmit
});
2762 my $ctime = gettimeofday
;
2764 foreach my $vmid (keys %$list) {
2766 my $d = $res->{$vmid};
2767 my $pid = $d->{pid
};
2770 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2771 next if !$pstat; # not running
2773 my $used = $pstat->{utime} + $pstat->{stime
};
2775 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2777 if ($pstat->{vsize
}) {
2778 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2781 my $old = $last_proc_pid_stat->{$pid};
2783 $last_proc_pid_stat->{$pid} = {
2791 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2793 if ($dtime > 1000) {
2794 my $dutime = $used - $old->{used
};
2796 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2797 $last_proc_pid_stat->{$pid} = {
2803 $d->{cpu
} = $old->{cpu
};
2807 return $res if !$full;
2809 my $qmpclient = PVE
::QMPClient-
>new();
2811 my $ballooncb = sub {
2812 my ($vmid, $resp) = @_;
2814 my $info = $resp->{'return'};
2815 return if !$info->{max_mem
};
2817 my $d = $res->{$vmid};
2819 # use memory assigned to VM
2820 $d->{maxmem
} = $info->{max_mem
};
2821 $d->{balloon
} = $info->{actual
};
2823 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2824 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2825 $d->{freemem
} = $info->{free_mem
};
2828 $d->{ballooninfo
} = $info;
2831 my $blockstatscb = sub {
2832 my ($vmid, $resp) = @_;
2833 my $data = $resp->{'return'} || [];
2834 my $totalrdbytes = 0;
2835 my $totalwrbytes = 0;
2837 for my $blockstat (@$data) {
2838 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2839 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2841 $blockstat->{device
} =~ s/drive-//;
2842 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2844 $res->{$vmid}->{diskread
} = $totalrdbytes;
2845 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2848 my $machinecb = sub {
2849 my ($vmid, $resp) = @_;
2850 my $data = $resp->{'return'} || [];
2852 $res->{$vmid}->{'running-machine'} =
2853 PVE
::QemuServer
::Machine
::current_from_query_machines
($data);
2856 my $versioncb = sub {
2857 my ($vmid, $resp) = @_;
2858 my $data = $resp->{'return'} // {};
2859 my $version = 'unknown';
2861 if (my $v = $data->{qemu
}) {
2862 $version = $v->{major
} . "." . $v->{minor
} . "." . $v->{micro
};
2865 $res->{$vmid}->{'running-qemu'} = $version;
2868 my $statuscb = sub {
2869 my ($vmid, $resp) = @_;
2871 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2872 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
2873 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
2874 # this fails if ballon driver is not loaded, so this must be
2875 # the last commnand (following command are aborted if this fails).
2876 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2878 my $status = 'unknown';
2879 if (!defined($status = $resp->{'return'}->{status
})) {
2880 warn "unable to get VM status\n";
2884 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2887 foreach my $vmid (keys %$list) {
2888 next if $opt_vmid && ($vmid ne $opt_vmid);
2889 next if !$res->{$vmid}->{pid
}; # not running
2890 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2893 $qmpclient->queue_execute(undef, 2);
2895 foreach my $vmid (keys %$list) {
2896 next if $opt_vmid && ($vmid ne $opt_vmid);
2897 next if !$res->{$vmid}->{pid
}; #not running
2899 # we can't use the $qmpclient since it might have already aborted on
2900 # 'query-balloon', but this might also fail for older versions...
2901 my $qemu_support = eval { mon_cmd
($vmid, "query-proxmox-support") };
2902 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
2905 foreach my $vmid (keys %$list) {
2906 next if $opt_vmid && ($vmid ne $opt_vmid);
2907 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2913 sub conf_has_serial
{
2916 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2917 if ($conf->{"serial$i"}) {
2925 sub conf_has_audio
{
2926 my ($conf, $id) = @_;
2929 my $audio = $conf->{"audio$id"};
2930 return if !defined($audio);
2932 my $audioproperties = parse_property_string
($audio_fmt, $audio);
2933 my $audiodriver = $audioproperties->{driver
} // 'spice';
2936 dev
=> $audioproperties->{device
},
2937 dev_id
=> "audiodev$id",
2938 backend
=> $audiodriver,
2939 backend_id
=> "$audiodriver-backend${id}",
2944 my ($audio, $audiopciaddr, $machine_version) = @_;
2948 my $id = $audio->{dev_id
};
2950 if (min_version
($machine_version, 4, 2)) {
2951 $audiodev = ",audiodev=$audio->{backend_id}";
2954 if ($audio->{dev
} eq 'AC97') {
2955 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
2956 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
2957 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
2958 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
2959 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
2961 die "unkown audio device '$audio->{dev}', implement me!";
2964 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2969 sub vga_conf_has_spice
{
2972 my $vgaconf = parse_vga
($vga);
2973 my $vgatype = $vgaconf->{type
};
2974 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
2981 return get_host_arch
() eq $arch;
2986 return $conf->{arch
} // get_host_arch
();
2989 my $default_machines = {
2994 sub get_installed_machine_version
{
2995 my ($kvmversion) = @_;
2996 $kvmversion = kvm_user_version
() if !defined($kvmversion);
2997 $kvmversion =~ m/^(\d+\.\d+)/;
3001 sub windows_get_pinned_machine_version
{
3002 my ($machine, $base_version, $kvmversion) = @_;
3004 my $pin_version = $base_version;
3005 if (!defined($base_version) ||
3006 !PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($base_version, $kvmversion)
3008 $pin_version = get_installed_machine_version
($kvmversion);
3010 if (!$machine || $machine eq 'pc') {
3011 $machine = "pc-i440fx-$pin_version";
3012 } elsif ($machine eq 'q35') {
3013 $machine = "pc-q35-$pin_version";
3014 } elsif ($machine eq 'virt') {
3015 $machine = "virt-$pin_version";
3017 warn "unknown machine type '$machine', not touching that!\n";
3023 sub get_vm_machine
{
3024 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
3026 my $machine = $forcemachine || $conf->{machine
};
3028 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
3029 $kvmversion //= kvm_user_version
();
3030 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3031 # layout which confuses windows quite a bit and may result in various regressions..
3032 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3033 if (windows_version
($conf->{ostype
})) {
3034 $machine = windows_get_pinned_machine_version
($machine, '5.1', $kvmversion);
3037 $machine ||= $default_machines->{$arch};
3038 if ($add_pve_version) {
3039 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
3040 $machine .= "+pve$pvever";
3044 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3045 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3046 $machine = $1 if $is_pxe;
3048 # for version-pinned machines that do not include a pve-version (e.g.
3049 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3050 $machine .= '+pve0';
3052 $machine .= '.pxe' if $is_pxe;
3058 sub get_ovmf_files
($) {
3061 my $ovmf = $OVMF->{$arch}
3062 or die "no OVMF images known for architecture '$arch'\n";
3068 aarch64
=> '/usr/bin/qemu-system-aarch64',
3069 x86_64
=> '/usr/bin/qemu-system-x86_64',
3071 sub get_command_for_arch
($) {
3073 return '/usr/bin/kvm' if is_native
($arch);
3075 my $cmd = $Arch2Qemu->{$arch}
3076 or die "don't know how to emulate architecture '$arch'\n";
3080 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3081 # to use in a QEMU command line (-cpu element), first array_intersect the result
3082 # of query_supported_ with query_understood_. This is necessary because:
3084 # a) query_understood_ returns flags the host cannot use and
3085 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
3086 # flags, but CPU settings - with most of them being flags. Those settings
3087 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
3089 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3090 # expensive. If you need the value returned from this, you can get it much
3091 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3092 # $accel being 'kvm' or 'tcg'.
3094 # pvestatd calls this function on startup and whenever the QEMU/KVM version
3095 # changes, automatically populating pmxcfs.
3097 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3098 # since kvm and tcg machines support different flags
3100 sub query_supported_cpu_flags
{
3103 $arch //= get_host_arch
();
3104 my $default_machine = $default_machines->{$arch};
3108 # FIXME: Once this is merged, the code below should work for ARM as well:
3109 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3110 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3113 my $kvm_supported = defined(kvm_version
());
3114 my $qemu_cmd = get_command_for_arch
($arch);
3116 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
3118 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3119 my $query_supported_run_qemu = sub {
3125 '-machine', $default_machine,
3127 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
3128 '-mon', 'chardev=qmp,mode=control',
3129 '-pidfile', $pidfile,
3134 push @$cmd, '-accel', 'tcg';
3137 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
3138 die "QEMU flag querying VM exited with code " . $rc if $rc;
3141 my $cmd_result = mon_cmd
(
3143 'query-cpu-model-expansion',
3145 model
=> { name
=> 'host' }
3148 my $props = $cmd_result->{model
}->{props
};
3149 foreach my $prop (keys %$props) {
3150 next if $props->{$prop} ne '1';
3151 # QEMU returns some flags multiple times, with '_', '.' or '-'
3152 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3153 # We only keep those with underscores, to match /proc/cpuinfo
3154 $prop =~ s/\.|-/_/g;
3155 $flags->{$prop} = 1;
3160 # force stop with 10 sec timeout and 'nocheck'
3161 # always stop, even if QMP failed
3162 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
3166 return [ sort keys %$flags ];
3169 # We need to query QEMU twice, since KVM and TCG have different supported flags
3170 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
3171 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
3172 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3174 if ($kvm_supported) {
3175 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
3176 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3183 # Understood CPU flags are written to a file at 'pve-qemu' compile time
3184 my $understood_cpu_flag_dir = "/usr/share/kvm";
3185 sub query_understood_cpu_flags
{
3186 my $arch = get_host_arch
();
3187 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3189 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3192 my $raw = file_get_contents
($filepath);
3193 $raw =~ s/^\s+|\s+$//g;
3194 my @flags = split(/\s+/, $raw);
3199 my sub get_cpuunits
{
3201 return $conf->{cpuunits
} // (PVE
::CGroup
::cgroup_mode
() == 2 ?
100 : 1024);
3203 sub config_to_command
{
3204 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3208 my $globalFlags = [];
3209 my $machineFlags = [];
3214 my $ostype = $conf->{ostype
};
3215 my $winversion = windows_version
($ostype);
3216 my $kvm = $conf->{kvm
};
3217 my $nodename = nodename
();
3219 my $arch = get_vm_arch
($conf);
3220 my $kvm_binary = get_command_for_arch
($arch);
3221 my $kvmver = kvm_user_version
($kvm_binary);
3223 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3224 $kvmver //= "undefined";
3225 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3228 my $add_pve_version = min_version
($kvmver, 4, 1);
3230 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
3231 my $machine_version = extract_version
($machine_type, $kvmver);
3232 $kvm //= 1 if is_native
($arch);
3234 $machine_version =~ m/(\d+)\.(\d+)/;
3235 my ($machine_major, $machine_minor) = ($1, $2);
3237 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3238 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3239 } elsif (!min_version
($kvmver, $machine_major, $machine_minor)) {
3240 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3241 ." please upgrade node '$nodename'\n"
3242 } elsif (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
3243 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
3244 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3245 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3246 ." node '$nodename'\n";
3249 # if a specific +pve version is required for a feature, use $version_guard
3250 # instead of min_version to allow machines to be run with the minimum
3252 my $required_pve_version = 0;
3253 my $version_guard = sub {
3254 my ($major, $minor, $pve) = @_;
3255 return 0 if !min_version
($machine_version, $major, $minor, $pve);
3256 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
3257 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
3258 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3262 if ($kvm && !defined kvm_version
()) {
3263 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3264 ." or enable in BIOS.\n";
3267 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3268 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3269 my $use_old_bios_files = undef;
3270 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3272 my $cpuunits = get_cpuunits
($conf);
3274 push @$cmd, $kvm_binary;
3276 push @$cmd, '-id', $vmid;
3278 my $vmname = $conf->{name
} || "vm$vmid";
3280 push @$cmd, '-name', $vmname;
3282 push @$cmd, '-no-shutdown';
3286 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3287 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
3288 push @$cmd, '-mon', "chardev=qmp,mode=control";
3290 if (min_version
($machine_version, 2, 12)) {
3291 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3292 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3295 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3297 push @$cmd, '-daemonize';
3299 if ($conf->{smbios1
}) {
3300 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3301 if ($smbios_conf->{base64
}) {
3302 # Do not pass base64 flag to qemu
3303 delete $smbios_conf->{base64
};
3304 my $smbios_string = "";
3305 foreach my $key (keys %$smbios_conf) {
3307 if ($key eq "uuid") {
3308 $value = $smbios_conf->{uuid
}
3310 $value = decode_base64
($smbios_conf->{$key});
3312 # qemu accepts any binary data, only commas need escaping by double comma
3314 $smbios_string .= "," . $key . "=" . $value if $value;
3316 push @$cmd, '-smbios', "type=1" . $smbios_string;
3318 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3322 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3323 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3324 die "uefi base image '$ovmf_code' not found\n" if ! -f
$ovmf_code;
3326 my ($path, $format);
3327 my $read_only_str = '';
3328 if (my $efidisk = $conf->{efidisk0
}) {
3329 my $d = parse_drive
('efidisk0', $efidisk);
3330 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3331 $format = $d->{format
};
3333 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3334 if (!defined($format)) {
3335 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3336 $format = qemu_img_format
($scfg, $volname);
3340 die "efidisk format must be specified\n"
3341 if !defined($format);
3344 $read_only_str = ',readonly=on' if drive_is_read_only
($conf, $d);
3346 warn "no efidisk configured! Using temporary efivars disk.\n";
3347 $path = "/tmp/$vmid-ovmf.fd";
3348 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3354 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3355 $size_str = ",size=" . (-s
$ovmf_vars);
3358 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3360 if ($path =~ m/^rbd:/) {
3361 $cache = ',cache=writeback';
3362 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3365 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
3366 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
3371 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3372 if (min_version
($machine_version, 4, 0)) {
3373 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3375 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3379 if ($conf->{vmgenid
}) {
3380 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3383 # add usb controllers
3384 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
(
3385 $conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3386 push @$devices, @usbcontrollers if @usbcontrollers;
3387 my $vga = parse_vga
($conf->{vga
});
3389 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3390 $vga->{type
} = 'qxl' if $qxlnum;
3392 if (!$vga->{type
}) {
3393 if ($arch eq 'aarch64') {
3394 $vga->{type
} = 'virtio';
3395 } elsif (min_version
($machine_version, 2, 9)) {
3396 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3398 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3402 # enable absolute mouse coordinates (needed by vnc)
3404 if (defined($conf->{tablet
})) {
3405 $tablet = $conf->{tablet
};
3407 $tablet = $defaults->{tablet
};
3408 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3409 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3413 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3414 my $kbd = print_keyboarddevice_full
($conf, $arch);
3415 push @$devices, '-device', $kbd if defined($kbd);
3418 my $bootorder = device_bootorder
($conf);
3420 # host pci device passthrough
3421 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE
::QemuServer
::PCI
::print_hostpci_devices
(
3422 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
3425 my $usb_dev_features = {};
3426 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3428 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
(
3429 $conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
3430 push @$devices, @usbdevices if @usbdevices;
3433 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3434 if (my $path = $conf->{"serial$i"}) {
3435 if ($path eq 'socket') {
3436 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3437 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3438 # On aarch64, serial0 is the UART device. Qemu only allows
3439 # connecting UART devices via the '-serial' command line, as
3440 # the device has a fixed slot on the hardware...
3441 if ($arch eq 'aarch64' && $i == 0) {
3442 push @$devices, '-serial', "chardev:serial$i";
3444 push @$devices, '-device', "isa-serial,chardev=serial$i";
3447 die "no such serial device\n" if ! -c
$path;
3448 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3449 push @$devices, '-device', "isa-serial,chardev=serial$i";
3455 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3456 if (my $path = $conf->{"parallel$i"}) {
3457 die "no such parallel device\n" if ! -c
$path;
3458 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3459 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3460 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3464 if (min_version
($machine_version, 4, 0) && (my $audio = conf_has_audio
($conf))) {
3465 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3466 my $audio_devs = audio_devs
($audio, $audiopciaddr, $machine_version);
3467 push @$devices, @$audio_devs;
3471 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3472 $sockets = $conf->{sockets
} if $conf->{sockets
};
3474 my $cores = $conf->{cores
} || 1;
3476 my $maxcpus = $sockets * $cores;
3478 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3480 my $allowed_vcpus = $cpuinfo->{cpus
};
3482 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3483 if ($allowed_vcpus < $maxcpus);
3485 if($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3487 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3488 for (my $i = 2; $i <= $vcpus; $i++) {
3489 my $cpustr = print_cpu_device
($conf,$i);
3490 push @$cmd, '-device', $cpustr;
3495 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3497 push @$cmd, '-nodefaults';
3499 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3501 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3503 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3505 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3506 push @$devices, '-device', print_vga_device
(
3507 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3508 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3509 push @$cmd, '-vnc', "unix:$socket,password=on";
3511 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3512 push @$cmd, '-nographic';
3516 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3517 my $useLocaltime = $conf->{localtime};
3519 if ($winversion >= 5) { # windows
3520 $useLocaltime = 1 if !defined($conf->{localtime});
3522 # use time drift fix when acpi is enabled
3523 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3524 $tdf = 1 if !defined($conf->{tdf
});
3528 if ($winversion >= 6) {
3529 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3530 push @$cmd, '-no-hpet';
3533 push @$rtcFlags, 'driftfix=slew' if $tdf;
3535 if ($conf->{startdate
} && $conf->{startdate
} ne 'now') {
3536 push @$rtcFlags, "base=$conf->{startdate}";
3537 } elsif ($useLocaltime) {
3538 push @$rtcFlags, 'base=localtime';
3542 push @$cmd, '-cpu', $forcecpu;
3544 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3547 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3549 push @$cmd, '-S' if $conf->{freeze
};
3551 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3553 my $guest_agent = parse_guest_agent
($conf);
3555 if ($guest_agent->{enabled
}) {
3556 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3557 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
3559 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3560 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3561 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3562 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3563 } elsif ($guest_agent->{type
} eq 'isa') {
3564 push @$devices, '-device', "isa-serial,chardev=qga0";
3568 my $rng = $conf->{rng0
} ? parse_rng
($conf->{rng0
}) : undef;
3569 if ($rng && $version_guard->(4, 1, 2)) {
3570 check_rng_source
($rng->{source
});
3572 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3573 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3574 my $limiter_str = "";
3576 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3579 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3580 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3581 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3589 for (my $i = 1; $i < $qxlnum; $i++){
3590 push @$devices, '-device', print_vga_device
(
3591 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3594 # assume other OS works like Linux
3595 my ($ram, $vram) = ("134217728", "67108864");
3596 if ($vga->{memory
}) {
3597 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3598 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3600 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3601 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3605 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3607 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3608 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3609 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3611 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3612 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3613 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3615 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3616 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3618 my $spice_enhancement_str = $conf->{spice_enhancements
} // '';
3619 my $spice_enhancement = parse_property_string
($spice_enhancements_fmt, $spice_enhancement_str);
3620 if ($spice_enhancement->{foldersharing
}) {
3621 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3622 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3625 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3626 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3627 if $spice_enhancement->{videostreaming
};
3629 push @$devices, '-spice', "$spice_opts";
3632 # enable balloon by default, unless explicitly disabled
3633 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3634 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3635 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3638 if ($conf->{watchdog
}) {
3639 my $wdopts = parse_watchdog
($conf->{watchdog
});
3640 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3641 my $watchdog = $wdopts->{model
} || 'i6300esb';
3642 push @$devices, '-device', "$watchdog$pciaddr";
3643 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3647 my $scsicontroller = {};
3648 my $ahcicontroller = {};
3649 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3651 # Add iscsi initiator name if available
3652 if (my $initiator = get_initiator_name
()) {
3653 push @$devices, '-iscsi', "initiator-name=$initiator";
3656 PVE
::QemuConfig-
>foreach_volume($conf, sub {
3657 my ($ds, $drive) = @_;
3659 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3660 check_volume_storage_type
($storecfg, $drive->{file
});
3661 push @$vollist, $drive->{file
};
3664 # ignore efidisk here, already added in bios/fw handling code above
3665 return if $drive->{interface
} eq 'efidisk';
3667 $use_virtio = 1 if $ds =~ m/^virtio/;
3669 $drive->{bootindex
} = $bootorder->{$ds} if $bootorder->{$ds};
3671 if ($drive->{interface
} eq 'virtio'){
3672 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3675 if ($drive->{interface
} eq 'scsi') {
3677 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3679 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3680 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3682 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3683 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3686 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3687 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3688 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3689 } elsif ($drive->{iothread
}) {
3690 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3694 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3695 $queues = ",num_queues=$drive->{queues}";
3698 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
3699 if !$scsicontroller->{$controller};
3700 $scsicontroller->{$controller}=1;
3703 if ($drive->{interface
} eq 'sata') {
3704 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3705 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3706 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
3707 if !$ahcicontroller->{$controller};
3708 $ahcicontroller->{$controller}=1;
3711 my $pbs_conf = $pbs_backing->{$ds};
3712 my $pbs_name = undef;
3714 $pbs_name = "drive-$ds-pbs";
3715 push @$devices, '-blockdev', print_pbs_blockdev
($pbs_conf, $pbs_name);
3718 my $drive_cmd = print_drive_commandline_full
(
3719 $storecfg, $vmid, $drive, $pbs_name, min_version
($kvmver, 6, 0));
3721 # extra protection for templates, but SATA and IDE don't support it..
3722 $drive_cmd .= ',readonly=on' if drive_is_read_only
($conf, $drive);
3724 push @$devices, '-drive',$drive_cmd;
3725 push @$devices, '-device', print_drivedevice_full
(
3726 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3729 for (my $i = 0; $i < $MAX_NETS; $i++) {
3730 my $netname = "net$i";
3732 next if !$conf->{$netname};
3733 my $d = parse_net
($conf->{$netname});
3736 $use_virtio = 1 if $d->{model
} eq 'virtio';
3738 $d->{bootindex
} = $bootorder->{$netname} if $bootorder->{$netname};
3740 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, $netname);
3741 push @$devices, '-netdev', $netdevfull;
3743 my $netdevicefull = print_netdevice_full
(
3744 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
3746 push @$devices, '-device', $netdevicefull;
3749 if ($conf->{ivshmem
}) {
3750 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3754 $bus = print_pcie_addr
("ivshmem");
3756 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3759 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3760 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3762 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3763 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
3764 .",size=$ivshmem->{size}M";
3767 # pci.4 is nested in pci.1
3768 $bridges->{1} = 1 if $bridges->{4};
3772 if (min_version
($machine_version, 2, 3)) {
3777 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3781 for my $k (sort {$b cmp $a} keys %$bridges) {
3782 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3785 if ($k == 2 && $legacy_igd) {
3788 $pciaddr = print_pci_addr
("pci.$k_name", undef, $arch, $machine_type);
3790 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3792 # add after -readconfig pve-q35.cfg
3793 splice @$devices, 2, 0, '-device', $devstr;
3795 unshift @$devices, '-device', $devstr if $k > 0;
3800 push @$machineFlags, 'accel=tcg';
3803 my $machine_type_min = $machine_type;
3804 if ($add_pve_version) {
3805 $machine_type_min =~ s/\+pve\d+$//;
3806 $machine_type_min .= "+pve$required_pve_version";
3808 push @$machineFlags, "type=${machine_type_min}";
3810 push @$cmd, @$devices;
3811 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
3812 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
3813 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
3815 if (my $vmstate = $conf->{vmstate
}) {
3816 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3817 push @$vollist, $vmstate;
3818 push @$cmd, '-loadstate', $statepath;
3819 print "activating and using '$vmstate' as vmstate\n";
3822 if (PVE
::QemuConfig-
>is_template($conf)) {
3823 # needed to workaround base volumes being read-only
3824 push @$cmd, '-snapshot';
3828 if ($conf->{args
}) {
3829 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3833 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3836 sub check_rng_source
{
3839 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3840 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
3843 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
3844 if ($source eq '/dev/hwrng' && file_read_firstline
($rng_current) eq 'none') {
3845 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
3846 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
3847 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
3848 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
3856 my $res = mon_cmd
($vmid, 'query-spice');
3858 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3861 sub vm_devices_list
{
3864 my $res = mon_cmd
($vmid, 'query-pci');
3865 my $devices_to_check = [];
3867 foreach my $pcibus (@$res) {
3868 push @$devices_to_check, @{$pcibus->{devices
}},
3871 while (@$devices_to_check) {
3873 for my $d (@$devices_to_check) {
3874 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3875 next if !$d->{'pci_bridge'};
3877 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3878 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3880 $devices_to_check = $to_check;
3883 my $resblock = mon_cmd
($vmid, 'query-block');
3884 foreach my $block (@$resblock) {
3885 if($block->{device
} =~ m/^drive-(\S+)/){
3890 my $resmice = mon_cmd
($vmid, 'query-mice');
3891 foreach my $mice (@$resmice) {
3892 if ($mice->{name
} eq 'QEMU HID Tablet') {
3893 $devices->{tablet
} = 1;
3898 # for usb devices there is no query-usb
3899 # but we can iterate over the entries in
3900 # qom-list path=/machine/peripheral
3901 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3902 foreach my $per (@$resperipheral) {
3903 if ($per->{name
} =~ m/^usb\d+$/) {
3904 $devices->{$per->{name
}} = 1;
3912 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3914 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3916 my $devices_list = vm_devices_list
($vmid);
3917 return 1 if defined($devices_list->{$deviceid});
3919 # add PCI bridge if we need it for the device
3920 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
3922 if ($deviceid eq 'tablet') {
3924 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3926 } elsif ($deviceid eq 'keyboard') {
3928 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3930 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3932 die "usb hotplug currently not reliable\n";
3933 # since we can't reliably hot unplug all added usb devices and usb
3934 # passthrough breaks live migration we disable usb hotplugging for now
3935 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
3937 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3939 qemu_iothread_add
($vmid, $deviceid, $device);
3941 qemu_driveadd
($storecfg, $vmid, $device);
3942 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
3944 qemu_deviceadd
($vmid, $devicefull);
3945 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3947 eval { qemu_drivedel
($vmid, $deviceid); };
3952 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3955 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3956 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3957 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3959 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3961 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3962 qemu_iothread_add
($vmid, $deviceid, $device);
3963 $devicefull .= ",iothread=iothread-$deviceid";
3966 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3967 $devicefull .= ",num_queues=$device->{queues}";
3970 qemu_deviceadd
($vmid, $devicefull);
3971 qemu_deviceaddverify
($vmid, $deviceid);
3973 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3975 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
3976 qemu_driveadd
($storecfg, $vmid, $device);
3978 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
3979 eval { qemu_deviceadd
($vmid, $devicefull); };
3981 eval { qemu_drivedel
($vmid, $deviceid); };
3986 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3988 return if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
3990 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
3991 my $use_old_bios_files = undef;
3992 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3994 my $netdevicefull = print_netdevice_full
(
3995 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3996 qemu_deviceadd
($vmid, $netdevicefull);
3998 qemu_deviceaddverify
($vmid, $deviceid);
3999 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4002 eval { qemu_netdevdel
($vmid, $deviceid); };
4007 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4010 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4011 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4013 qemu_deviceadd
($vmid, $devicefull);
4014 qemu_deviceaddverify
($vmid, $deviceid);
4017 die "can't hotplug device '$deviceid'\n";
4023 # fixme: this should raise exceptions on error!
4024 sub vm_deviceunplug
{
4025 my ($vmid, $conf, $deviceid) = @_;
4027 my $devices_list = vm_devices_list
($vmid);
4028 return 1 if !defined($devices_list->{$deviceid});
4030 my $bootdisks = PVE
::QemuServer
::Drive
::get_bootdisks
($conf);
4031 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
4033 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4034 qemu_devicedel
($vmid, $deviceid);
4035 } elsif ($deviceid =~ m/^usb\d+$/) {
4036 die "usb hotplug currently not reliable\n";
4037 # when unplugging usb devices this way, there may be remaining usb
4038 # controllers/hubs so we disable it for now
4039 #qemu_devicedel($vmid, $deviceid);
4040 #qemu_devicedelverify($vmid, $deviceid);
4041 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4042 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4044 qemu_devicedel
($vmid, $deviceid);
4045 qemu_devicedelverify
($vmid, $deviceid);
4046 qemu_drivedel
($vmid, $deviceid);
4047 qemu_iothread_del
($vmid, $deviceid, $device);
4048 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4049 qemu_devicedel
($vmid, $deviceid);
4050 qemu_devicedelverify
($vmid, $deviceid);
4051 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4052 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4054 qemu_devicedel
($vmid, $deviceid);
4055 qemu_drivedel
($vmid, $deviceid);
4056 qemu_deletescsihw
($conf, $vmid, $deviceid);
4058 qemu_iothread_del
($vmid, "virtioscsi$device->{index}", $device)
4059 if $conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single');
4060 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4061 qemu_devicedel
($vmid, $deviceid);
4062 qemu_devicedelverify
($vmid, $deviceid);
4063 qemu_netdevdel
($vmid, $deviceid);
4065 die "can't unplug device '$deviceid'\n";
4071 sub qemu_deviceadd
{
4072 my ($vmid, $devicefull) = @_;
4074 $devicefull = "driver=".$devicefull;
4075 my %options = split(/[=,]/, $devicefull);
4077 mon_cmd
($vmid, "device_add" , %options);
4080 sub qemu_devicedel
{
4081 my ($vmid, $deviceid) = @_;
4083 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
4086 sub qemu_iothread_add
{
4087 my ($vmid, $deviceid, $device) = @_;
4089 if ($device->{iothread
}) {
4090 my $iothreads = vm_iothreads_list
($vmid);
4091 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4095 sub qemu_iothread_del
{
4096 my ($vmid, $deviceid, $device) = @_;
4098 if ($device->{iothread
}) {
4099 my $iothreads = vm_iothreads_list
($vmid);
4100 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4104 sub qemu_objectadd
{
4105 my ($vmid, $objectid, $qomtype) = @_;
4107 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4112 sub qemu_objectdel
{
4113 my ($vmid, $objectid) = @_;
4115 mon_cmd
($vmid, "object-del", id
=> $objectid);
4121 my ($storecfg, $vmid, $device) = @_;
4123 my $kvmver = get_running_qemu_version
($vmid);
4124 my $io_uring = min_version
($kvmver, 6, 0);
4125 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device, undef, $io_uring);
4126 $drive =~ s/\\/\\\\/g;
4127 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
4129 # If the command succeeds qemu prints: "OK
"
4130 return 1 if $ret =~ m/OK/s;
4132 die "adding drive failed
: $ret\n";
4136 my ($vmid, $deviceid) = @_;
4138 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
4141 return 1 if $ret eq "";
4143 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4144 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4146 die "deleting drive
$deviceid failed
: $ret\n";
4149 sub qemu_deviceaddverify {
4150 my ($vmid, $deviceid) = @_;
4152 for (my $i = 0; $i <= 5; $i++) {
4153 my $devices_list = vm_devices_list($vmid);
4154 return 1 if defined($devices_list->{$deviceid});
4158 die "error on hotplug device
'$deviceid'\n";
4162 sub qemu_devicedelverify {
4163 my ($vmid, $deviceid) = @_;
4165 # need to verify that the device is correctly removed as device_del
4166 # is async and empty return is not reliable
4168 for (my $i = 0; $i <= 5; $i++) {
4169 my $devices_list = vm_devices_list($vmid);
4170 return 1 if !defined($devices_list->{$deviceid});
4174 die "error on hot-unplugging device
'$deviceid'\n";
4177 sub qemu_findorcreatescsihw {
4178 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4180 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4182 my $scsihwid="$controller_prefix$controller";
4183 my $devices_list = vm_devices_list($vmid);
4185 if (!defined($devices_list->{$scsihwid})) {
4186 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4192 sub qemu_deletescsihw {
4193 my ($conf, $vmid, $opt) = @_;
4195 my $device = parse_drive($opt, $conf->{$opt});
4197 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4198 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4202 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4204 my $devices_list = vm_devices_list($vmid);
4205 foreach my $opt (keys %{$devices_list}) {
4206 if (is_valid_drivename($opt)) {
4207 my $drive = parse_drive($opt, $conf->{$opt});
4208 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4214 my $scsihwid="scsihw
$controller";
4216 vm_deviceunplug($vmid, $conf, $scsihwid);
4221 sub qemu_add_pci_bridge {
4222 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4228 print_pci_addr($device, $bridges, $arch, $machine_type);
4230 while (my ($k, $v) = each %$bridges) {
4233 return 1 if !defined($bridgeid) || $bridgeid < 1;
4235 my $bridge = "pci
.$bridgeid";
4236 my $devices_list = vm_devices_list($vmid);
4238 if (!defined($devices_list->{$bridge})) {
4239 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4245 sub qemu_set_link_status {
4246 my ($vmid, $device, $up) = @_;
4248 mon_cmd($vmid, "set_link
", name => $device,
4249 up => $up ? JSON::true : JSON::false);
4252 sub qemu_netdevadd {
4253 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4255 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4256 my %options = split(/[=,]/, $netdev);
4258 if (defined(my $vhost = $options{vhost})) {
4259 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4262 if (defined(my $queues = $options{queues})) {
4263 $options{queues} = $queues + 0;
4266 mon_cmd($vmid, "netdev_add
", %options);
4270 sub qemu_netdevdel {
4271 my ($vmid, $deviceid) = @_;
4273 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4276 sub qemu_usb_hotplug {
4277 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4281 # remove the old one first
4282 vm_deviceunplug($vmid, $conf, $deviceid);
4284 # check if xhci controller is necessary and available
4285 if ($device->{usb3}) {
4287 my $devicelist = vm_devices_list($vmid);
4289 if (!$devicelist->{xhci}) {
4290 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4291 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4294 my $d = parse_usb_device($device->{host});
4295 $d->{usb3} = $device->{usb3};
4298 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4301 sub qemu_cpu_hotplug {
4302 my ($vmid, $conf, $vcpus) = @_;
4304 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4307 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4308 $sockets = $conf->{sockets} if $conf->{sockets};
4309 my $cores = $conf->{cores} || 1;
4310 my $maxcpus = $sockets * $cores;
4312 $vcpus = $maxcpus if !$vcpus;
4314 die "you can
't add more vcpus than maxcpus\n"
4315 if $vcpus > $maxcpus;
4317 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4319 if ($vcpus < $currentvcpus) {
4321 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4323 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4324 qemu_devicedel($vmid, "cpu$i");
4326 my $currentrunningvcpus = undef;
4328 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4329 last if scalar(@{$currentrunningvcpus}) == $i-1;
4330 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4334 #update conf after each succesfull cpu unplug
4335 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4336 PVE::QemuConfig->write_config($vmid, $conf);
4339 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4345 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4346 die "vcpus in running vm does not match its configuration\n"
4347 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4349 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4351 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4352 my $cpustr = print_cpu_device($conf, $i);
4353 qemu_deviceadd($vmid, $cpustr);
4356 my $currentrunningvcpus = undef;
4358 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4359 last if scalar(@{$currentrunningvcpus}) == $i;
4360 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4364 #update conf after each succesfull cpu hotplug
4365 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4366 PVE::QemuConfig->write_config($vmid, $conf);
4370 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4371 mon_cmd($vmid, "cpu-add", id => int($i));
4376 sub qemu_block_set_io_throttle {
4377 my ($vmid, $deviceid,
4378 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4379 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4380 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4381 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4383 return if !check_running($vmid) ;
4385 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4387 bps_rd => int($bps_rd),
4388 bps_wr => int($bps_wr),
4390 iops_rd => int($iops_rd),
4391 iops_wr => int($iops_wr),
4392 bps_max => int($bps_max),
4393 bps_rd_max => int($bps_rd_max),
4394 bps_wr_max => int($bps_wr_max),
4395 iops_max => int($iops_max),
4396 iops_rd_max => int($iops_rd_max),
4397 iops_wr_max => int($iops_wr_max),
4398 bps_max_length => int($bps_max_length),
4399 bps_rd_max_length => int($bps_rd_max_length),
4400 bps_wr_max_length => int($bps_wr_max_length),
4401 iops_max_length => int($iops_max_length),
4402 iops_rd_max_length => int($iops_rd_max_length),
4403 iops_wr_max_length => int($iops_wr_max_length),
4408 sub qemu_block_resize {
4409 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4411 my $running = check_running($vmid);
4413 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4415 return if !$running;
4417 my $padding = (1024 - $size % 1024) % 1024;
4418 $size = $size + $padding;
4423 device => $deviceid,
4429 sub qemu_volume_snapshot {
4430 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4432 my $running = check_running($vmid);
4434 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4435 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4437 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4441 sub qemu_volume_snapshot_delete {
4442 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4444 my $running = check_running($vmid);
4449 my $conf = PVE::QemuConfig->load_config($vmid);
4450 PVE::QemuConfig->foreach_volume($conf, sub {
4451 my ($ds, $drive) = @_;
4452 $running = 1 if $drive->{file} eq $volid;
4456 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4457 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4459 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4463 sub set_migration_caps {
4464 my ($vmid, $savevm) = @_;
4466 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4468 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm
' : 'pbs-dirty-bitmap-migration
';
4469 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4474 "auto-converge" => 1,
4476 "x-rdma-pin-all" => 0,
4479 "dirty-bitmaps" => $dirty_bitmaps,
4482 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4484 for my $supported_capability (@$supported_capabilities) {
4486 capability => $supported_capability->{capability},
4487 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4491 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4495 my ($conf, $func, @param) = @_;
4499 my $test_volid = sub {
4500 my ($key, $drive, $snapname) = @_;
4502 my $volid = $drive->{file};
4505 $volhash->{$volid}->{cdrom} //= 1;
4506 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
4508 my $replicate = $drive->{replicate} // 1;
4509 $volhash->{$volid}->{replicate} //= 0;
4510 $volhash->{$volid}->{replicate} = 1 if $replicate;
4512 $volhash->{$volid}->{shared} //= 0;
4513 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
4515 $volhash->{$volid}->{referenced_in_config} //= 0;
4516 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4518 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4519 if defined($snapname);
4521 my $size = $drive->{size};
4522 $volhash->{$volid}->{size} //= $size if $size;
4524 $volhash->{$volid}->{is_vmstate} //= 0;
4525 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate
';
4527 $volhash->{$volid}->{is_unused} //= 0;
4528 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
4530 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
4533 my $include_opts = {
4534 extra_keys => ['vmstate
'],
4535 include_unused => 1,
4538 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
4539 foreach my $snapname (keys %{$conf->{snapshots}}) {
4540 my $snap = $conf->{snapshots}->{$snapname};
4541 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
4544 foreach my $volid (keys %$volhash) {
4545 &$func($volid, $volhash->{$volid}, @param);
4549 my $fast_plug_option = {
4557 'vmstatestorage
' => 1,
4562 # hotplug changes in [PENDING]
4563 # $selection hash can be used to only apply specified options, for
4564 # example: { cores => 1 } (only apply changed 'cores
')
4565 # $errors ref is used to return error messages
4566 sub vmconfig_hotplug_pending {
4567 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4569 my $defaults = load_defaults();
4570 my $arch = get_vm_arch($conf);
4571 my $machine_type = get_vm_machine($conf, undef, $arch);
4573 # commit values which do not have any impact on running VM first
4574 # Note: those option cannot raise errors, we we do not care about
4575 # $selection and always apply them.
4577 my $add_error = sub {
4578 my ($opt, $msg) = @_;
4579 $errors->{$opt} = "hotplug problem - $msg";
4583 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4584 if ($fast_plug_option->{$opt}) {
4585 $conf->{$opt} = $conf->{pending}->{$opt};
4586 delete $conf->{pending}->{$opt};
4592 PVE::QemuConfig->write_config($vmid, $conf);
4595 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4597 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
4598 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4599 foreach my $opt (sort keys %$pending_delete_hash) {
4600 next if $selection && !$selection->{$opt};
4601 my $force = $pending_delete_hash->{$opt}->{force};
4603 if ($opt eq 'hotplug
') {
4604 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4605 } elsif ($opt eq 'tablet
') {
4606 die "skip\n" if !$hotplug_features->{usb};
4607 if ($defaults->{tablet}) {
4608 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4609 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4610 if $arch eq 'aarch64
';
4612 vm_deviceunplug($vmid, $conf, 'tablet
');
4613 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4615 } elsif ($opt =~ m/^usb\d+/) {
4617 # since we cannot reliably hot unplug usb devices we are disabling it
4618 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4619 #vm_deviceunplug($vmid, $conf, $opt);
4620 } elsif ($opt eq 'vcpus
') {
4621 die "skip\n" if !$hotplug_features->{cpu};
4622 qemu_cpu_hotplug($vmid, $conf, undef);
4623 } elsif ($opt eq 'balloon
') {
4624 # enable balloon device is not hotpluggable
4625 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4626 # here we reset the ballooning value to memory
4627 my $balloon = $conf->{memory} || $defaults->{memory};
4628 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4629 } elsif ($fast_plug_option->{$opt}) {
4631 } elsif ($opt =~ m/^net(\d+)$/) {
4632 die "skip\n" if !$hotplug_features->{network};
4633 vm_deviceunplug($vmid, $conf, $opt);
4634 } elsif (is_valid_drivename($opt)) {
4635 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4636 vm_deviceunplug($vmid, $conf, $opt);
4637 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4638 } elsif ($opt =~ m/^memory$/) {
4639 die "skip\n" if !$hotplug_features->{memory};
4640 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4641 } elsif ($opt eq 'cpuunits
') {
4642 $cgroup->change_cpu_shares(undef, 1024);
4643 } elsif ($opt eq 'cpulimit
') {
4644 $cgroup->change_cpu_quota(-1, 100000);
4650 &$add_error($opt, $err) if $err ne "skip\n";
4652 delete $conf->{$opt};
4653 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4657 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4658 $apply_pending_cloudinit = sub {
4659 return if $apply_pending_cloudinit_done; # once is enough
4660 $apply_pending_cloudinit_done = 1; # once is enough
4662 my ($key, $value) = @_;
4664 my @cloudinit_opts = keys %$confdesc_cloudinit;
4665 foreach my $opt (keys %{$conf->{pending}}) {
4666 next if !grep { $_ eq $opt } @cloudinit_opts;
4667 $conf->{$opt} = delete $conf->{pending}->{$opt};
4670 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4671 foreach my $opt (sort keys %$pending_delete_hash) {
4672 next if !grep { $_ eq $opt } @cloudinit_opts;
4673 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4674 delete $conf->{$opt};
4677 my $new_conf = { %$conf };
4678 $new_conf->{$key} = $value;
4679 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4682 foreach my $opt (keys %{$conf->{pending}}) {
4683 next if $selection && !$selection->{$opt};
4684 my $value = $conf->{pending}->{$opt};
4686 if ($opt eq 'hotplug
') {
4687 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4688 } elsif ($opt eq 'tablet
') {
4689 die "skip\n" if !$hotplug_features->{usb};
4691 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4692 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4693 if $arch eq 'aarch64
';
4694 } elsif ($value == 0) {
4695 vm_deviceunplug($vmid, $conf, 'tablet
');
4696 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4698 } elsif ($opt =~ m/^usb\d+$/) {
4700 # since we cannot reliably hot unplug usb devices we disable it for now
4701 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4702 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4703 #die "skip\n" if !$d;
4704 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4705 } elsif ($opt eq 'vcpus
') {
4706 die "skip\n" if !$hotplug_features->{cpu};
4707 qemu_cpu_hotplug($vmid, $conf, $value);
4708 } elsif ($opt eq 'balloon
') {
4709 # enable/disable balloning device is not hotpluggable
4710 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4711 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4712 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4714 # allow manual ballooning if shares is set to zero
4715 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4716 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4717 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4719 } elsif ($opt =~ m/^net(\d+)$/) {
4720 # some changes can be done without hotplug
4721 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4722 $vmid, $opt, $value, $arch, $machine_type);
4723 } elsif (is_valid_drivename($opt)) {
4724 die "skip\n" if $opt eq 'efidisk0
';
4725 # some changes can be done without hotplug
4726 my $drive = parse_drive($opt, $value);
4727 if (drive_is_cloudinit($drive)) {
4728 &$apply_pending_cloudinit($opt, $value);
4730 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4731 $vmid, $opt, $value, $arch, $machine_type);
4732 } elsif ($opt =~ m/^memory$/) { #dimms
4733 die "skip\n" if !$hotplug_features->{memory};
4734 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4735 } elsif ($opt eq 'cpuunits
') {
4736 $cgroup->change_cpu_shares($conf->{pending}->{$opt}, 1024);
4737 } elsif ($opt eq 'cpulimit
') {
4738 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4739 $cgroup->change_cpu_quota($cpulimit, 100000);
4741 die "skip\n"; # skip non-hot-pluggable options
4745 &$add_error($opt, $err) if $err ne "skip\n";
4747 $conf->{$opt} = $value;
4748 delete $conf->{pending}->{$opt};
4752 PVE::QemuConfig->write_config($vmid, $conf);
4755 sub try_deallocate_drive {
4756 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4758 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4759 my $volid = $drive->{file};
4760 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4761 my $sid = PVE::Storage::parse_volume_id($volid);
4762 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4764 # check if the disk is really unused
4765 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4766 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4767 PVE::Storage::vdisk_free($storecfg, $volid);
4770 # If vm is not owner of this disk remove from config
4778 sub vmconfig_delete_or_detach_drive {
4779 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4781 my $drive = parse_drive($opt, $conf->{$opt});
4783 my $rpcenv = PVE::RPCEnvironment::get();
4784 my $authuser = $rpcenv->get_user();
4787 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4788 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4790 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4796 sub vmconfig_apply_pending {
4797 my ($vmid, $conf, $storecfg, $errors) = @_;
4799 my $add_apply_error = sub {
4800 my ($opt, $msg) = @_;
4801 my $err_msg = "unable to apply pending change $opt : $msg";
4802 $errors->{$opt} = $err_msg;
4808 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4809 foreach my $opt (sort keys %$pending_delete_hash) {
4810 my $force = $pending_delete_hash->{$opt}->{force};
4812 if ($opt =~ m/^unused/) {
4813 die "internal error";
4814 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4815 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4819 $add_apply_error->($opt, $err);
4821 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4822 delete $conf->{$opt};
4826 PVE::QemuConfig->cleanup_pending($conf);
4828 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4829 next if $opt eq 'delete'; # just to be sure
4831 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4832 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4836 $add_apply_error->($opt, $err);
4838 $conf->{$opt} = delete $conf->{pending}->{$opt};
4842 # write all changes at once to avoid unnecessary i/o
4843 PVE::QemuConfig->write_config($vmid, $conf);
4846 sub vmconfig_update_net {
4847 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4849 my $newnet = parse_net($value);
4851 if ($conf->{$opt}) {
4852 my $oldnet = parse_net($conf->{$opt});
4854 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4855 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4856 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4857 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4859 # for non online change, we try to hot-unplug
4860 die "skip\n" if !$hotplug;
4861 vm_deviceunplug($vmid, $conf, $opt);
4864 die "internal error" if $opt !~ m/net(\d+)/;
4865 my $iface = "tap${vmid}i$1";
4867 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4868 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4869 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4870 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4871 PVE::Network::tap_unplug($iface);
4874 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4876 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4878 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4879 # Rate can be applied on its own but any change above needs to
4880 # include the rate in tap_plug since OVS resets everything.
4881 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4884 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4885 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4893 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4899 sub vmconfig_update_disk {
4900 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4902 my $drive = parse_drive($opt, $value);
4904 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
4905 my $media = $drive->{media} || 'disk
';
4906 my $oldmedia = $old_drive->{media} || 'disk
';
4907 die "unable to change media type\n" if $media ne $oldmedia;
4909 if (!drive_is_cdrom($old_drive)) {
4911 if ($drive->{file} ne $old_drive->{file}) {
4913 die "skip\n" if !$hotplug;
4915 # unplug and register as unused
4916 vm_deviceunplug($vmid, $conf, $opt);
4917 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4920 # update existing disk
4922 # skip non hotpluggable value
4923 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4924 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4925 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4926 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4927 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
4932 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4933 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4934 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4935 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4936 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4937 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4938 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4939 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4940 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4941 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4942 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4943 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4944 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4945 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4946 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4947 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4948 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4949 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4951 qemu_block_set_io_throttle(
4953 ($drive->{mbps} || 0)*1024*1024,
4954 ($drive->{mbps_rd} || 0)*1024*1024,
4955 ($drive->{mbps_wr} || 0)*1024*1024,
4956 $drive->{iops} || 0,
4957 $drive->{iops_rd} || 0,
4958 $drive->{iops_wr} || 0,
4959 ($drive->{mbps_max} || 0)*1024*1024,
4960 ($drive->{mbps_rd_max} || 0)*1024*1024,
4961 ($drive->{mbps_wr_max} || 0)*1024*1024,
4962 $drive->{iops_max} || 0,
4963 $drive->{iops_rd_max} || 0,
4964 $drive->{iops_wr_max} || 0,
4965 $drive->{bps_max_length} || 1,
4966 $drive->{bps_rd_max_length} || 1,
4967 $drive->{bps_wr_max_length} || 1,
4968 $drive->{iops_max_length} || 1,
4969 $drive->{iops_rd_max_length} || 1,
4970 $drive->{iops_wr_max_length} || 1,
4980 if ($drive->{file} eq 'none
') {
4981 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4982 if (drive_is_cloudinit($old_drive)) {
4983 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4986 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4988 # force eject if locked
4989 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4992 mon_cmd($vmid, "blockdev-change-medium",
4993 id => "$opt", filename => "$path");
5001 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5003 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5004 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5007 # called in locked context by incoming migration
5008 sub vm_migrate_get_nbd_disks {
5009 my ($storecfg, $conf, $replicated_volumes) = @_;
5011 my $local_volumes = {};
5012 PVE::QemuConfig->foreach_volume($conf, sub {
5013 my ($ds, $drive) = @_;
5015 return if drive_is_cdrom($drive);
5017 my $volid = $drive->{file};
5021 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5023 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5024 return if $scfg->{shared};
5026 # replicated disks re-use existing state via bitmap
5027 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5028 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
5030 return $local_volumes;
5033 # called in locked context by incoming migration
5034 sub vm_migrate_alloc_nbd_disks {
5035 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
5040 foreach my $opt (sort keys %$source_volumes) {
5041 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
5043 if ($use_existing) {
5044 $nbd->{$opt}->{drivestr} = print_drive($drive);
5045 $nbd->{$opt}->{volid} = $volid;
5046 $nbd->{$opt}->{replicated} = 1;
5050 # If a remote storage is specified and the format of the original
5051 # volume is not available there, fall back to the default format.
5052 # Otherwise use the same format as the original.
5053 if (!$storagemap->{identity}) {
5054 $storeid = map_storage($storagemap, $storeid);
5055 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5056 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5057 my $fileFormat = qemu_img_format($scfg, $volname);
5058 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
5060 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5061 $format = qemu_img_format($scfg, $volname);
5064 my $size = $drive->{size} / 1024;
5065 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
5066 my $newdrive = $drive;
5067 $newdrive->{format} = $format;
5068 $newdrive->{file} = $newvolid;
5069 my $drivestr = print_drive($newdrive);
5070 $nbd->{$opt}->{drivestr} = $drivestr;
5071 $nbd->{$opt}->{volid} = $newvolid;
5077 # see vm_start_nolock for parameters, additionally:
5079 # storagemap = parsed storage map for allocating NBD disks
5081 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5083 return PVE::QemuConfig->lock_config($vmid, sub {
5084 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5086 die "you can't start a vm
if it
's a template\n"
5087 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
5089 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended
');
5090 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup
');
5092 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5094 if ($has_backup_lock && $running) {
5095 # a backup is currently running, attempt to start the guest in the
5096 # existing QEMU instance
5097 return vm_resume($vmid);
5100 PVE::QemuConfig->check_lock($conf)
5101 if !($params->{skiplock} || $has_suspended_lock);
5103 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
5105 die "VM $vmid already running\n" if $running;
5107 if (my $storagemap = $migrate_opts->{storagemap}) {
5108 my $replicated = $migrate_opts->{replicated_volumes};
5109 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5110 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5112 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5113 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5117 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
5123 # statefile => 'tcp
', 'unix
' for migration or path/volid for RAM state
5124 # skiplock => 0/1, skip checking for config lock
5125 # skiptemplate => 0/1, skip checking whether VM is template
5126 # forcemachine => to force Qemu machine (rollback/migration)
5127 # forcecpu => a QEMU '-cpu
' argument string to override get_cpu_options
5128 # timeout => in seconds
5129 # paused => start VM in paused state (backup)
5130 # resume => resume from hibernation
5141 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
5142 # migratedfrom => source node
5143 # spice_ticket => used for spice migration, passed via tunnel/stdin
5144 # network => CIDR of migration network
5145 # type => secure/insecure - tunnel over encrypted connection or plain-text
5146 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
5147 # replicated_volumes = which volids should be re-used with bitmaps for nbd migration
5148 sub vm_start_nolock {
5149 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
5151 my $statefile = $params->{statefile};
5152 my $resume = $params->{resume};
5154 my $migratedfrom = $migrate_opts->{migratedfrom};
5155 my $migration_type = $migrate_opts->{type};
5159 # clean up leftover reboot request files
5160 eval { clear_reboot_request($vmid); };
5163 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5164 vmconfig_apply_pending($vmid, $conf, $storecfg);
5165 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5168 # don't regenerate the ISO
if the VM
is started as part of a live migration
5169 # this way we can reuse the old ISO with the correct config
5170 PVE
::QemuServer
::Cloudinit
::generate_cloudinitconfig
($conf, $vmid) if !$migratedfrom;
5172 my $defaults = load_defaults
();
5174 # set environment variable useful inside network script
5175 $ENV{PVE_MIGRATED_FROM
} = $migratedfrom if $migratedfrom;
5177 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-start', 1);
5179 my $forcemachine = $params->{forcemachine
};
5180 my $forcecpu = $params->{forcecpu
};
5182 # enforce machine and CPU type on suspended vm to ensure HW compatibility
5183 $forcemachine = $conf->{runningmachine
};
5184 $forcecpu = $conf->{runningcpu
};
5185 print "Resuming suspended VM\n";
5188 my ($cmd, $vollist, $spice_port) = config_to_command
($storecfg, $vmid,
5189 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
5192 my $get_migration_ip = sub {
5193 my ($nodename) = @_;
5195 return $migration_ip if defined($migration_ip);
5197 my $cidr = $migrate_opts->{network
};
5199 if (!defined($cidr)) {
5200 my $dc_conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5201 $cidr = $dc_conf->{migration
}->{network
};
5204 if (defined($cidr)) {
5205 my $ips = PVE
::Network
::get_local_ip_from_cidr
($cidr);
5207 die "could not get IP: no address configured on local " .
5208 "node for network '$cidr'\n" if scalar(@$ips) == 0;
5210 die "could not get IP: multiple addresses configured on local " .
5211 "node for network '$cidr'\n" if scalar(@$ips) > 1;
5213 $migration_ip = @$ips[0];
5216 $migration_ip = PVE
::Cluster
::remote_node_ip
($nodename, 1)
5217 if !defined($migration_ip);
5219 return $migration_ip;
5224 if ($statefile eq 'tcp') {
5225 my $localip = "localhost";
5226 my $datacenterconf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5227 my $nodename = nodename
();
5229 if (!defined($migration_type)) {
5230 if (defined($datacenterconf->{migration
}->{type
})) {
5231 $migration_type = $datacenterconf->{migration
}->{type
};
5233 $migration_type = 'secure';
5237 if ($migration_type eq 'insecure') {
5238 $localip = $get_migration_ip->($nodename);
5239 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5242 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5243 my $migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5244 $migrate_uri = "tcp:${localip}:${migrate_port}";
5245 push @$cmd, '-incoming', $migrate_uri;
5248 } elsif ($statefile eq 'unix') {
5249 # should be default for secure migrations as a ssh TCP forward
5250 # tunnel is not deterministic reliable ready and fails regurarly
5251 # to set up in time, so use UNIX socket forwards
5252 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5253 unlink $socket_addr;
5255 $migrate_uri = "unix:$socket_addr";
5257 push @$cmd, '-incoming', $migrate_uri;
5260 } elsif (-e
$statefile) {
5261 push @$cmd, '-loadstate', $statefile;
5263 my $statepath = PVE
::Storage
::path
($storecfg, $statefile);
5264 push @$vollist, $statefile;
5265 push @$cmd, '-loadstate', $statepath;
5267 } elsif ($params->{paused
}) {
5272 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
5273 my $d = parse_hostpci
($conf->{"hostpci$i"});
5275 my $pcidevices = $d->{pciid
};
5276 foreach my $pcidevice (@$pcidevices) {
5277 my $pciid = $pcidevice->{id
};
5279 my $info = PVE
::SysFSTools
::pci_device_info
("$pciid");
5280 die "IOMMU not present\n" if !PVE
::SysFSTools
::check_iommu_support
();
5281 die "no pci device info for device '$pciid'\n" if !$info;
5284 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
5285 PVE
::SysFSTools
::pci_create_mdev_device
($pciid, $uuid, $d->{mdev
});
5287 die "can't unbind/bind PCI group to VFIO '$pciid'\n"
5288 if !PVE
::SysFSTools
::pci_dev_group_bind_to_vfio
($pciid);
5289 die "can't reset PCI device '$pciid'\n"
5290 if $info->{has_fl_reset
} && !PVE
::SysFSTools
::pci_dev_reset
($info);
5295 PVE
::Storage
::activate_volumes
($storecfg, $vollist);
5298 run_command
(['/bin/systemctl', 'stop', "$vmid.scope"],
5299 outfunc
=> sub {}, errfunc
=> sub {});
5301 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5302 # timeout should be more than enough here...
5303 PVE
::Systemd
::wait_for_unit_removed
("$vmid.scope", 5);
5305 my $cpuunits = get_cpuunits
($conf);
5307 my $start_timeout = $params->{timeout
} // config_aware_timeout
($conf, $resume);
5309 timeout
=> $statefile ?
undef : $start_timeout,
5314 # when migrating, prefix QEMU output so other side can pick up any
5315 # errors that might occur and show the user
5316 if ($migratedfrom) {
5317 $run_params{quiet
} = 1;
5318 $run_params{logfunc
} = sub { print "QEMU: $_[0]\n" };
5322 Slice
=> 'qemu.slice',
5323 KillMode
=> 'process',
5325 TimeoutStopUSec
=> ULONG_MAX
, # infinity
5328 if (PVE
::CGroup
::cgroup_mode
() == 2) {
5329 $cpuunits = 10000 if $cpuunits >= 10000; # else we get an error
5330 $properties{CPUWeight
} = $cpuunits;
5332 $properties{CPUShares
} = $cpuunits;
5335 if (my $cpulimit = $conf->{cpulimit
}) {
5336 $properties{CPUQuota
} = int($cpulimit * 100);
5338 $properties{timeout
} = 10 if $statefile; # setting up the scope shoul be quick
5340 my $run_qemu = sub {
5341 PVE
::Tools
::run_fork
sub {
5342 PVE
::Systemd
::enter_systemd_scope
($vmid, "Proxmox VE VM $vmid", %properties);
5344 my $exitcode = run_command
($cmd, %run_params);
5345 die "QEMU exited with code $exitcode\n" if $exitcode;
5349 if ($conf->{hugepages
}) {
5352 my $hugepages_topology = PVE
::QemuServer
::Memory
::hugepages_topology
($conf);
5353 my $hugepages_host_topology = PVE
::QemuServer
::Memory
::hugepages_host_topology
();
5355 PVE
::QemuServer
::Memory
::hugepages_mount
();
5356 PVE
::QemuServer
::Memory
::hugepages_allocate
($hugepages_topology, $hugepages_host_topology);
5358 eval { $run_qemu->() };
5360 PVE
::QemuServer
::Memory
::hugepages_reset
($hugepages_host_topology)
5361 if !$conf->{keephugepages
};
5365 PVE
::QemuServer
::Memory
::hugepages_pre_deallocate
($hugepages_topology)
5366 if !$conf->{keephugepages
};
5368 eval { PVE
::QemuServer
::Memory
::hugepages_update_locked
($code); };
5371 eval { $run_qemu->() };
5375 # deactivate volumes if start fails
5376 eval { PVE
::Storage
::deactivate_volumes
($storecfg, $vollist); };
5377 die "start failed: $err";
5380 print "migration listens on $migrate_uri\n" if $migrate_uri;
5381 $res->{migrate_uri
} = $migrate_uri;
5383 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5384 eval { mon_cmd
($vmid, "cont"); };
5388 #start nbd server for storage migration
5389 if (my $nbd = $migrate_opts->{nbd
}) {
5390 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version
} // 0;
5392 my $migrate_storage_uri;
5393 # nbd_protocol_version > 0 for unix socket support
5394 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5395 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5396 mon_cmd
($vmid, "nbd-server-start", addr
=> { type
=> 'unix', data
=> { path
=> $socket_path } } );
5397 $migrate_storage_uri = "nbd:unix:$socket_path";
5399 my $nodename = nodename
();
5400 my $localip = $get_migration_ip->($nodename);
5401 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
5402 my $storage_migrate_port = PVE
::Tools
::next_migrate_port
($pfamily);
5404 mon_cmd
($vmid, "nbd-server-start", addr
=> {
5407 host
=> "${localip}",
5408 port
=> "${storage_migrate_port}",
5411 $localip = "[$localip]" if Net
::IP
::ip_is_ipv6
($localip);
5412 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5415 $res->{migrate_storage_uri
} = $migrate_storage_uri;
5417 foreach my $opt (sort keys %$nbd) {
5418 my $drivestr = $nbd->{$opt}->{drivestr
};
5419 my $volid = $nbd->{$opt}->{volid
};
5420 mon_cmd
($vmid, "nbd-server-add", device
=> "drive-$opt", writable
=> JSON
::true
);
5421 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5422 print "storage migration listens on $nbd_uri volume:$drivestr\n";
5423 print "re-using replicated volume: $opt - $volid\n"
5424 if $nbd->{$opt}->{replicated
};
5426 $res->{drives
}->{$opt} = $nbd->{$opt};
5427 $res->{drives
}->{$opt}->{nbd_uri
} = $nbd_uri;
5431 if ($migratedfrom) {
5433 set_migration_caps
($vmid);
5438 print "spice listens on port $spice_port\n";
5439 $res->{spice_port
} = $spice_port;
5440 if ($migrate_opts->{spice_ticket
}) {
5441 mon_cmd
($vmid, "set_password", protocol
=> 'spice', password
=>
5442 $migrate_opts->{spice_ticket
});
5443 mon_cmd
($vmid, "expire_password", protocol
=> 'spice', time => "+30");
5448 mon_cmd
($vmid, "balloon", value
=> $conf->{balloon
}*1024*1024)
5449 if !$statefile && $conf->{balloon
};
5451 foreach my $opt (keys %$conf) {
5452 next if $opt !~ m/^net\d+$/;
5453 my $nicconf = parse_net
($conf->{$opt});
5454 qemu_set_link_status
($vmid, $opt, 0) if $nicconf->{link_down
};
5458 mon_cmd
($vmid, 'qom-set',
5459 path
=> "machine/peripheral/balloon0",
5460 property
=> "guest-stats-polling-interval",
5461 value
=> 2) if (!defined($conf->{balloon
}) || $conf->{balloon
});
5464 print "Resumed VM, removing state\n";
5465 if (my $vmstate = $conf->{vmstate
}) {
5466 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5467 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5469 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
5470 PVE
::QemuConfig-
>write_config($vmid, $conf);
5473 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5478 sub vm_commandline
{
5479 my ($storecfg, $vmid, $snapname) = @_;
5481 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5486 my $snapshot = $conf->{snapshots
}->{$snapname};
5487 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5489 # check for machine or CPU overrides in snapshot
5490 $forcemachine = $snapshot->{runningmachine
};
5491 $forcecpu = $snapshot->{runningcpu
};
5493 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5498 my $defaults = load_defaults
();
5500 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults,
5501 $forcemachine, $forcecpu);
5503 return PVE
::Tools
::cmd2string
($cmd);
5507 my ($vmid, $skiplock) = @_;
5509 PVE
::QemuConfig-
>lock_config($vmid, sub {
5511 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5513 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5515 mon_cmd
($vmid, "system_reset");
5519 sub get_vm_volumes
{
5523 foreach_volid
($conf, sub {
5524 my ($volid, $attr) = @_;
5526 return if $volid =~ m
|^/|;
5528 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5531 push @$vollist, $volid;
5537 sub vm_stop_cleanup
{
5538 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5543 my $vollist = get_vm_volumes
($conf);
5544 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5547 foreach my $ext (qw(mon qmp pid vnc qga)) {
5548 unlink "/var/run/qemu-server/${vmid}.$ext";
5551 if ($conf->{ivshmem
}) {
5552 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5553 # just delete it for now, VMs which have this already open do not
5554 # are affected, but new VMs will get a separated one. If this
5555 # becomes an issue we either add some sort of ref-counting or just
5556 # add a "don't delete on stop" flag to the ivshmem format.
5557 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5560 foreach my $key (keys %$conf) {
5561 next if $key !~ m/^hostpci(\d+)$/;
5562 my $hostpciindex = $1;
5563 my $d = parse_hostpci
($conf->{$key});
5564 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5566 foreach my $pci (@{$d->{pciid
}}) {
5567 my $pciid = $pci->{id
};
5568 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5572 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5574 warn $@ if $@; # avoid errors - just warn
5577 # call only in locked context
5579 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5581 my $pid = check_running
($vmid, $nocheck);
5586 $conf = PVE
::QemuConfig-
>load_config($vmid);
5587 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5588 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5589 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5590 $timeout = $opts->{down
} if $opts->{down
};
5592 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5597 if (defined($conf) && get_qga_key
($conf, 'enabled')) {
5598 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5600 mon_cmd
($vmid, "system_powerdown");
5603 mon_cmd
($vmid, "quit");
5609 $timeout = 60 if !defined($timeout);
5612 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5617 if ($count >= $timeout) {
5619 warn "VM still running - terminating now with SIGTERM\n";
5622 die "VM quit/powerdown failed - got timeout\n";
5625 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5629 if (!check_running
($vmid, $nocheck)) {
5630 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5634 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5637 die "VM quit/powerdown failed\n";
5645 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5650 if ($count >= $timeout) {
5651 warn "VM still running - terminating now with SIGKILL\n";
5656 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5659 # Note: use $nocheck to skip tests if VM configuration file exists.
5660 # We need that when migration VMs to other nodes (files already moved)
5661 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5663 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5665 $force = 1 if !defined($force) && !$shutdown;
5668 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5669 kill 15, $pid if $pid;
5670 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5671 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5675 PVE
::QemuConfig-
>lock_config($vmid, sub {
5676 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5681 my ($vmid, $timeout) = @_;
5683 PVE
::QemuConfig-
>lock_config($vmid, sub {
5686 # only reboot if running, as qmeventd starts it again on a stop event
5687 return if !check_running
($vmid);
5689 create_reboot_request
($vmid);
5691 my $storecfg = PVE
::Storage
::config
();
5692 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5696 # avoid that the next normal shutdown will be confused for a reboot
5697 clear_reboot_request
($vmid);
5703 # note: if using the statestorage parameter, the caller has to check privileges
5705 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5712 PVE
::QemuConfig-
>lock_config($vmid, sub {
5714 $conf = PVE
::QemuConfig-
>load_config($vmid);
5716 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5717 PVE
::QemuConfig-
>check_lock($conf)
5718 if !($skiplock || $is_backing_up);
5720 die "cannot suspend to disk during backup\n"
5721 if $is_backing_up && $includestate;
5723 if ($includestate) {
5724 $conf->{lock} = 'suspending';
5725 my $date = strftime
("%Y-%m-%d", localtime(time()));
5726 $storecfg = PVE
::Storage
::config
();
5727 if (!$statestorage) {
5728 $statestorage = find_vmstate_storage
($conf, $storecfg);
5729 # check permissions for the storage
5730 my $rpcenv = PVE
::RPCEnvironment
::get
();
5731 if ($rpcenv->{type
} ne 'cli') {
5732 my $authuser = $rpcenv->get_user();
5733 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5738 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate(
5739 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5740 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5741 PVE
::QemuConfig-
>write_config($vmid, $conf);
5743 mon_cmd
($vmid, "stop");
5747 if ($includestate) {
5749 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5752 set_migration_caps
($vmid, 1);
5753 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5755 my $state = mon_cmd
($vmid, "query-savevm");
5756 if (!$state->{status
}) {
5757 die "savevm not active\n";
5758 } elsif ($state->{status
} eq 'active') {
5761 } elsif ($state->{status
} eq 'completed') {
5762 print "State saved, quitting\n";
5764 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5765 die "query-savevm failed with error '$state->{error}'\n"
5767 die "query-savevm returned status '$state->{status}'\n";
5773 PVE
::QemuConfig-
>lock_config($vmid, sub {
5774 $conf = PVE
::QemuConfig-
>load_config($vmid);
5776 # cleanup, but leave suspending lock, to indicate something went wrong
5778 mon_cmd
($vmid, "savevm-end");
5779 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5780 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5781 delete $conf->@{qw(vmstate runningmachine runningcpu)};
5782 PVE
::QemuConfig-
>write_config($vmid, $conf);
5788 die "lock changed unexpectedly\n"
5789 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5791 mon_cmd
($vmid, "quit");
5792 $conf->{lock} = 'suspended';
5793 PVE
::QemuConfig-
>write_config($vmid, $conf);
5799 my ($vmid, $skiplock, $nocheck) = @_;
5801 PVE
::QemuConfig-
>lock_config($vmid, sub {
5802 my $res = mon_cmd
($vmid, 'query-status');
5803 my $resume_cmd = 'cont';
5806 if ($res->{status
}) {
5807 return if $res->{status
} eq 'running'; # job done, go home
5808 $resume_cmd = 'system_wakeup' if $res->{status
} eq 'suspended';
5809 $reset = 1 if $res->{status
} eq 'shutdown';
5814 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5816 PVE
::QemuConfig-
>check_lock($conf)
5817 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5821 # required if a VM shuts down during a backup and we get a resume
5822 # request before the backup finishes for example
5823 mon_cmd
($vmid, "system_reset");
5825 mon_cmd
($vmid, $resume_cmd);
5830 my ($vmid, $skiplock, $key) = @_;
5832 PVE
::QemuConfig-
>lock_config($vmid, sub {
5834 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5836 # there is no qmp command, so we use the human monitor command
5837 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5838 die $res if $res ne '';
5842 # vzdump restore implementaion
5844 sub tar_archive_read_firstfile
{
5845 my $archive = shift;
5847 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5849 # try to detect archive type first
5850 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5851 die "unable to open file '$archive'\n";
5852 my $firstfile = <$fh>;
5856 die "ERROR: archive contaions no data\n" if !$firstfile;
5862 sub tar_restore_cleanup
{
5863 my ($storecfg, $statfile) = @_;
5865 print STDERR
"starting cleanup\n";
5867 if (my $fd = IO
::File-
>new($statfile, "r")) {
5868 while (defined(my $line = <$fd>)) {
5869 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5872 if ($volid =~ m
|^/|) {
5873 unlink $volid || die 'unlink failed\n';
5875 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5877 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5879 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5881 print STDERR
"unable to parse line in statfile - $line";
5888 sub restore_file_archive
{
5889 my ($archive, $vmid, $user, $opts) = @_;
5891 return restore_vma_archive
($archive, $vmid, $user, $opts)
5894 my $info = PVE
::Storage
::archive_info
($archive);
5895 my $format = $opts->{format
} // $info->{format
};
5896 my $comp = $info->{compression
};
5898 # try to detect archive format
5899 if ($format eq 'tar') {
5900 return restore_tar_archive
($archive, $vmid, $user, $opts);
5902 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5906 # hepler to remove disks that will not be used after restore
5907 my $restore_cleanup_oldconf = sub {
5908 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5910 PVE
::QemuConfig-
>foreach_volume($oldconf, sub {
5911 my ($ds, $drive) = @_;
5913 return if drive_is_cdrom
($drive, 1);
5915 my $volid = $drive->{file
};
5916 return if !$volid || $volid =~ m
|^/|;
5918 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
5919 return if !$path || !$owner || ($owner != $vmid);
5921 # Note: only delete disk we want to restore
5922 # other volumes will become unused
5923 if ($virtdev_hash->{$ds}) {
5924 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
5931 # delete vmstate files, after the restore we have no snapshots anymore
5932 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5933 my $snap = $oldconf->{snapshots
}->{$snapname};
5934 if ($snap->{vmstate
}) {
5935 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
5943 # Helper to parse vzdump backup device hints
5945 # $rpcenv: Environment, used to ckeck storage permissions
5946 # $user: User ID, to check storage permissions
5947 # $storecfg: Storage configuration
5948 # $fh: the file handle for reading the configuration
5949 # $devinfo: should contain device sizes for all backu-up'ed devices
5950 # $options: backup options (pool, default storage)
5952 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5953 my $parse_backup_hints = sub {
5954 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
5956 my $virtdev_hash = {};
5958 while (defined(my $line = <$fh>)) {
5959 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5960 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5961 die "archive does not contain data for drive '$virtdev'\n"
5962 if !$devinfo->{$devname};
5964 if (defined($options->{storage
})) {
5965 $storeid = $options->{storage
} || 'local';
5966 } elsif (!$storeid) {
5969 $format = 'raw' if !$format;
5970 $devinfo->{$devname}->{devname
} = $devname;
5971 $devinfo->{$devname}->{virtdev
} = $virtdev;
5972 $devinfo->{$devname}->{format
} = $format;
5973 $devinfo->{$devname}->{storeid
} = $storeid;
5975 # check permission on storage
5976 my $pool = $options->{pool
}; # todo: do we need that?
5977 if ($user ne 'root@pam') {
5978 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5981 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5982 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5984 my $drive = parse_drive
($virtdev, $2);
5985 if (drive_is_cloudinit
($drive)) {
5986 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5987 $storeid = $options->{storage
} if defined ($options->{storage
});
5988 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5989 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
5991 $virtdev_hash->{$virtdev} = {
5993 storeid
=> $storeid,
5994 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6001 return $virtdev_hash;
6004 # Helper to allocate and activate all volumes required for a restore
6006 # $storecfg: Storage configuration
6007 # $virtdev_hash: as returned by parse_backup_hints()
6009 # Returns: { $virtdev => $volid }
6010 my $restore_allocate_devices = sub {
6011 my ($storecfg, $virtdev_hash, $vmid) = @_;
6014 foreach my $virtdev (sort keys %$virtdev_hash) {
6015 my $d = $virtdev_hash->{$virtdev};
6016 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6017 my $storeid = $d->{storeid
};
6018 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6020 # test if requested format is supported
6021 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6022 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6023 $d->{format
} = $defFormat if !$supported;
6026 if ($d->{is_cloudinit
}) {
6027 $name = "vm-$vmid-cloudinit";
6028 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6029 if ($scfg->{path
}) {
6030 $name .= ".$d->{format}";
6034 my $volid = PVE
::Storage
::vdisk_alloc
(
6035 $storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6037 print STDERR
"new volume ID is '$volid'\n";
6038 $d->{volid
} = $volid;
6040 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6042 $map->{$virtdev} = $volid;
6048 sub restore_update_config_line
{
6049 my ($cookie, $map, $line, $unique) = @_;
6051 return '' if $line =~ m/^\#qmdump\#/;
6052 return '' if $line =~ m/^\#vzdump\#/;
6053 return '' if $line =~ m/^lock:/;
6054 return '' if $line =~ m/^unused\d+:/;
6055 return '' if $line =~ m/^parent:/;
6059 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
6060 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6061 # try to convert old 1.X settings
6062 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6063 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
6064 my ($model, $macaddr) = split(/\=/, $devconfig);
6065 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
6068 bridge
=> "vmbr$ind",
6069 macaddr
=> $macaddr,
6071 my $netstr = print_net
($net);
6073 $res .= "net$cookie->{netcount}: $netstr\n";
6074 $cookie->{netcount
}++;
6076 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6077 my ($id, $netstr) = ($1, $2);
6078 my $net = parse_net
($netstr);
6079 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
6080 $netstr = print_net
($net);
6081 $res .= "$id: $netstr\n";
6082 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
6085 my $di = parse_drive
($virtdev, $value);
6086 if (defined($di->{backup
}) && !$di->{backup
}) {
6088 } elsif ($map->{$virtdev}) {
6089 delete $di->{format
}; # format can change on restore
6090 $di->{file
} = $map->{$virtdev};
6091 $value = print_drive
($di);
6092 $res .= "$virtdev: $value\n";
6096 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6098 if ($vmgenid ne '0') {
6099 # always generate a new vmgenid if there was a valid one setup
6100 $vmgenid = generate_uuid
();
6102 $res .= "vmgenid: $vmgenid\n";
6103 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6104 my ($uuid, $uuid_str);
6105 UUID
::generate
($uuid);
6106 UUID
::unparse
($uuid, $uuid_str);
6107 my $smbios1 = parse_smbios1
($2);
6108 $smbios1->{uuid
} = $uuid_str;
6109 $res .= $1.print_smbios1
($smbios1)."\n";
6117 my $restore_deactivate_volumes = sub {
6118 my ($storecfg, $devinfo) = @_;
6121 foreach my $devname (keys %$devinfo) {
6122 my $volid = $devinfo->{$devname}->{volid
};
6123 push @$vollist, $volid if $volid;
6126 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
6129 my $restore_destroy_volumes = sub {
6130 my ($storecfg, $devinfo) = @_;
6132 foreach my $devname (keys %$devinfo) {
6133 my $volid = $devinfo->{$devname}->{volid
};
6136 if ($volid =~ m
|^/|) {
6137 unlink $volid || die 'unlink failed\n';
6139 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6141 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6143 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6148 my ($cfg, $vmid) = @_;
6150 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid, undef, 'images');
6152 my $volid_hash = {};
6153 foreach my $storeid (keys %$info) {
6154 foreach my $item (@{$info->{$storeid}}) {
6155 next if !($item->{volid
} && $item->{size
});
6156 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6157 $volid_hash->{$item->{volid
}} = $item;
6164 sub update_disk_config
{
6165 my ($vmid, $conf, $volid_hash) = @_;
6168 my $prefix = "VM $vmid";
6170 # used and unused disks
6171 my $referenced = {};
6173 # Note: it is allowed to define multiple storages with same path (alias), so
6174 # we need to check both 'volid' and real 'path' (two different volid can point
6175 # to the same path).
6177 my $referencedpath = {};
6180 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6181 my ($opt, $drive) = @_;
6183 my $volid = $drive->{file
};
6185 my $volume = $volid_hash->{$volid};
6187 # mark volid as "in-use" for next step
6188 $referenced->{$volid} = 1;
6189 if ($volume && (my $path = $volume->{path
})) {
6190 $referencedpath->{$path} = 1;
6193 return if drive_is_cdrom
($drive);
6196 my ($updated, $msg) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volume->{size
});
6197 if (defined($updated)) {
6199 $conf->{$opt} = print_drive
($updated);
6200 print "$prefix ($opt): $msg\n";
6204 # remove 'unusedX' entry if volume is used
6205 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
6206 my ($opt, $drive) = @_;
6208 my $volid = $drive->{file
};
6212 $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6213 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6214 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
6216 delete $conf->{$opt};
6219 $referenced->{$volid} = 1;
6220 $referencedpath->{$path} = 1 if $path;
6223 foreach my $volid (sort keys %$volid_hash) {
6224 next if $volid =~ m/vm-$vmid-state-/;
6225 next if $referenced->{$volid};
6226 my $path = $volid_hash->{$volid}->{path
};
6227 next if !$path; # just to be sure
6228 next if $referencedpath->{$path};
6230 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6231 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
6232 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6239 my ($vmid, $nolock, $dryrun) = @_;
6241 my $cfg = PVE
::Storage
::config
();
6243 print "rescan volumes...\n";
6244 my $volid_hash = scan_volids
($cfg, $vmid);
6246 my $updatefn = sub {
6249 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6251 PVE
::QemuConfig-
>check_lock($conf);
6254 foreach my $volid (keys %$volid_hash) {
6255 my $info = $volid_hash->{$volid};
6256 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6259 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
6261 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6264 if (defined($vmid)) {
6268 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6271 my $vmlist = config_list
();
6272 foreach my $vmid (keys %$vmlist) {
6276 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6282 sub restore_proxmox_backup_archive
{
6283 my ($archive, $vmid, $user, $options) = @_;
6285 my $storecfg = PVE
::Storage
::config
();
6287 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
6288 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6290 my $fingerprint = $scfg->{fingerprint
};
6291 my $keyfile = PVE
::Storage
::PBSPlugin
::pbs_encryption_key_file_name
($storecfg, $storeid);
6293 my $repo = PVE
::PBSClient
::get_repository
($scfg);
6295 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
6296 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
6297 local $ENV{PBS_PASSWORD
} = $password;
6298 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
6300 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6301 PVE
::Storage
::parse_volname
($storecfg, $archive);
6303 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6305 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6307 my $tmpdir = "/var/tmp/vzdumptmp$$";
6311 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6312 # disable interrupts (always do cleanups)
6316 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6318 # Note: $oldconf is undef if VM does not exists
6319 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6320 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6321 my $new_conf_raw = '';
6323 my $rpcenv = PVE
::RPCEnvironment
::get
();
6332 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6334 my $cfgfn = "$tmpdir/qemu-server.conf";
6335 my $firewall_config_fn = "$tmpdir/fw.conf";
6336 my $index_fn = "$tmpdir/index.json";
6338 my $cmd = "restore";
6340 my $param = [$pbs_backup_name, "index.json", $index_fn];
6341 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6342 my $index = PVE
::Tools
::file_get_contents
($index_fn);
6343 $index = decode_json
($index);
6345 # print Dumper($index);
6346 foreach my $info (@{$index->{files
}}) {
6347 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
6349 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
6350 $devinfo->{$devname}->{size
} = $1;
6352 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6357 my $is_qemu_server_backup = scalar(
6358 grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}}
6360 if (!$is_qemu_server_backup) {
6361 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6363 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
6365 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6366 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6368 if ($has_firewall_config) {
6369 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6370 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6372 my $pve_firewall_dir = '/etc/pve/firewall';
6373 mkdir $pve_firewall_dir; # make sure the dir exists
6374 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6377 my $fh = IO
::File-
>new($cfgfn, "r") ||
6378 die "unable to read qemu-server.conf - $!\n";
6380 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6382 # fixme: rate limit?
6384 # create empty/temp config
6385 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6387 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6390 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6392 foreach my $virtdev (sort keys %$virtdev_hash) {
6393 my $d = $virtdev_hash->{$virtdev};
6394 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6396 # this fails if storage is unavailable
6397 my $volid = $d->{volid
};
6398 my $path = PVE
::Storage
::path
($storecfg, $volid);
6400 # for live-restore we only want to preload the efidisk
6401 next if $options->{live
} && $virtdev ne 'efidisk0';
6403 my $pbs_restore_cmd = [
6404 '/usr/bin/pbs-restore',
6405 '--repository', $repo,
6407 "$d->{devname}.img.fidx",
6412 push @$pbs_restore_cmd, '--format', $d->{format
} if $d->{format
};
6413 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e
$keyfile;
6415 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6416 push @$pbs_restore_cmd, '--skip-zero';
6419 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6420 print "restore proxmox backup image: $dbg_cmdstring\n";
6421 run_command
($pbs_restore_cmd);
6424 $fh->seek(0, 0) || die "seek failed - $!\n";
6426 my $cookie = { netcount
=> 0 };
6427 while (defined(my $line = <$fh>)) {
6428 $new_conf_raw .= restore_update_config_line
(
6440 if ($err || !$options->{live
}) {
6441 $restore_deactivate_volumes->($storecfg, $devinfo);
6447 $restore_destroy_volumes->($storecfg, $devinfo);
6451 if ($options->{live
}) {
6452 # keep lock during live-restore
6453 $new_conf_raw .= "\nlock: create";
6456 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6458 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6460 eval { rescan
($vmid, 1); };
6463 PVE
::AccessControl
::add_vm_to_pool
($vmid, $options->{pool
}) if $options->{pool
};
6465 if ($options->{live
}) {
6471 local $SIG{PIPE
} = sub { die "got signal ($!) - abort\n"; };
6473 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6474 die "cannot do live-restore for template\n" if PVE
::QemuConfig-
>is_template($conf);
6476 delete $devinfo->{'drive-efidisk0'}; # this special drive is already restored before start
6477 pbs_live_restore
($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
6479 PVE
::QemuConfig-
>remove_lock($vmid, "create");
6483 sub pbs_live_restore
{
6484 my ($vmid, $conf, $storecfg, $restored_disks, $repo, $keyfile, $snap) = @_;
6486 print "starting VM for live-restore\n";
6487 print "repository: '$repo', snapshot: '$snap'\n";
6489 my $pbs_backing = {};
6490 for my $ds (keys %$restored_disks) {
6491 $ds =~ m/^drive-(.*)$/;
6493 $pbs_backing->{$confname} = {
6494 repository
=> $repo,
6496 archive
=> "$ds.img.fidx",
6498 $pbs_backing->{$confname}->{keyfile
} = $keyfile if -e
$keyfile;
6500 my $drive = parse_drive
($confname, $conf->{$confname});
6501 print "restoring '$ds' to '$drive->{file}'\n";
6504 my $drives_streamed = 0;
6506 # make sure HA doesn't interrupt our restore by stopping the VM
6507 if (PVE
::HA
::Config
::vm_is_ha_managed
($vmid)) {
6508 run_command
(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
6511 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6512 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
6513 vm_start_nolock
($storecfg, $vmid, $conf, {paused
=> 1, 'pbs-backing' => $pbs_backing}, {});
6515 my $qmeventd_fd = register_qmeventd_handle
($vmid);
6517 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6518 # this will effectively collapse the backing image chain consisting of
6519 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6520 # removes itself once all backing images vanish with 'auto-remove=on')
6522 for my $ds (sort keys %$restored_disks) {
6523 my $job_id = "restore-$ds";
6524 mon_cmd
($vmid, 'block-stream',
6525 'job-id' => $job_id,
6528 $jobs->{$job_id} = {};
6531 mon_cmd
($vmid, 'cont');
6532 qemu_drive_mirror_monitor
($vmid, undef, $jobs, 'auto', 0, 'stream');
6534 print "restore-drive jobs finished successfully, removing all tracking block devices"
6535 ." to disconnect from Proxmox Backup Server\n";
6537 for my $ds (sort keys %$restored_disks) {
6538 mon_cmd
($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6541 close($qmeventd_fd);
6547 warn "An error occured during live-restore: $err\n";
6548 _do_vm_stop
($storecfg, $vmid, 1, 1, 10, 0, 1);
6549 die "live-restore failed\n";
6553 sub restore_vma_archive
{
6554 my ($archive, $vmid, $user, $opts, $comp) = @_;
6556 my $readfrom = $archive;
6558 my $cfg = PVE
::Storage
::config
();
6560 my $bwlimit = $opts->{bwlimit
};
6562 my $dbg_cmdstring = '';
6563 my $add_pipe = sub {
6565 push @$commands, $cmd;
6566 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6567 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6572 if ($archive eq '-') {
6575 # If we use a backup from a PVE defined storage we also consider that
6576 # storage's rate limit:
6577 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6578 if (defined($volid)) {
6579 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6580 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6582 print STDERR
"applying read rate limit: $readlimit\n";
6583 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6584 $add_pipe->($cstream);
6590 my $info = PVE
::Storage
::decompressor_info
('vma', $comp);
6591 my $cmd = $info->{decompressor
};
6592 push @$cmd, $readfrom;
6596 my $tmpdir = "/var/tmp/vzdumptmp$$";
6599 # disable interrupts (always do cleanups)
6603 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6605 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6606 POSIX
::mkfifo
($mapfifo, 0600);
6608 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
6610 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6617 my $rpcenv = PVE
::RPCEnvironment
::get
();
6619 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6621 # Note: $oldconf is undef if VM does not exist
6622 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6623 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6624 my $new_conf_raw = '';
6628 my $print_devmap = sub {
6629 my $cfgfn = "$tmpdir/qemu-server.conf";
6631 # we can read the config - that is already extracted
6632 my $fh = IO
::File-
>new($cfgfn, "r") ||
6633 die "unable to read qemu-server.conf - $!\n";
6635 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6637 my $pve_firewall_dir = '/etc/pve/firewall';
6638 mkdir $pve_firewall_dir; # make sure the dir exists
6639 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6642 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6644 foreach my $info (values %{$virtdev_hash}) {
6645 my $storeid = $info->{storeid
};
6646 next if defined($storage_limits{$storeid});
6648 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$storeid], $bwlimit) // 0;
6649 print STDERR
"rate limit for storage $storeid: $limit KiB/s\n" if $limit;
6650 $storage_limits{$storeid} = $limit * 1024;
6653 foreach my $devname (keys %$devinfo) {
6654 die "found no device mapping information for device '$devname'\n"
6655 if !$devinfo->{$devname}->{virtdev
};
6658 # create empty/temp config
6660 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6661 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6665 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6667 # print restore information to $fifofh
6668 foreach my $virtdev (sort keys %$virtdev_hash) {
6669 my $d = $virtdev_hash->{$virtdev};
6670 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6672 my $storeid = $d->{storeid
};
6673 my $volid = $d->{volid
};
6676 if (my $limit = $storage_limits{$storeid}) {
6677 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6680 my $write_zeros = 1;
6681 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6685 my $path = PVE
::Storage
::path
($cfg, $volid);
6687 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6689 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6692 $fh->seek(0, 0) || die "seek failed - $!\n";
6694 my $cookie = { netcount
=> 0 };
6695 while (defined(my $line = <$fh>)) {
6696 $new_conf_raw .= restore_update_config_line
(
6713 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6714 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6716 $oldtimeout = alarm($timeout);
6723 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6724 my ($dev_id, $size, $devname) = ($1, $2, $3);
6725 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6726 } elsif ($line =~ m/^CTIME: /) {
6727 # we correctly received the vma config, so we can disable
6728 # the timeout now for disk allocation (set to 10 minutes, so
6729 # that we always timeout if something goes wrong)
6732 print $fifofh "done\n";
6733 my $tmp = $oldtimeout || 0;
6734 $oldtimeout = undef;
6741 print "restore vma archive: $dbg_cmdstring\n";
6742 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6746 alarm($oldtimeout) if $oldtimeout;
6748 $restore_deactivate_volumes->($cfg, $devinfo);
6750 close($fifofh) if $fifofh;
6755 $restore_destroy_volumes->($cfg, $devinfo);
6759 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6761 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6763 eval { rescan
($vmid, 1); };
6766 PVE
::AccessControl
::add_vm_to_pool
($vmid, $opts->{pool
}) if $opts->{pool
};
6769 sub restore_tar_archive
{
6770 my ($archive, $vmid, $user, $opts) = @_;
6772 if ($archive ne '-') {
6773 my $firstfile = tar_archive_read_firstfile
($archive);
6774 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
6775 if $firstfile ne 'qemu-server.conf';
6778 my $storecfg = PVE
::Storage
::config
();
6780 # avoid zombie disks when restoring over an existing VM -> cleanup first
6781 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6782 # skiplock=1 because qmrestore has set the 'create' lock itself already
6783 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6784 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6786 my $tocmd = "/usr/lib/qemu-server/qmextract";
6788 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6789 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6790 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6791 $tocmd .= ' --info' if $opts->{info
};
6793 # tar option "xf" does not autodetect compression when read from STDIN,
6794 # so we pipe to zcat
6795 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6796 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6798 my $tmpdir = "/var/tmp/vzdumptmp$$";
6801 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6802 local $ENV{VZDUMP_VMID
} = $vmid;
6803 local $ENV{VZDUMP_USER
} = $user;
6805 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6806 my $new_conf_raw = '';
6808 # disable interrupts (always do cleanups)
6812 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6820 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6822 if ($archive eq '-') {
6823 print "extracting archive from STDIN\n";
6824 run_command
($cmd, input
=> "<&STDIN");
6826 print "extracting archive '$archive'\n";
6830 return if $opts->{info
};
6834 my $statfile = "$tmpdir/qmrestore.stat";
6835 if (my $fd = IO
::File-
>new($statfile, "r")) {
6836 while (defined (my $line = <$fd>)) {
6837 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6838 $map->{$1} = $2 if $1;
6840 print STDERR
"unable to parse line in statfile - $line\n";
6846 my $confsrc = "$tmpdir/qemu-server.conf";
6848 my $srcfd = IO
::File-
>new($confsrc, "r") || die "unable to open file '$confsrc'\n";
6850 my $cookie = { netcount
=> 0 };
6851 while (defined (my $line = <$srcfd>)) {
6852 $new_conf_raw .= restore_update_config_line
(
6863 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6869 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6871 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6873 eval { rescan
($vmid, 1); };
6877 sub foreach_storage_used_by_vm
{
6878 my ($conf, $func) = @_;
6882 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6883 my ($ds, $drive) = @_;
6884 return if drive_is_cdrom
($drive);
6886 my $volid = $drive->{file
};
6888 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6889 $sidhash->{$sid} = $sid if $sid;
6892 foreach my $sid (sort keys %$sidhash) {
6897 my $qemu_snap_storage = {
6900 sub do_snapshots_with_qemu
{
6901 my ($storecfg, $volid) = @_;
6903 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6904 my $scfg = $storecfg->{ids
}->{$storage_name};
6905 die "could not find storage '$storage_name'\n" if !defined($scfg);
6907 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6911 if ($volid =~ m/\.(qcow2|qed)$/){
6918 sub qga_check_running
{
6919 my ($vmid, $nowarn) = @_;
6921 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6923 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6929 sub template_create
{
6930 my ($vmid, $conf, $disk) = @_;
6932 my $storecfg = PVE
::Storage
::config
();
6934 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6935 my ($ds, $drive) = @_;
6937 return if drive_is_cdrom
($drive);
6938 return if $disk && $ds ne $disk;
6940 my $volid = $drive->{file
};
6941 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6943 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6944 $drive->{file
} = $voliddst;
6945 $conf->{$ds} = print_drive
($drive);
6946 PVE
::QemuConfig-
>write_config($vmid, $conf);
6950 sub convert_iscsi_path
{
6953 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6958 my $initiator_name = get_initiator_name
();
6960 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6961 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6964 die "cannot convert iscsi path '$path', unkown format\n";
6967 sub qemu_img_convert
{
6968 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6970 my $storecfg = PVE
::Storage
::config
();
6971 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6972 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6974 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6978 my $src_is_iscsi = 0;
6982 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6983 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6984 $src_format = qemu_img_format
($src_scfg, $src_volname);
6985 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6986 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6987 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
6988 } elsif (-f
$src_volid) {
6989 $src_path = $src_volid;
6990 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6995 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
6997 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6998 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6999 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7000 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
7003 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
7004 push @$cmd, '-l', "snapshot.name=$snapname"
7005 if $snapname && $src_format && $src_format eq "qcow2";
7006 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
7007 push @$cmd, '-T', $cachemode if defined($cachemode);
7009 if ($src_is_iscsi) {
7010 push @$cmd, '--image-opts';
7011 $src_path = convert_iscsi_path
($src_path);
7012 } elsif ($src_format) {
7013 push @$cmd, '-f', $src_format;
7016 if ($dst_is_iscsi) {
7017 push @$cmd, '--target-image-opts';
7018 $dst_path = convert_iscsi_path
($dst_path);
7020 push @$cmd, '-O', $dst_format;
7023 push @$cmd, $src_path;
7025 if (!$dst_is_iscsi && $is_zero_initialized) {
7026 push @$cmd, "zeroinit:$dst_path";
7028 push @$cmd, $dst_path;
7033 if($line =~ m/\((\S+)\/100\
%\)/){
7035 my $transferred = int($size * $percent / 100);
7036 my $total_h = render_bytes
($size, 1);
7037 my $transferred_h = render_bytes
($transferred, 1);
7039 print "transferred $transferred_h of $total_h ($percent%)\n";
7044 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
7046 die "copy failed: $err" if $err;
7049 sub qemu_img_format
{
7050 my ($scfg, $volname) = @_;
7052 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
7059 sub qemu_drive_mirror
{
7060 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
7062 $jobs = {} if !$jobs;
7066 $jobs->{"drive-$drive"} = {};
7068 if ($dst_volid =~ /^nbd:/) {
7069 $qemu_target = $dst_volid;
7072 my $storecfg = PVE
::Storage
::config
();
7073 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
7075 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7077 $format = qemu_img_format
($dst_scfg, $dst_volname);
7079 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7081 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
7084 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
7085 $opts->{format
} = $format if $format;
7087 if (defined($src_bitmap)) {
7088 $opts->{sync
} = 'incremental';
7089 $opts->{bitmap
} = $src_bitmap;
7090 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7093 if (defined($bwlimit)) {
7094 $opts->{speed
} = $bwlimit * 1024;
7095 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
7097 print "drive mirror is starting for drive-$drive\n";
7100 # if a job already runs for this device we get an error, catch it for cleanup
7101 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
7103 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7105 die "mirroring error: $err\n";
7108 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
7111 # $completion can be either
7112 # 'complete': wait until all jobs are ready, block-job-complete them (default)
7113 # 'cancel': wait until all jobs are ready, block-job-cancel them
7114 # 'skip': wait until all jobs are ready, return with block jobs in ready state
7115 # 'auto': wait until all jobs disappear, only use for jobs which complete automatically
7116 sub qemu_drive_mirror_monitor
{
7117 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
7119 $completion //= 'complete';
7123 my $err_complete = 0;
7125 my $starttime = time ();
7127 die "block job ('$op') timed out\n" if $err_complete > 300;
7129 my $stats = mon_cmd
($vmid, "query-block-jobs");
7132 my $running_jobs = {};
7133 for my $stat (@$stats) {
7134 next if $stat->{type
} ne $op;
7135 $running_jobs->{$stat->{device
}} = $stat;
7138 my $readycounter = 0;
7140 for my $job_id (sort keys %$jobs) {
7141 my $job = $running_jobs->{$job_id};
7143 my $vanished = !defined($job);
7144 my $complete = defined($jobs->{$job_id}->{complete
}) && $vanished;
7145 if($complete || ($vanished && $completion eq 'auto')) {
7146 print "$job_id: $op-job finished\n";
7147 delete $jobs->{$job_id};
7151 die "$job_id: '$op' has been cancelled\n" if !defined($job);
7153 my $busy = $job->{busy
};
7154 my $ready = $job->{ready
};
7155 if (my $total = $job->{len
}) {
7156 my $transferred = $job->{offset
} || 0;
7157 my $remaining = $total - $transferred;
7158 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
7160 my $duration = $ctime - $starttime;
7161 my $total_h = render_bytes
($total, 1);
7162 my $transferred_h = render_bytes
($transferred, 1);
7164 my $status = sprintf(
7165 "transferred $transferred_h of $total_h ($percent%%) in %s",
7166 render_duration
($duration),
7171 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7173 $status .= ", ready";
7176 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready
};
7177 $jobs->{$job_id}->{ready
} = $ready;
7180 $readycounter++ if $job->{ready
};
7183 last if scalar(keys %$jobs) == 0;
7185 if ($readycounter == scalar(keys %$jobs)) {
7186 print "all '$op' jobs are ready\n";
7188 # do the complete later (or has already been done)
7189 last if $completion eq 'skip' || $completion eq 'auto';
7191 if ($vmiddst && $vmiddst != $vmid) {
7192 my $agent_running = $qga && qga_check_running
($vmid);
7193 if ($agent_running) {
7194 print "freeze filesystem\n";
7195 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
7197 print "suspend vm\n";
7198 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
7201 # if we clone a disk for a new target vm, we don't switch the disk
7202 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
7204 if ($agent_running) {
7205 print "unfreeze filesystem\n";
7206 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
7208 print "resume vm\n";
7209 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
7215 for my $job_id (sort keys %$jobs) {
7216 # try to switch the disk if source and destination are on the same guest
7217 print "$job_id: Completing block job_id...\n";
7220 if ($completion eq 'complete') {
7221 $op = 'block-job-complete';
7222 } elsif ($completion eq 'cancel') {
7223 $op = 'block-job-cancel';
7225 die "invalid completion value: $completion\n";
7227 eval { mon_cmd
($vmid, $op, device
=> $job_id) };
7228 if ($@ =~ m/cannot be completed/) {
7229 print "$job_id: block job cannot be completed, trying again.\n";
7232 print "$job_id: Completed successfully.\n";
7233 $jobs->{$job_id}->{complete
} = 1;
7244 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7245 die "block job ($op) error: $err";
7249 sub qemu_blockjobs_cancel
{
7250 my ($vmid, $jobs) = @_;
7252 foreach my $job (keys %$jobs) {
7253 print "$job: Cancelling block job\n";
7254 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
7255 $jobs->{$job}->{cancel
} = 1;
7259 my $stats = mon_cmd
($vmid, "query-block-jobs");
7261 my $running_jobs = {};
7262 foreach my $stat (@$stats) {
7263 $running_jobs->{$stat->{device
}} = $stat;
7266 foreach my $job (keys %$jobs) {
7268 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
7269 print "$job: Done.\n";
7270 delete $jobs->{$job};
7274 last if scalar(keys %$jobs) == 0;
7281 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7282 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
7287 print "create linked clone of drive $drivename ($drive->{file})\n";
7288 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
7289 push @$newvollist, $newvolid;
7292 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7293 $storeid = $storage if $storage;
7295 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7297 print "create full clone of drive $drivename ($drive->{file})\n";
7300 if (drive_is_cloudinit
($drive)) {
7301 $name = "vm-$newvmid-cloudinit";
7302 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7303 if ($scfg->{path
}) {
7304 $name .= ".$dst_format";
7307 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
7308 } elsif ($drivename eq 'efidisk0') {
7309 $size = get_efivars_size
($conf);
7311 ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 10);
7313 $newvolid = PVE
::Storage
::vdisk_alloc
(
7314 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7316 push @$newvollist, $newvolid;
7318 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7320 if (drive_is_cloudinit
($drive)) {
7321 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7322 # if this is the case, we have to complete any block-jobs still there from
7323 # previous drive-mirrors
7324 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7325 qemu_drive_mirror_monitor
($vmid, $newvmid, $jobs, $completion, $qga);
7330 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7331 if (!$running || $snapname) {
7332 # TODO: handle bwlimits
7333 if ($drivename eq 'efidisk0') {
7334 # the relevant data on the efidisk may be smaller than the source
7335 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7336 # that is given by the OVMF_VARS.fd
7337 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
7338 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
7340 # better for Ceph if block size is not too small, see bug #3324
7343 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=$bs", "osize=$size",
7344 "if=$src_path", "of=$dst_path"]);
7346 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7350 my $kvmver = get_running_qemu_version
($vmid);
7351 if (!min_version
($kvmver, 2, 7)) {
7352 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7353 if $drive->{iothread
};
7356 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7357 $completion, $qga, $bwlimit);
7362 my ($size) = eval { PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 10) };
7365 $disk->{format
} = undef;
7366 $disk->{file
} = $newvolid;
7367 $disk->{size
} = $size if defined($size);
7372 sub get_running_qemu_version
{
7374 my $res = mon_cmd
($vmid, "query-version");
7375 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7378 sub qemu_use_old_bios_files
{
7379 my ($machine_type) = @_;
7381 return if !$machine_type;
7383 my $use_old_bios_files = undef;
7385 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7387 $use_old_bios_files = 1;
7389 my $version = extract_version
($machine_type, kvm_user_version
());
7390 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7391 # load new efi bios files on migration. So this hack is required to allow
7392 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7393 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7394 $use_old_bios_files = !min_version
($version, 2, 4);
7397 return ($use_old_bios_files, $machine_type);
7400 sub get_efivars_size
{
7402 my $arch = get_vm_arch
($conf);
7403 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
7404 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
7405 return -s
$ovmf_vars;
7408 sub update_efidisk_size
{
7411 return if !defined($conf->{efidisk0
});
7413 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
7414 $disk->{size
} = get_efivars_size
($conf);
7415 $conf->{efidisk0
} = print_drive
($disk);
7420 sub create_efidisk
($$$$$) {
7421 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
7423 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
7424 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7426 my $vars_size_b = -s
$ovmf_vars;
7427 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
7428 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7429 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7431 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
7432 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
7434 return ($volid, $size/1024);
7437 sub vm_iothreads_list
{
7440 my $res = mon_cmd
($vmid, 'query-iothreads');
7443 foreach my $iothread (@$res) {
7444 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7451 my ($conf, $drive) = @_;
7455 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7457 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7463 my $controller = int($drive->{index} / $maxdev);
7464 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single')
7468 return ($maxdev, $controller, $controller_prefix);
7471 sub windows_version
{
7474 return 0 if !$ostype;
7478 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7480 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7482 } elsif ($ostype =~ m/^win(\d+)$/) {
7489 sub resolve_dst_disk_format
{
7490 my ($storecfg, $storeid, $src_volname, $format) = @_;
7491 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7494 # if no target format is specified, use the source disk format as hint
7496 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7497 $format = qemu_img_format
($scfg, $src_volname);
7503 # test if requested format is supported - else use default
7504 my $supported = grep { $_ eq $format } @$validFormats;
7505 $format = $defFormat if !$supported;
7509 # NOTE: if this logic changes, please update docs & possibly gui logic
7510 sub find_vmstate_storage
{
7511 my ($conf, $storecfg) = @_;
7513 # first, return storage from conf if set
7514 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
7516 my ($target, $shared, $local);
7518 foreach_storage_used_by_vm
($conf, sub {
7520 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7521 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7522 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7525 # second, use shared storage where VM has at least one disk
7526 # third, use local storage where VM has at least one disk
7527 # fall back to local storage
7528 $target = $shared // $local // 'local';
7534 my ($uuid, $uuid_str);
7535 UUID
::generate
($uuid);
7536 UUID
::unparse
($uuid, $uuid_str);
7540 sub generate_smbios1_uuid
{
7541 return "uuid=".generate_uuid
();
7547 mon_cmd
($vmid, 'nbd-server-stop');
7550 sub create_reboot_request
{
7552 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7553 or die "failed to create reboot trigger file: $!\n";
7557 sub clear_reboot_request
{
7559 my $path = "/run/qemu-server/$vmid.reboot";
7562 $res = unlink($path);
7563 die "could not remove reboot request for $vmid: $!"
7564 if !$res && $! != POSIX
::ENOENT
;
7569 sub bootorder_from_legacy
{
7570 my ($conf, $bootcfg) = @_;
7572 my $boot = $bootcfg->{legacy
} || $boot_fmt->{legacy
}->{default};
7573 my $bootindex_hash = {};
7575 foreach my $o (split(//, $boot)) {
7576 $bootindex_hash->{$o} = $i*100;
7582 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7583 my ($ds, $drive) = @_;
7585 if (drive_is_cdrom
($drive, 1)) {
7586 if ($bootindex_hash->{d
}) {
7587 $bootorder->{$ds} = $bootindex_hash->{d
};
7588 $bootindex_hash->{d
} += 1;
7590 } elsif ($bootindex_hash->{c
}) {
7591 $bootorder->{$ds} = $bootindex_hash->{c
}
7592 if $conf->{bootdisk
} && $conf->{bootdisk
} eq $ds;
7593 $bootindex_hash->{c
} += 1;
7597 if ($bootindex_hash->{n
}) {
7598 for (my $i = 0; $i < $MAX_NETS; $i++) {
7599 my $netname = "net$i";
7600 next if !$conf->{$netname};
7601 $bootorder->{$netname} = $bootindex_hash->{n
};
7602 $bootindex_hash->{n
} += 1;
7609 # Generate default device list for 'boot: order=' property. Matches legacy
7610 # default boot order, but with explicit device names. This is important, since
7611 # the fallback for when neither 'order' nor the old format is specified relies
7612 # on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
7613 sub get_default_bootdevices
{
7619 my $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 0);
7620 push @ret, $first if $first;
7623 $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 1);
7624 push @ret, $first if $first;
7627 for (my $i = 0; $i < $MAX_NETS; $i++) {
7628 my $netname = "net$i";
7629 next if !$conf->{$netname};
7630 push @ret, $netname;
7637 sub device_bootorder
{
7640 return bootorder_from_legacy
($conf) if !defined($conf->{boot
});
7642 my $boot = parse_property_string
($boot_fmt, $conf->{boot
});
7645 if (!defined($boot) || $boot->{legacy
}) {
7646 $bootorder = bootorder_from_legacy
($conf, $boot);
7647 } elsif ($boot->{order
}) {
7648 my $i = 100; # start at 100 to allow user to insert devices before us with -args
7649 for my $dev (PVE
::Tools
::split_list
($boot->{order
})) {
7650 $bootorder->{$dev} = $i++;
7657 sub register_qmeventd_handle
{
7661 my $peer = "/var/run/qmeventd.sock";
7666 $fh = IO
::Socket
::UNIX-
>new(Peer
=> $peer, Blocking
=> 0, Timeout
=> 1);
7668 if ($! != EINTR
&& $! != EAGAIN
) {
7669 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
7672 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
7673 . "after $count retries\n";
7678 # send handshake to mark VM as backing up
7679 print $fh to_json
({vzdump
=> {vmid
=> "$vmid"}});
7681 # return handle to be closed later when inhibit is no longer required
7685 # bash completion helper
7687 sub complete_backup_archives
{
7688 my ($cmdname, $pname, $cvalue) = @_;
7690 my $cfg = PVE
::Storage
::config
();
7694 if ($cvalue =~ m/^([^:]+):/) {
7698 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7701 foreach my $id (keys %$data) {
7702 foreach my $item (@{$data->{$id}}) {
7703 next if $item->{format
} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
7704 push @$res, $item->{volid
} if defined($item->{volid
});
7711 my $complete_vmid_full = sub {
7714 my $idlist = vmstatus
();
7718 foreach my $id (keys %$idlist) {
7719 my $d = $idlist->{$id};
7720 if (defined($running)) {
7721 next if $d->{template
};
7722 next if $running && $d->{status
} ne 'running';
7723 next if !$running && $d->{status
} eq 'running';
7732 return &$complete_vmid_full();
7735 sub complete_vmid_stopped
{
7736 return &$complete_vmid_full(0);
7739 sub complete_vmid_running
{
7740 return &$complete_vmid_full(1);
7743 sub complete_storage
{
7745 my $cfg = PVE
::Storage
::config
();
7746 my $ids = $cfg->{ids
};
7749 foreach my $sid (keys %$ids) {
7750 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7751 next if !$ids->{$sid}->{content
}->{images
};
7758 sub complete_migration_storage
{
7759 my ($cmd, $param, $current_value, $all_args) = @_;
7761 my $targetnode = @$all_args[1];
7763 my $cfg = PVE
::Storage
::config
();
7764 my $ids = $cfg->{ids
};
7767 foreach my $sid (keys %$ids) {
7768 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7769 next if !$ids->{$sid}->{content
}->{images
};
7778 my $qmpstatus = eval {
7779 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid);
7780 mon_cmd
($vmid, "query-status");
7783 return $qmpstatus && $qmpstatus->{status
} eq "paused";
7786 sub check_volume_storage_type
{
7787 my ($storecfg, $vol) = @_;
7789 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($vol);
7790 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7791 my ($vtype) = PVE
::Storage
::parse_volname
($storecfg, $vol);
7793 die "storage '$storeid' does not support content-type '$vtype'\n"
7794 if !$scfg->{content
}->{$vtype};