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 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.",
319 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
327 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
334 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
340 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.",
348 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
349 "It should not be necessary to set it.",
350 enum
=> PVE
::Tools
::kvmkeymaplist
(),
355 type
=> 'string', format
=> 'dns-name',
356 description
=> "Set a name for the VM. Only used on the configuration web interface.",
361 description
=> "SCSI controller model",
362 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
368 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
373 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
374 description
=> "Specify guest operating system.",
375 verbose_description
=> <<EODESC,
376 Specify guest operating system. This is used to enable special
377 optimization/features for specific operating systems:
380 other;; unspecified OS
381 wxp;; Microsoft Windows XP
382 w2k;; Microsoft Windows 2000
383 w2k3;; Microsoft Windows 2003
384 w2k8;; Microsoft Windows 2008
385 wvista;; Microsoft Windows Vista
386 win7;; Microsoft Windows 7
387 win8;; Microsoft Windows 8/2012/2012r2
388 win10;; Microsoft Windows 10/2016/2019
389 l24;; Linux 2.4 Kernel
390 l26;; Linux 2.6 - 5.X Kernel
391 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
396 type
=> 'string', format
=> 'pve-qm-boot',
397 description
=> "Specify guest boot order. Use with 'order=', usage with"
398 . " no key or 'legacy=' is deprecated.",
402 type
=> 'string', format
=> 'pve-qm-bootdisk',
403 description
=> "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
404 pattern
=> '(ide|sata|scsi|virtio)\d+',
409 description
=> "The number of CPUs. Please use option -sockets instead.",
416 description
=> "The number of CPU sockets.",
423 description
=> "The number of cores per socket.",
430 description
=> "Enable/disable NUMA.",
436 description
=> "Enable/disable hugepages memory.",
437 enum
=> [qw(any 2 1024)],
443 description
=> "Use together with hugepages. If enabled, hugepages will not not be deleted"
444 ." after VM shutdown and can be used for subsequent starts.",
449 description
=> "Number of hotplugged vcpus.",
456 description
=> "Enable/disable ACPI.",
461 description
=> "Enable/disable Qemu GuestAgent and its properties.",
463 format
=> $agent_fmt,
468 description
=> "Enable/disable KVM hardware virtualization.",
474 description
=> "Enable/disable time drift fix.",
480 description
=> "Set the real time clock to local time. This is enabled by default if ostype"
481 ." indicates a Microsoft OS.",
486 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
490 type
=> 'string', format
=> $vga_fmt,
491 description
=> "Configure the VGA hardware.",
492 verbose_description
=> "Configure the VGA Hardware. If you want to use high resolution"
493 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
494 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
495 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
496 ." display server. For win* OS you can select how many independent displays you want,"
497 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
498 ." using a serial device as terminal.",
502 type
=> 'string', format
=> 'pve-qm-watchdog',
503 description
=> "Create a virtual hardware watchdog device.",
504 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled (by a guest"
505 ." action), the watchdog must be periodically polled by an agent inside the guest or"
506 ." else the watchdog will reset the guest (or execute the respective action specified)",
511 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
512 description
=> "Set the initial date of the real time clock. Valid format for date are:"
513 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
514 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
517 startup
=> get_standard_option
('pve-startup-order'),
521 description
=> "Enable/disable Template.",
527 description
=> "Arbitrary arguments passed to kvm.",
528 verbose_description
=> <<EODESCR,
529 Arbitrary arguments passed to kvm, for example:
531 args: -no-reboot -no-hpet
533 NOTE: this option is for experts only.
540 description
=> "Enable/disable the USB tablet device.",
541 verbose_description
=> "Enable/disable the USB tablet device. This device is usually needed"
542 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
543 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
544 ." may consider disabling this to save some context switches. This is turned off by"
545 ." default if you use spice (`qm set <vmid> --vga qxl`).",
550 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
554 migrate_downtime
=> {
557 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
563 type
=> 'string', format
=> 'pve-qm-ide',
564 typetext
=> '<volume>',
565 description
=> "This is an alias for option -ide2",
569 description
=> "Emulated CPU type.",
571 format
=> 'pve-vm-cpu-conf',
573 parent
=> get_standard_option
('pve-snapshot-name', {
575 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
579 description
=> "Timestamp for snapshots.",
585 type
=> 'string', format
=> 'pve-volume-id',
586 description
=> "Reference to a volume which stores the VM state. This is used internally"
589 vmstatestorage
=> get_standard_option
('pve-storage-id', {
590 description
=> "Default storage for VM state volumes/files.",
593 runningmachine
=> get_standard_option
('pve-qemu-machine', {
594 description
=> "Specifies the QEMU machine type of the running vm. This is used internally"
598 description
=> "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
599 ." internally for snapshots.",
602 pattern
=> $PVE::QemuServer
::CPUConfig
::qemu_cmdline_cpu_re
,
603 format_description
=> 'QEMU -cpu parameter'
605 machine
=> get_standard_option
('pve-qemu-machine'),
607 description
=> "Virtual processor architecture. Defaults to the host.",
610 enum
=> [qw(x86_64 aarch64)],
613 description
=> "Specify SMBIOS type 1 fields.",
614 type
=> 'string', format
=> 'pve-qm-smbios1',
621 description
=> "Sets the protection flag of the VM. This will disable the remove VM and"
622 ." remove disk operations.",
628 enum
=> [ qw(seabios ovmf) ],
629 description
=> "Select BIOS implementation.",
630 default => 'seabios',
634 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
635 format_description
=> 'UUID',
636 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
637 ." to disable explicitly.",
638 verbose_description
=> "The VM generation ID (vmgenid) device exposes a 128-bit integer"
639 ." value identifier to the guest OS. This allows to notify the guest operating system"
640 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
641 ." execution or creation from a template). The guest operating system notices the"
642 ." change, and is then able to react as appropriate by marking its copies of"
643 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
644 ."Note that auto-creation only works when done through API/CLI create or update methods"
645 .", but not when manually editing the config file.",
646 default => "1 (autogenerated)",
651 format
=> 'pve-volume-id',
653 description
=> "Script that will be executed during various steps in the vms lifetime.",
657 format
=> $ivshmem_fmt,
658 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to"
664 format
=> $audio_fmt,
665 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
668 spice_enhancements
=> {
670 format
=> $spice_enhancements_fmt,
671 description
=> "Configure additional enhancements for SPICE.",
675 type
=> 'string', format
=> 'pve-tag-list',
676 description
=> 'Tags of the VM. This is only meta information.',
682 description
=> "Configure a VirtIO-based Random Number Generator.",
691 description
=> 'Specify a custom file containing all meta data passed to the VM via"
692 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
693 format
=> 'pve-volume-id',
694 format_description
=> 'volume',
699 description
=> 'Specify a custom file containing all network data passed to the VM via'
701 format
=> 'pve-volume-id',
702 format_description
=> 'volume',
707 description
=> 'Specify a custom file containing all user data passed to the VM via'
709 format
=> 'pve-volume-id',
710 format_description
=> 'volume',
713 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
715 my $confdesc_cloudinit = {
719 description
=> 'Specifies the cloud-init configuration format. The default depends on the'
720 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
721 .' and `configdrive2` for windows.',
722 enum
=> ['configdrive2', 'nocloud', 'opennebula'],
727 description
=> "cloud-init: User name to change ssh keys and password for instead of the"
728 ." image's configured default user.",
733 description
=> 'cloud-init: Password to assign the user. Using this is generally not'
734 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
735 .' support hashed passwords.',
740 description
=> 'cloud-init: Specify custom files to replace the automatically generated'
742 format
=> 'pve-qm-cicustom',
747 description
=> "cloud-init: Sets DNS search domains for a container. Create will'
748 .' automatically use the setting from the host if neither searchdomain nor nameserver'
753 type
=> 'string', format
=> 'address-list',
754 description
=> "cloud-init: Sets DNS server IP address for a container. Create will'
755 .' automatically use the setting from the host if neither searchdomain nor nameserver'
761 format
=> 'urlencoded',
762 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
766 # what about other qemu settings ?
768 #machine => 'string',
781 ##soundhw => 'string',
783 while (my ($k, $v) = each %$confdesc) {
784 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
787 my $MAX_USB_DEVICES = 5;
789 my $MAX_SERIAL_PORTS = 4;
790 my $MAX_PARALLEL_PORTS = 3;
796 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
797 description
=> "CPUs accessing this NUMA node.",
798 format_description
=> "id[-id];...",
802 description
=> "Amount of memory this NUMA node provides.",
807 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
808 description
=> "Host NUMA nodes to use.",
809 format_description
=> "id[-id];...",
814 enum
=> [qw(preferred bind interleave)],
815 description
=> "NUMA allocation policy.",
819 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
822 type
=> 'string', format
=> $numa_fmt,
823 description
=> "NUMA topology.",
825 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
827 for (my $i = 0; $i < $MAX_NUMA; $i++) {
828 $confdesc->{"numa$i"} = $numadesc;
831 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
832 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
833 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
834 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
836 my $net_fmt_bridge_descr = <<__EOD__;
837 Bridge to attach the network device to. The Proxmox VE standard bridge
840 If you do not specify a bridge, we create a kvm user (NATed) network
841 device, which provides DHCP and DNS services. The following addresses
848 The DHCP server assign addresses to the guest starting from 10.0.2.15.
852 macaddr
=> get_standard_option
('mac-addr', {
853 description
=> "MAC address. That address must be unique withing your network. This is"
854 ." automatically generated if not specified.",
858 description
=> "Network Card Model. The 'virtio' model provides the best performance with"
859 ." very low CPU overhead. If your guest does not support this driver, it is usually"
860 ." best to use 'e1000'.",
861 enum
=> $nic_model_list,
864 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
867 description
=> $net_fmt_bridge_descr,
868 format_description
=> 'bridge',
869 pattern
=> '[-_.\w\d]+',
874 minimum
=> 0, maximum
=> 16,
875 description
=> 'Number of packet queues to be used on the device.',
881 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
886 minimum
=> 1, maximum
=> 4094,
887 description
=> 'VLAN tag to apply to packets on this interface.',
892 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
893 description
=> 'VLAN trunks to pass through this interface.',
894 format_description
=> 'vlanid[;vlanid...]',
899 description
=> 'Whether this interface should be protected by the firewall.',
904 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
909 minimum
=> 1, maximum
=> 65520,
910 description
=> "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
917 type
=> 'string', format
=> $net_fmt,
918 description
=> "Specify network devices.",
921 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
926 format
=> 'pve-ipv4-config',
927 format_description
=> 'IPv4Format/CIDR',
928 description
=> 'IPv4 address in CIDR format.',
935 format_description
=> 'GatewayIPv4',
936 description
=> 'Default gateway for IPv4 traffic.',
942 format
=> 'pve-ipv6-config',
943 format_description
=> 'IPv6Format/CIDR',
944 description
=> 'IPv6 address in CIDR format.',
951 format_description
=> 'GatewayIPv6',
952 description
=> 'Default gateway for IPv6 traffic.',
957 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
960 type
=> 'string', format
=> 'pve-qm-ipconfig',
961 description
=> <<'EODESCR',
962 cloud-init: Specify IP addresses and gateways for the corresponding interface.
964 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
966 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
967 gateway should be provided.
968 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
969 cloud-init 19.4 or newer.
971 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
975 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
977 for (my $i = 0; $i < $MAX_NETS; $i++) {
978 $confdesc->{"net$i"} = $netdesc;
979 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
982 foreach my $key (keys %$confdesc_cloudinit) {
983 $confdesc->{$key} = $confdesc_cloudinit->{$key};
986 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
987 sub verify_volume_id_or_qm_path
{
988 my ($volid, $noerr) = @_;
990 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
994 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
995 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
1006 type
=> 'string', format
=> 'pve-qm-usb-device',
1007 format_description
=> 'HOSTUSBDEVICE|spice',
1008 description
=> <<EODESCR,
1009 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1011 'bus-port(.port)*' (decimal numbers) or
1012 'vendor_id:product_id' (hexadeciaml numbers) or
1015 You can use the 'lsusb -t' command to list existing usb devices.
1017 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1018 machines - use with special care.
1020 The value 'spice' can be used to add a usb redirection devices for spice.
1026 description
=> "Specifies whether if given host option is a USB3 device or port.",
1033 type
=> 'string', format
=> $usb_fmt,
1034 description
=> "Configure an USB device (n is 0 to 4).",
1036 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1041 pattern
=> '(/dev/.+|socket)',
1042 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1043 verbose_description
=> <<EODESCR,
1044 Create a serial device inside the VM (n is 0 to 3), and pass through a
1045 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1046 host side (use 'qm terminal' to open a terminal connection).
1048 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1049 use with special care.
1051 CAUTION: Experimental! User reported problems with this option.
1058 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1059 description
=> "Map host parallel devices (n is 0 to 2).",
1060 verbose_description
=> <<EODESCR,
1061 Map host parallel devices (n is 0 to 2).
1063 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1064 machines - use with special care.
1066 CAUTION: Experimental! User reported problems with this option.
1070 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1071 $confdesc->{"parallel$i"} = $paralleldesc;
1074 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1075 $confdesc->{"serial$i"} = $serialdesc;
1078 for (my $i = 0; $i < $PVE::QemuServer
::PCI
::MAX_HOSTPCI_DEVICES
; $i++) {
1079 $confdesc->{"hostpci$i"} = $PVE::QemuServer
::PCI
::hostpcidesc
;
1082 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1083 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1086 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1087 $confdesc->{"usb$i"} = $usbdesc;
1095 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1096 . " Deprecated, use 'order=' instead.",
1097 pattern
=> '[acdn]{1,4}',
1098 format_description
=> "[acdn]{1,4}",
1100 # note: this is also the fallback if boot: is not given at all
1106 format
=> 'pve-qm-bootdev-list',
1107 format_description
=> "device[;device...]",
1108 description
=> <<EODESC,
1109 The guest will attempt to boot from devices in the order they appear here.
1111 Disks, optical drives and passed-through storage USB devices will be directly
1112 booted from, NICs will load PXE, and PCIe devices will either behave like disks
1113 (e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1115 Note that only devices in this list will be marked as bootable and thus loaded
1116 by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1117 (e.g. software-raid), you need to specify all of them here.
1119 Overrides the deprecated 'legacy=[acdn]*' value when given.
1123 PVE
::JSONSchema
::register_format
('pve-qm-boot', $boot_fmt);
1125 PVE
::JSONSchema
::register_format
('pve-qm-bootdev', \
&verify_bootdev
);
1126 sub verify_bootdev
{
1127 my ($dev, $noerr) = @_;
1129 return $dev if PVE
::QemuServer
::Drive
::is_valid_drivename
($dev) && $dev !~ m/^efidisk/;
1133 return 0 if $dev !~ m/^$base\d+$/;
1134 return 0 if !$confdesc->{$dev};
1138 return $dev if $check->("net");
1139 return $dev if $check->("usb");
1140 return $dev if $check->("hostpci");
1143 die "invalid boot device '$dev'\n";
1146 sub print_bootorder
{
1148 return "" if !@$devs;
1149 my $data = { order
=> join(';', @$devs) };
1150 return PVE
::JSONSchema
::print_property_string
($data, $boot_fmt);
1153 my $kvm_api_version = 0;
1156 return $kvm_api_version if $kvm_api_version;
1158 open my $fh, '<', '/dev/kvm' or return;
1160 # 0xae00 => KVM_GET_API_VERSION
1161 $kvm_api_version = ioctl($fh, 0xae00, 0);
1164 return $kvm_api_version;
1167 my $kvm_user_version = {};
1170 sub kvm_user_version
{
1173 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1174 my $st = stat($binary);
1176 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1177 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1178 $cachedmtime == $st->mtime;
1180 $kvm_user_version->{$binary} = 'unknown';
1181 $kvm_mtime->{$binary} = $st->mtime;
1185 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1186 $kvm_user_version->{$binary} = $2;
1190 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1193 return $kvm_user_version->{$binary};
1196 my sub extract_version
{
1197 my ($machine_type, $version) = @_;
1198 $version = kvm_user_version
() if !defined($version);
1199 PVE
::QemuServer
::Machine
::extract_version
($machine_type, $version)
1202 sub kernel_has_vhost_net
{
1203 return -c
'/dev/vhost-net';
1208 return defined($confdesc->{$key});
1212 sub get_cdrom_path
{
1214 return $cdrom_path if $cdrom_path;
1216 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1217 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1218 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1222 my ($storecfg, $vmid, $cdrom) = @_;
1224 if ($cdrom eq 'cdrom') {
1225 return get_cdrom_path
();
1226 } elsif ($cdrom eq 'none') {
1228 } elsif ($cdrom =~ m
|^/|) {
1231 return PVE
::Storage
::path
($storecfg, $cdrom);
1235 # try to convert old style file names to volume IDs
1236 sub filename_to_volume_id
{
1237 my ($vmid, $file, $media) = @_;
1239 if (!($file eq 'none' || $file eq 'cdrom' ||
1240 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1242 return if $file =~ m
|/|;
1244 if ($media && $media eq 'cdrom') {
1245 $file = "local:iso/$file";
1247 $file = "local:$vmid/$file";
1254 sub verify_media_type
{
1255 my ($opt, $vtype, $media) = @_;
1260 if ($media eq 'disk') {
1262 } elsif ($media eq 'cdrom') {
1265 die "internal error";
1268 return if ($vtype eq $etype);
1270 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1273 sub cleanup_drive_path
{
1274 my ($opt, $storecfg, $drive) = @_;
1276 # try to convert filesystem paths to volume IDs
1278 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1279 ($drive->{file
} !~ m
|^/dev/.+|) &&
1280 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1281 ($drive->{file
} !~ m/^\d+$/)) {
1282 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1283 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1285 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1286 verify_media_type
($opt, $vtype, $drive->{media
});
1287 $drive->{file
} = $volid;
1290 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1293 sub parse_hotplug_features
{
1298 return $res if $data eq '0';
1300 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1302 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1303 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1306 die "invalid hotplug feature '$feature'\n";
1312 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1313 sub pve_verify_hotplug_features
{
1314 my ($value, $noerr) = @_;
1316 return $value if parse_hotplug_features
($value);
1320 die "unable to parse hotplug option\n";
1324 my($fh, $noerr) = @_;
1327 my $SG_GET_VERSION_NUM = 0x2282;
1329 my $versionbuf = "\x00" x
8;
1330 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1332 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1335 my $version = unpack("I", $versionbuf);
1336 if ($version < 30000) {
1337 die "scsi generic interface too old\n" if !$noerr;
1341 my $buf = "\x00" x
36;
1342 my $sensebuf = "\x00" x
8;
1343 my $cmd = pack("C x3 C x1", 0x12, 36);
1345 # see /usr/include/scsi/sg.h
1346 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";
1348 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1349 length($sensebuf), 0, length($buf), $buf,
1350 $cmd, $sensebuf, 6000);
1352 $ret = ioctl($fh, $SG_IO, $packet);
1354 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1358 my @res = unpack($sg_io_hdr_t, $packet);
1359 if ($res[17] || $res[18]) {
1360 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1365 (my $byte0, my $byte1, $res->{vendor
},
1366 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1368 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1369 $res->{type
} = $byte0 & 31;
1377 my $fh = IO
::File-
>new("+<$path") || return;
1378 my $res = scsi_inquiry
($fh, 1);
1384 sub print_tabletdevice_full
{
1385 my ($conf, $arch) = @_;
1387 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1389 # we use uhci for old VMs because tablet driver was buggy in older qemu
1391 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1397 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1400 sub print_keyboarddevice_full
{
1401 my ($conf, $arch, $machine) = @_;
1403 return if $arch ne 'aarch64';
1405 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1408 my sub get_drive_id
{
1410 return "$drive->{interface}$drive->{index}";
1413 sub print_drivedevice_full
{
1414 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1419 my $drive_id = get_drive_id
($drive);
1420 if ($drive->{interface
} eq 'virtio') {
1421 my $pciaddr = print_pci_addr
("$drive_id", $bridges, $arch, $machine_type);
1422 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1423 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread
};
1424 } elsif ($drive->{interface
} eq 'scsi') {
1426 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1427 my $unit = $drive->{index} % $maxdev;
1428 my $devicetype = 'hd';
1430 if (drive_is_cdrom
($drive)) {
1433 if ($drive->{file
} =~ m
|^/|) {
1434 $path = $drive->{file
};
1435 if (my $info = path_is_scsi
($path)) {
1436 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1437 $devicetype = 'block';
1438 } elsif ($info->{type
} == 1) { # tape
1439 $devicetype = 'generic';
1443 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1446 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1447 my $version = extract_version
($machine_type, kvm_user_version
());
1448 if ($path =~ m/^iscsi\:\/\
// &&
1449 !min_version
($version, 4, 1)) {
1450 $devicetype = 'generic';
1454 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1455 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
1457 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1458 .",lun=$drive->{index}";
1460 $device .= ",drive=drive-$drive_id,id=$drive_id";
1462 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1463 $device .= ",rotation_rate=1";
1465 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1467 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1468 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1469 my $controller = int($drive->{index} / $maxdev);
1470 my $unit = $drive->{index} % $maxdev;
1471 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1473 $device = "ide-$devicetype";
1474 if ($drive->{interface
} eq 'ide') {
1475 $device .= ",bus=ide.$controller,unit=$unit";
1477 $device .= ",bus=ahci$controller.$unit";
1479 $device .= ",drive=drive-$drive_id,id=$drive_id";
1481 if ($devicetype eq 'hd') {
1482 if (my $model = $drive->{model
}) {
1483 $model = URI
::Escape
::uri_unescape
($model);
1484 $device .= ",model=$model";
1486 if ($drive->{ssd
}) {
1487 $device .= ",rotation_rate=1";
1490 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1491 } elsif ($drive->{interface
} eq 'usb') {
1493 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1495 die "unsupported interface type";
1498 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1500 if (my $serial = $drive->{serial
}) {
1501 $serial = URI
::Escape
::uri_unescape
($serial);
1502 $device .= ",serial=$serial";
1509 sub get_initiator_name
{
1512 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return;
1513 while (defined(my $line = <$fh>)) {
1514 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1523 sub print_drive_commandline_full
{
1524 my ($storecfg, $vmid, $drive, $pbs_name) = @_;
1527 my $volid = $drive->{file
};
1528 my $format = $drive->{format
};
1529 my $drive_id = get_drive_id
($drive);
1531 if (drive_is_cdrom
($drive)) {
1532 $path = get_iso_path
($storecfg, $vmid, $volid);
1533 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
1535 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1537 $path = PVE
::Storage
::path
($storecfg, $volid);
1538 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1539 $format //= qemu_img_format
($scfg, $volname);
1546 my $is_rbd = $path =~ m/^rbd:/;
1549 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1550 foreach my $o (@qemu_drive_options) {
1551 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1554 # snapshot only accepts on|off
1555 if (defined($drive->{snapshot
})) {
1556 my $v = $drive->{snapshot
} ?
'on' : 'off';
1557 $opts .= ",snapshot=$v";
1560 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1561 my ($dir, $qmpname) = @$type;
1562 if (my $v = $drive->{"mbps$dir"}) {
1563 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1565 if (my $v = $drive->{"mbps${dir}_max"}) {
1566 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1568 if (my $v = $drive->{"bps${dir}_max_length"}) {
1569 $opts .= ",throttling.bps$qmpname-max-length=$v";
1571 if (my $v = $drive->{"iops${dir}"}) {
1572 $opts .= ",throttling.iops$qmpname=$v";
1574 if (my $v = $drive->{"iops${dir}_max"}) {
1575 $opts .= ",throttling.iops$qmpname-max=$v";
1577 if (my $v = $drive->{"iops${dir}_max_length"}) {
1578 $opts .= ",throttling.iops$qmpname-max-length=$v";
1583 $format = "rbd" if $is_rbd;
1584 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1586 $opts .= ",format=alloc-track,file.driver=$format";
1588 $opts .= ",format=$format";
1591 my $cache_direct = 0;
1593 if (my $cache = $drive->{cache
}) {
1594 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1595 } elsif (!drive_is_cdrom
($drive)) {
1596 $opts .= ",cache=none";
1600 # aio native works only with O_DIRECT
1601 if (!$drive->{aio
}) {
1603 $opts .= ",aio=native";
1605 $opts .= ",aio=threads";
1609 if (!drive_is_cdrom
($drive)) {
1611 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1612 $detectzeroes = 'off';
1613 } elsif ($drive->{discard
}) {
1614 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1616 # This used to be our default with discard not being specified:
1617 $detectzeroes = 'on';
1620 # note: 'detect-zeroes' works per blockdev and we want it to persist
1621 # after the alloc-track is removed, so put it on 'file' directly
1622 my $dz_param = $pbs_name ?
"file.detect-zeroes" : "detect-zeroes";
1623 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
1627 $opts .= ",backing=$pbs_name";
1628 $opts .= ",auto-remove=on";
1631 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1632 my $file_param = "file";
1634 # non-rbd drivers require the underlying file to be a seperate block
1635 # node, so add a second .file indirection
1636 $file_param .= ".file" if !$is_rbd;
1637 $file_param .= ".filename";
1639 my $pathinfo = $path ?
"$file_param=$path," : '';
1641 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1644 sub print_pbs_blockdev
{
1645 my ($pbs_conf, $pbs_name) = @_;
1646 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1647 $blockdev .= ",repository=$pbs_conf->{repository}";
1648 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1649 $blockdev .= ",archive=$pbs_conf->{archive}";
1650 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile
};
1654 sub print_netdevice_full
{
1655 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1657 my $device = $net->{model
};
1658 if ($net->{model
} eq 'virtio') {
1659 $device = 'virtio-net-pci';
1662 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1663 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1664 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1665 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1666 # and out of each queue plus one config interrupt and control vector queue
1667 my $vectors = $net->{queues
} * 2 + 2;
1668 $tmpstr .= ",vectors=$vectors,mq=on";
1670 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1672 if (my $mtu = $net->{mtu
}) {
1673 if ($net->{model
} eq 'virtio' && $net->{bridge
}) {
1674 my $bridge_mtu = PVE
::Network
::read_bridge_mtu
($net->{bridge
});
1677 } elsif ($mtu < 576) {
1678 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1679 } elsif ($mtu > $bridge_mtu) {
1680 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1682 $tmpstr .= ",host_mtu=$mtu";
1684 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
1688 if ($use_old_bios_files) {
1690 if ($device eq 'virtio-net-pci') {
1691 $romfile = 'pxe-virtio.rom';
1692 } elsif ($device eq 'e1000') {
1693 $romfile = 'pxe-e1000.rom';
1694 } elsif ($device eq 'ne2k') {
1695 $romfile = 'pxe-ne2k_pci.rom';
1696 } elsif ($device eq 'pcnet') {
1697 $romfile = 'pxe-pcnet.rom';
1698 } elsif ($device eq 'rtl8139') {
1699 $romfile = 'pxe-rtl8139.rom';
1701 $tmpstr .= ",romfile=$romfile" if $romfile;
1707 sub print_netdev_full
{
1708 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1711 if ($netid =~ m/^net(\d+)$/) {
1715 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1717 my $ifname = "tap${vmid}i$i";
1719 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1720 die "interface name '$ifname' is too long (max 15 character)\n"
1721 if length($ifname) >= 16;
1723 my $vhostparam = '';
1724 if (is_native
($arch)) {
1725 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1728 my $vmname = $conf->{name
} || "vm$vmid";
1731 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1733 if ($net->{bridge
}) {
1734 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1735 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1737 $netdev = "type=user,id=$netid,hostname=$vmname";
1740 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1746 'cirrus' => 'cirrus-vga',
1748 'vmware' => 'vmware-svga',
1749 'virtio' => 'virtio-vga',
1752 sub print_vga_device
{
1753 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1755 my $type = $vga_map->{$vga->{type
}};
1756 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1757 $type = 'virtio-gpu';
1759 my $vgamem_mb = $vga->{memory
};
1761 my $max_outputs = '';
1763 $type = $id ?
'qxl' : 'qxl-vga';
1765 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1766 # set max outputs so linux can have up to 4 qxl displays with one device
1767 if (min_version
($machine_version, 4, 1)) {
1768 $max_outputs = ",max_outputs=4";
1773 die "no devicetype for $vga->{type}\n" if !$type;
1777 if ($vga->{type
} eq 'virtio') {
1778 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1779 $memory = ",max_hostmem=$bytes";
1781 # from https://www.spice-space.org/multiple-monitors.html
1782 $memory = ",vgamem_mb=$vga->{memory}";
1783 my $ram = $vgamem_mb * 4;
1784 my $vram = $vgamem_mb * 2;
1785 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1787 $memory = ",vgamem_mb=$vga->{memory}";
1789 } elsif ($qxlnum && $id) {
1790 $memory = ",ram_size=67108864,vram_size=33554432";
1794 if ($type eq 'VGA' && windows_version
($conf->{ostype
})) {
1795 $edidoff=",edid=off" if (!defined($conf->{bios
}) || $conf->{bios
} ne 'ovmf');
1798 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1799 my $vgaid = "vga" . ($id // '');
1802 if ($q35 && $vgaid eq 'vga') {
1803 # the first display uses pcie.0 bus on q35 machines
1804 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1806 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1809 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
1812 sub parse_number_sets
{
1815 foreach my $part (split(/;/, $set)) {
1816 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1817 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1818 push @$res, [ $1, $2 ];
1820 die "invalid range: $part\n";
1829 my $res = parse_property_string
($numa_fmt, $data);
1830 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1831 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1835 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1839 my $res = eval { parse_property_string
($net_fmt, $data) };
1844 if (!defined($res->{macaddr
})) {
1845 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1846 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1851 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1852 sub parse_ipconfig
{
1855 my $res = eval { parse_property_string
($ipconfig_fmt, $data) };
1861 if ($res->{gw
} && !$res->{ip
}) {
1862 warn 'gateway specified without specifying an IP address';
1865 if ($res->{gw6
} && !$res->{ip6
}) {
1866 warn 'IPv6 gateway specified without specifying an IPv6 address';
1869 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1870 warn 'gateway specified together with DHCP';
1873 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1875 warn "IPv6 gateway specified together with $res->{ip6} address";
1879 if (!$res->{ip
} && !$res->{ip6
}) {
1880 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1889 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1892 sub add_random_macs
{
1893 my ($settings) = @_;
1895 foreach my $opt (keys %$settings) {
1896 next if $opt !~ m/^net(\d+)$/;
1897 my $net = parse_net
($settings->{$opt});
1899 $settings->{$opt} = print_net
($net);
1903 sub vm_is_volid_owner
{
1904 my ($storecfg, $vmid, $volid) = @_;
1906 if ($volid !~ m
|^/|) {
1908 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1909 if ($owner && ($owner == $vmid)) {
1917 sub vmconfig_register_unused_drive
{
1918 my ($storecfg, $vmid, $conf, $drive) = @_;
1920 if (drive_is_cloudinit
($drive)) {
1921 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1923 } elsif (!drive_is_cdrom
($drive)) {
1924 my $volid = $drive->{file
};
1925 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1926 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1931 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1935 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1936 format_description
=> 'UUID',
1937 description
=> "Set SMBIOS1 UUID.",
1942 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1943 format_description
=> 'Base64 encoded string',
1944 description
=> "Set SMBIOS1 version.",
1949 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1950 format_description
=> 'Base64 encoded string',
1951 description
=> "Set SMBIOS1 serial number.",
1956 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1957 format_description
=> 'Base64 encoded string',
1958 description
=> "Set SMBIOS1 manufacturer.",
1963 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1964 format_description
=> 'Base64 encoded string',
1965 description
=> "Set SMBIOS1 product ID.",
1970 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1971 format_description
=> 'Base64 encoded string',
1972 description
=> "Set SMBIOS1 SKU string.",
1977 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1978 format_description
=> 'Base64 encoded string',
1979 description
=> "Set SMBIOS1 family string.",
1984 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
1992 my $res = eval { parse_property_string
($smbios1_fmt, $data) };
1999 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2002 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2004 sub parse_watchdog
{
2009 my $res = eval { parse_property_string
($watchdog_fmt, $value) };
2014 sub parse_guest_agent
{
2017 return {} if !defined($conf->{agent
});
2019 my $res = eval { parse_property_string
($agent_fmt, $conf->{agent
}) };
2022 # if the agent is disabled ignore the other potentially set properties
2023 return {} if !$res->{enabled
};
2028 my ($conf, $key) = @_;
2029 return undef if !defined($conf->{agent
});
2031 my $agent = parse_guest_agent
($conf);
2032 return $agent->{$key};
2038 return {} if !$value;
2039 my $res = eval { parse_property_string
($vga_fmt, $value) };
2049 my $res = eval { parse_property_string
($rng_fmt, $value) };
2054 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2055 sub verify_usb_device
{
2056 my ($value, $noerr) = @_;
2058 return $value if parse_usb_device
($value);
2062 die "unable to parse usb device\n";
2065 # add JSON properties for create and set function
2066 sub json_config_properties
{
2069 foreach my $opt (keys %$confdesc) {
2070 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' ||
2071 $opt eq 'runningmachine' || $opt eq 'runningcpu';
2072 $prop->{$opt} = $confdesc->{$opt};
2078 # return copy of $confdesc_cloudinit to generate documentation
2079 sub cloudinit_config_properties
{
2081 return dclone
($confdesc_cloudinit);
2085 my ($key, $value) = @_;
2087 die "unknown setting '$key'\n" if !$confdesc->{$key};
2089 my $type = $confdesc->{$key}->{type
};
2091 if (!defined($value)) {
2092 die "got undefined value\n";
2095 if ($value =~ m/[\n\r]/) {
2096 die "property contains a line feed\n";
2099 if ($type eq 'boolean') {
2100 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2101 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2102 die "type check ('boolean') failed - got '$value'\n";
2103 } elsif ($type eq 'integer') {
2104 return int($1) if $value =~ m/^(\d+)$/;
2105 die "type check ('integer') failed - got '$value'\n";
2106 } elsif ($type eq 'number') {
2107 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2108 die "type check ('number') failed - got '$value'\n";
2109 } elsif ($type eq 'string') {
2110 if (my $fmt = $confdesc->{$key}->{format
}) {
2111 PVE
::JSONSchema
::check_format
($fmt, $value);
2114 $value =~ s/^\"(.*)\"$/$1/;
2117 die "internal error"
2122 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
2124 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2126 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2128 if ($conf->{template
}) {
2129 # check if any base image is still used by a linked clone
2130 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2131 my ($ds, $drive) = @_;
2132 return if drive_is_cdrom
($drive);
2134 my $volid = $drive->{file
};
2135 return if !$volid || $volid =~ m
|^/|;
2137 die "base volume '$volid' is still in use by linked cloned\n"
2138 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2143 # only remove disks owned by this VM (referenced in the config)
2144 PVE
::QemuConfig-
>foreach_volume_full($conf, { include_unused
=> 1 }, sub {
2145 my ($ds, $drive) = @_;
2146 return if drive_is_cdrom
($drive, 1);
2148 my $volid = $drive->{file
};
2149 return if !$volid || $volid =~ m
|^/|;
2151 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2152 return if !$path || !$owner || ($owner != $vmid);
2154 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2155 warn "Could not remove disk '$volid', check manually: $@" if $@;
2158 if ($purge_unreferenced) { # also remove unreferenced disk
2159 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid, undef, 'images');
2160 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2161 my ($volid, $sid, $volname, $d) = @_;
2162 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2167 if (defined $replacement_conf) {
2168 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2170 PVE
::QemuConfig-
>destroy_config($vmid);
2174 sub parse_vm_config
{
2175 my ($filename, $raw) = @_;
2177 return if !defined($raw);
2180 digest
=> Digest
::SHA
::sha1_hex
($raw),
2185 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2186 || die "got strange filename '$filename'";
2194 my @lines = split(/\n/, $raw);
2195 foreach my $line (@lines) {
2196 next if $line =~ m/^\s*$/;
2198 if ($line =~ m/^\[PENDING\]\s*$/i) {
2199 $section = 'pending';
2200 if (defined($descr)) {
2202 $conf->{description
} = $descr;
2205 $conf = $res->{$section} = {};
2208 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2210 if (defined($descr)) {
2212 $conf->{description
} = $descr;
2215 $conf = $res->{snapshots
}->{$section} = {};
2219 if ($line =~ m/^\#(.*)\s*$/) {
2220 $descr = '' if !defined($descr);
2221 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2225 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2226 $descr = '' if !defined($descr);
2227 $descr .= PVE
::Tools
::decode_text
($2);
2228 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2229 $conf->{snapstate
} = $1;
2230 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2233 $conf->{$key} = $value;
2234 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2236 if ($section eq 'pending') {
2237 $conf->{delete} = $value; # we parse this later
2239 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2241 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2244 eval { $value = check_type
($key, $value); };
2246 warn "vm $vmid - unable to parse value of '$key' - $@";
2248 $key = 'ide2' if $key eq 'cdrom';
2249 my $fmt = $confdesc->{$key}->{format
};
2250 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2251 my $v = parse_drive
($key, $value);
2252 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2253 $v->{file
} = $volid;
2254 $value = print_drive
($v);
2256 warn "vm $vmid - unable to parse value of '$key'\n";
2261 $conf->{$key} = $value;
2264 warn "vm $vmid - unable to parse config: $line\n";
2268 if (defined($descr)) {
2270 $conf->{description
} = $descr;
2272 delete $res->{snapstate
}; # just to be sure
2277 sub write_vm_config
{
2278 my ($filename, $conf) = @_;
2280 delete $conf->{snapstate
}; # just to be sure
2282 if ($conf->{cdrom
}) {
2283 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2284 $conf->{ide2
} = $conf->{cdrom
};
2285 delete $conf->{cdrom
};
2288 # we do not use 'smp' any longer
2289 if ($conf->{sockets
}) {
2290 delete $conf->{smp
};
2291 } elsif ($conf->{smp
}) {
2292 $conf->{sockets
} = $conf->{smp
};
2293 delete $conf->{cores
};
2294 delete $conf->{smp
};
2297 my $used_volids = {};
2299 my $cleanup_config = sub {
2300 my ($cref, $pending, $snapname) = @_;
2302 foreach my $key (keys %$cref) {
2303 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2304 $key eq 'snapstate' || $key eq 'pending';
2305 my $value = $cref->{$key};
2306 if ($key eq 'delete') {
2307 die "propertry 'delete' is only allowed in [PENDING]\n"
2309 # fixme: check syntax?
2312 eval { $value = check_type
($key, $value); };
2313 die "unable to parse value of '$key' - $@" if $@;
2315 $cref->{$key} = $value;
2317 if (!$snapname && is_valid_drivename
($key)) {
2318 my $drive = parse_drive
($key, $value);
2319 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2324 &$cleanup_config($conf);
2326 &$cleanup_config($conf->{pending
}, 1);
2328 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2329 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2330 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2333 # remove 'unusedX' settings if we re-add a volume
2334 foreach my $key (keys %$conf) {
2335 my $value = $conf->{$key};
2336 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2337 delete $conf->{$key};
2341 my $generate_raw_config = sub {
2342 my ($conf, $pending) = @_;
2346 # add description as comment to top of file
2347 if (defined(my $descr = $conf->{description
})) {
2349 foreach my $cl (split(/\n/, $descr)) {
2350 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2353 $raw .= "#\n" if $pending;
2357 foreach my $key (sort keys %$conf) {
2358 next if $key =~ /^(digest|description|pending|snapshots)$/;
2359 $raw .= "$key: $conf->{$key}\n";
2364 my $raw = &$generate_raw_config($conf);
2366 if (scalar(keys %{$conf->{pending
}})){
2367 $raw .= "\n[PENDING]\n";
2368 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2371 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2372 $raw .= "\n[$snapname]\n";
2373 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2383 # we use static defaults from our JSON schema configuration
2384 foreach my $key (keys %$confdesc) {
2385 if (defined(my $default = $confdesc->{$key}->{default})) {
2386 $res->{$key} = $default;
2394 my $vmlist = PVE
::Cluster
::get_vmlist
();
2396 return $res if !$vmlist || !$vmlist->{ids
};
2397 my $ids = $vmlist->{ids
};
2398 my $nodename = nodename
();
2400 foreach my $vmid (keys %$ids) {
2401 my $d = $ids->{$vmid};
2402 next if !$d->{node
} || $d->{node
} ne $nodename;
2403 next if !$d->{type
} || $d->{type
} ne 'qemu';
2404 $res->{$vmid}->{exists} = 1;
2409 # test if VM uses local resources (to prevent migration)
2410 sub check_local_resources
{
2411 my ($conf, $noerr) = @_;
2415 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2416 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2418 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2420 foreach my $k (keys %$conf) {
2421 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2422 # sockets are safe: they will recreated be on the target side post-migrate
2423 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2424 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2427 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2432 # check if used storages are available on all nodes (use by migrate)
2433 sub check_storage_availability
{
2434 my ($storecfg, $conf, $node) = @_;
2436 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2437 my ($ds, $drive) = @_;
2439 my $volid = $drive->{file
};
2442 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2445 # check if storage is available on both nodes
2446 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2447 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2451 # list nodes where all VM images are available (used by has_feature API)
2453 my ($conf, $storecfg) = @_;
2455 my $nodelist = PVE
::Cluster
::get_nodelist
();
2456 my $nodehash = { map { $_ => 1 } @$nodelist };
2457 my $nodename = nodename
();
2459 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2460 my ($ds, $drive) = @_;
2462 my $volid = $drive->{file
};
2465 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2467 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2468 if ($scfg->{disable
}) {
2470 } elsif (my $avail = $scfg->{nodes
}) {
2471 foreach my $node (keys %$nodehash) {
2472 delete $nodehash->{$node} if !$avail->{$node};
2474 } elsif (!$scfg->{shared
}) {
2475 foreach my $node (keys %$nodehash) {
2476 delete $nodehash->{$node} if $node ne $nodename
2485 sub check_local_storage_availability
{
2486 my ($conf, $storecfg) = @_;
2488 my $nodelist = PVE
::Cluster
::get_nodelist
();
2489 my $nodehash = { map { $_ => {} } @$nodelist };
2491 PVE
::QemuConfig-
>foreach_volume($conf, sub {
2492 my ($ds, $drive) = @_;
2494 my $volid = $drive->{file
};
2497 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2499 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2501 if ($scfg->{disable
}) {
2502 foreach my $node (keys %$nodehash) {
2503 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2505 } elsif (my $avail = $scfg->{nodes
}) {
2506 foreach my $node (keys %$nodehash) {
2507 if (!$avail->{$node}) {
2508 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2515 foreach my $node (values %$nodehash) {
2516 if (my $unavail = $node->{unavailable_storages
}) {
2517 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2524 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2526 my ($vmid, $nocheck, $node) = @_;
2528 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2529 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2534 my $vzlist = config_list
();
2536 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2538 while (defined(my $de = $fd->read)) {
2539 next if $de !~ m/^(\d+)\.pid$/;
2541 next if !defined($vzlist->{$vmid});
2542 if (my $pid = check_running
($vmid)) {
2543 $vzlist->{$vmid}->{pid
} = $pid;
2550 our $vmstatus_return_properties = {
2551 vmid
=> get_standard_option
('pve-vmid'),
2553 description
=> "Qemu process status.",
2555 enum
=> ['stopped', 'running'],
2558 description
=> "Maximum memory in bytes.",
2561 renderer
=> 'bytes',
2564 description
=> "Root disk size in bytes.",
2567 renderer
=> 'bytes',
2570 description
=> "VM name.",
2575 description
=> "Qemu QMP agent status.",
2580 description
=> "PID of running qemu process.",
2585 description
=> "Uptime.",
2588 renderer
=> 'duration',
2591 description
=> "Maximum usable CPUs.",
2596 description
=> "The current config lock, if any.",
2601 description
=> "The current configured tags, if any",
2605 'running-machine' => {
2606 description
=> "The currently running machine type (if running).",
2611 description
=> "The currently running QEMU version (if running).",
2617 my $last_proc_pid_stat;
2619 # get VM status information
2620 # This must be fast and should not block ($full == false)
2621 # We only query KVM using QMP if $full == true (this can be slow)
2623 my ($opt_vmid, $full) = @_;
2627 my $storecfg = PVE
::Storage
::config
();
2629 my $list = vzlist
();
2630 my $defaults = load_defaults
();
2632 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2634 my $cpucount = $cpuinfo->{cpus
} || 1;
2636 foreach my $vmid (keys %$list) {
2637 next if $opt_vmid && ($vmid ne $opt_vmid);
2639 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2641 my $d = { vmid
=> $vmid };
2642 $d->{pid
} = $list->{$vmid}->{pid
};
2644 # fixme: better status?
2645 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2647 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2648 if (defined($size)) {
2649 $d->{disk
} = 0; # no info available
2650 $d->{maxdisk
} = $size;
2656 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2657 * ($conf->{cores
} || $defaults->{cores
});
2658 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2659 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2661 $d->{name
} = $conf->{name
} || "VM $vmid";
2662 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2663 : $defaults->{memory
}*(1024*1024);
2665 if ($conf->{balloon
}) {
2666 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2667 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2668 : $defaults->{shares
};
2679 $d->{diskwrite
} = 0;
2681 $d->{template
} = 1 if PVE
::QemuConfig-
>is_template($conf);
2683 $d->{serial
} = 1 if conf_has_serial
($conf);
2684 $d->{lock} = $conf->{lock} if $conf->{lock};
2685 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2690 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2691 foreach my $dev (keys %$netdev) {
2692 next if $dev !~ m/^tap([1-9]\d*)i/;
2694 my $d = $res->{$vmid};
2697 $d->{netout
} += $netdev->{$dev}->{receive
};
2698 $d->{netin
} += $netdev->{$dev}->{transmit
};
2701 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2702 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2707 my $ctime = gettimeofday
;
2709 foreach my $vmid (keys %$list) {
2711 my $d = $res->{$vmid};
2712 my $pid = $d->{pid
};
2715 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2716 next if !$pstat; # not running
2718 my $used = $pstat->{utime} + $pstat->{stime
};
2720 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2722 if ($pstat->{vsize
}) {
2723 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2726 my $old = $last_proc_pid_stat->{$pid};
2728 $last_proc_pid_stat->{$pid} = {
2736 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2738 if ($dtime > 1000) {
2739 my $dutime = $used - $old->{used
};
2741 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2742 $last_proc_pid_stat->{$pid} = {
2748 $d->{cpu
} = $old->{cpu
};
2752 return $res if !$full;
2754 my $qmpclient = PVE
::QMPClient-
>new();
2756 my $ballooncb = sub {
2757 my ($vmid, $resp) = @_;
2759 my $info = $resp->{'return'};
2760 return if !$info->{max_mem
};
2762 my $d = $res->{$vmid};
2764 # use memory assigned to VM
2765 $d->{maxmem
} = $info->{max_mem
};
2766 $d->{balloon
} = $info->{actual
};
2768 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2769 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2770 $d->{freemem
} = $info->{free_mem
};
2773 $d->{ballooninfo
} = $info;
2776 my $blockstatscb = sub {
2777 my ($vmid, $resp) = @_;
2778 my $data = $resp->{'return'} || [];
2779 my $totalrdbytes = 0;
2780 my $totalwrbytes = 0;
2782 for my $blockstat (@$data) {
2783 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2784 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2786 $blockstat->{device
} =~ s/drive-//;
2787 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2789 $res->{$vmid}->{diskread
} = $totalrdbytes;
2790 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2793 my $machinecb = sub {
2794 my ($vmid, $resp) = @_;
2795 my $data = $resp->{'return'} || [];
2797 $res->{$vmid}->{'running-machine'} =
2798 PVE
::QemuServer
::Machine
::current_from_query_machines
($data);
2801 my $versioncb = sub {
2802 my ($vmid, $resp) = @_;
2803 my $data = $resp->{'return'} // {};
2804 my $version = 'unknown';
2806 if (my $v = $data->{qemu
}) {
2807 $version = $v->{major
} . "." . $v->{minor
} . "." . $v->{micro
};
2810 $res->{$vmid}->{'running-qemu'} = $version;
2813 my $statuscb = sub {
2814 my ($vmid, $resp) = @_;
2816 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2817 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
2818 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
2819 # this fails if ballon driver is not loaded, so this must be
2820 # the last commnand (following command are aborted if this fails).
2821 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2823 my $status = 'unknown';
2824 if (!defined($status = $resp->{'return'}->{status
})) {
2825 warn "unable to get VM status\n";
2829 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2832 foreach my $vmid (keys %$list) {
2833 next if $opt_vmid && ($vmid ne $opt_vmid);
2834 next if !$res->{$vmid}->{pid
}; # not running
2835 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2838 $qmpclient->queue_execute(undef, 2);
2840 foreach my $vmid (keys %$list) {
2841 next if $opt_vmid && ($vmid ne $opt_vmid);
2842 next if !$res->{$vmid}->{pid
}; #not running
2844 # we can't use the $qmpclient since it might have already aborted on
2845 # 'query-balloon', but this might also fail for older versions...
2846 my $qemu_support = eval { mon_cmd
($vmid, "query-proxmox-support") };
2847 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
2850 foreach my $vmid (keys %$list) {
2851 next if $opt_vmid && ($vmid ne $opt_vmid);
2852 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2858 sub conf_has_serial
{
2861 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2862 if ($conf->{"serial$i"}) {
2870 sub conf_has_audio
{
2871 my ($conf, $id) = @_;
2874 my $audio = $conf->{"audio$id"};
2875 return if !defined($audio);
2877 my $audioproperties = parse_property_string
($audio_fmt, $audio);
2878 my $audiodriver = $audioproperties->{driver
} // 'spice';
2881 dev
=> $audioproperties->{device
},
2882 dev_id
=> "audiodev$id",
2883 backend
=> $audiodriver,
2884 backend_id
=> "$audiodriver-backend${id}",
2889 my ($audio, $audiopciaddr, $machine_version) = @_;
2893 my $id = $audio->{dev_id
};
2895 if (min_version
($machine_version, 4, 2)) {
2896 $audiodev = ",audiodev=$audio->{backend_id}";
2899 if ($audio->{dev
} eq 'AC97') {
2900 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
2901 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
2902 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
2903 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
2904 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
2906 die "unkown audio device '$audio->{dev}', implement me!";
2909 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2914 sub vga_conf_has_spice
{
2917 my $vgaconf = parse_vga
($vga);
2918 my $vgatype = $vgaconf->{type
};
2919 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
2926 return get_host_arch
() eq $arch;
2931 return $conf->{arch
} // get_host_arch
();
2934 my $default_machines = {
2939 sub get_installed_machine_version
{
2940 my ($kvmversion) = @_;
2941 $kvmversion = kvm_user_version
() if !defined($kvmversion);
2942 $kvmversion =~ m/^(\d+\.\d+)/;
2946 sub windows_get_pinned_machine_version
{
2947 my ($machine, $base_version, $kvmversion) = @_;
2949 my $pin_version = $base_version;
2950 if (!defined($base_version) ||
2951 !PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($base_version, $kvmversion)
2953 $pin_version = get_installed_machine_version
($kvmversion);
2955 if (!$machine || $machine eq 'pc') {
2956 $machine = "pc-i440fx-$pin_version";
2957 } elsif ($machine eq 'q35') {
2958 $machine = "pc-q35-$pin_version";
2959 } elsif ($machine eq 'virt') {
2960 $machine = "virt-$pin_version";
2962 warn "unknown machine type '$machine', not touching that!\n";
2968 sub get_vm_machine
{
2969 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
2971 my $machine = $forcemachine || $conf->{machine
};
2973 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
2974 $kvmversion //= kvm_user_version
();
2975 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
2976 # layout which confuses windows quite a bit and may result in various regressions..
2977 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
2978 if (windows_version
($conf->{ostype
})) {
2979 $machine = windows_get_pinned_machine_version
($machine, '5.1', $kvmversion);
2982 $machine ||= $default_machines->{$arch};
2983 if ($add_pve_version) {
2984 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
2985 $machine .= "+pve$pvever";
2989 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
2990 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
2991 $machine = $1 if $is_pxe;
2993 # for version-pinned machines that do not include a pve-version (e.g.
2994 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
2995 $machine .= '+pve0';
2997 $machine .= '.pxe' if $is_pxe;
3003 sub get_ovmf_files
($) {
3006 my $ovmf = $OVMF->{$arch}
3007 or die "no OVMF images known for architecture '$arch'\n";
3013 aarch64
=> '/usr/bin/qemu-system-aarch64',
3014 x86_64
=> '/usr/bin/qemu-system-x86_64',
3016 sub get_command_for_arch
($) {
3018 return '/usr/bin/kvm' if is_native
($arch);
3020 my $cmd = $Arch2Qemu->{$arch}
3021 or die "don't know how to emulate architecture '$arch'\n";
3025 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3026 # to use in a QEMU command line (-cpu element), first array_intersect the result
3027 # of query_supported_ with query_understood_. This is necessary because:
3029 # a) query_understood_ returns flags the host cannot use and
3030 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
3031 # flags, but CPU settings - with most of them being flags. Those settings
3032 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
3034 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3035 # expensive. If you need the value returned from this, you can get it much
3036 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3037 # $accel being 'kvm' or 'tcg'.
3039 # pvestatd calls this function on startup and whenever the QEMU/KVM version
3040 # changes, automatically populating pmxcfs.
3042 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3043 # since kvm and tcg machines support different flags
3045 sub query_supported_cpu_flags
{
3048 $arch //= get_host_arch
();
3049 my $default_machine = $default_machines->{$arch};
3053 # FIXME: Once this is merged, the code below should work for ARM as well:
3054 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3055 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3058 my $kvm_supported = defined(kvm_version
());
3059 my $qemu_cmd = get_command_for_arch
($arch);
3061 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
3063 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3064 my $query_supported_run_qemu = sub {
3070 '-machine', $default_machine,
3072 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
3073 '-mon', 'chardev=qmp,mode=control',
3074 '-pidfile', $pidfile,
3079 push @$cmd, '-accel', 'tcg';
3082 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
3083 die "QEMU flag querying VM exited with code " . $rc if $rc;
3086 my $cmd_result = mon_cmd
(
3088 'query-cpu-model-expansion',
3090 model
=> { name
=> 'host' }
3093 my $props = $cmd_result->{model
}->{props
};
3094 foreach my $prop (keys %$props) {
3095 next if $props->{$prop} ne '1';
3096 # QEMU returns some flags multiple times, with '_', '.' or '-'
3097 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3098 # We only keep those with underscores, to match /proc/cpuinfo
3099 $prop =~ s/\.|-/_/g;
3100 $flags->{$prop} = 1;
3105 # force stop with 10 sec timeout and 'nocheck'
3106 # always stop, even if QMP failed
3107 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
3111 return [ sort keys %$flags ];
3114 # We need to query QEMU twice, since KVM and TCG have different supported flags
3115 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
3116 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
3117 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3119 if ($kvm_supported) {
3120 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
3121 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3128 # Understood CPU flags are written to a file at 'pve-qemu' compile time
3129 my $understood_cpu_flag_dir = "/usr/share/kvm";
3130 sub query_understood_cpu_flags
{
3131 my $arch = get_host_arch
();
3132 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3134 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3137 my $raw = file_get_contents
($filepath);
3138 $raw =~ s/^\s+|\s+$//g;
3139 my @flags = split(/\s+/, $raw);
3144 sub config_to_command
{
3145 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3149 my $globalFlags = [];
3150 my $machineFlags = [];
3155 my $ostype = $conf->{ostype
};
3156 my $winversion = windows_version
($ostype);
3157 my $kvm = $conf->{kvm
};
3158 my $nodename = nodename
();
3160 my $arch = get_vm_arch
($conf);
3161 my $kvm_binary = get_command_for_arch
($arch);
3162 my $kvmver = kvm_user_version
($kvm_binary);
3164 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3165 $kvmver //= "undefined";
3166 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3169 my $add_pve_version = min_version
($kvmver, 4, 1);
3171 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
3172 my $machine_version = extract_version
($machine_type, $kvmver);
3173 $kvm //= 1 if is_native
($arch);
3175 $machine_version =~ m/(\d+)\.(\d+)/;
3176 my ($machine_major, $machine_minor) = ($1, $2);
3178 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3179 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3180 } elsif (!min_version
($kvmver, $machine_major, $machine_minor)) {
3181 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3182 ." please upgrade node '$nodename'\n"
3183 } elsif (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
3184 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
3185 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3186 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3187 ." node '$nodename'\n";
3190 # if a specific +pve version is required for a feature, use $version_guard
3191 # instead of min_version to allow machines to be run with the minimum
3193 my $required_pve_version = 0;
3194 my $version_guard = sub {
3195 my ($major, $minor, $pve) = @_;
3196 return 0 if !min_version
($machine_version, $major, $minor, $pve);
3197 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
3198 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
3199 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3203 if ($kvm && !defined kvm_version
()) {
3204 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3205 ." or enable in BIOS.\n";
3208 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3209 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3210 my $use_old_bios_files = undef;
3211 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3213 my $cpuunits = defined($conf->{cpuunits
}) ?
3214 $conf->{cpuunits
} : $defaults->{cpuunits
};
3216 push @$cmd, $kvm_binary;
3218 push @$cmd, '-id', $vmid;
3220 my $vmname = $conf->{name
} || "vm$vmid";
3222 push @$cmd, '-name', $vmname;
3224 push @$cmd, '-no-shutdown';
3228 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
3229 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
3230 push @$cmd, '-mon', "chardev=qmp,mode=control";
3232 if (min_version
($machine_version, 2, 12)) {
3233 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3234 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3237 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3239 push @$cmd, '-daemonize';
3241 if ($conf->{smbios1
}) {
3242 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3243 if ($smbios_conf->{base64
}) {
3244 # Do not pass base64 flag to qemu
3245 delete $smbios_conf->{base64
};
3246 my $smbios_string = "";
3247 foreach my $key (keys %$smbios_conf) {
3249 if ($key eq "uuid") {
3250 $value = $smbios_conf->{uuid
}
3252 $value = decode_base64
($smbios_conf->{$key});
3254 # qemu accepts any binary data, only commas need escaping by double comma
3256 $smbios_string .= "," . $key . "=" . $value if $value;
3258 push @$cmd, '-smbios', "type=1" . $smbios_string;
3260 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3264 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3265 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3266 die "uefi base image '$ovmf_code' not found\n" if ! -f
$ovmf_code;
3268 my ($path, $format);
3269 if (my $efidisk = $conf->{efidisk0
}) {
3270 my $d = parse_drive
('efidisk0', $efidisk);
3271 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3272 $format = $d->{format
};
3274 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3275 if (!defined($format)) {
3276 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3277 $format = qemu_img_format
($scfg, $volname);
3281 die "efidisk format must be specified\n"
3282 if !defined($format);
3285 warn "no efidisk configured! Using temporary efivars disk.\n";
3286 $path = "/tmp/$vmid-ovmf.fd";
3287 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3293 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3294 $size_str = ",size=" . (-s
$ovmf_vars);
3297 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
3298 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0$size_str,file=$path";
3303 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3304 if (min_version
($machine_version, 4, 0)) {
3305 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3307 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3311 if ($conf->{vmgenid
}) {
3312 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3315 # add usb controllers
3316 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
(
3317 $conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3318 push @$devices, @usbcontrollers if @usbcontrollers;
3319 my $vga = parse_vga
($conf->{vga
});
3321 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3322 $vga->{type
} = 'qxl' if $qxlnum;
3324 if (!$vga->{type
}) {
3325 if ($arch eq 'aarch64') {
3326 $vga->{type
} = 'virtio';
3327 } elsif (min_version
($machine_version, 2, 9)) {
3328 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3330 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3334 # enable absolute mouse coordinates (needed by vnc)
3336 if (defined($conf->{tablet
})) {
3337 $tablet = $conf->{tablet
};
3339 $tablet = $defaults->{tablet
};
3340 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3341 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3345 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3346 my $kbd = print_keyboarddevice_full
($conf, $arch);
3347 push @$devices, '-device', $kbd if defined($kbd);
3350 my $bootorder = device_bootorder
($conf);
3352 # host pci device passthrough
3353 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE
::QemuServer
::PCI
::print_hostpci_devices
(
3354 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
3357 my $usb_dev_features = {};
3358 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3360 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
(
3361 $conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
3362 push @$devices, @usbdevices if @usbdevices;
3365 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3366 if (my $path = $conf->{"serial$i"}) {
3367 if ($path eq 'socket') {
3368 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3369 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3370 # On aarch64, serial0 is the UART device. Qemu only allows
3371 # connecting UART devices via the '-serial' command line, as
3372 # the device has a fixed slot on the hardware...
3373 if ($arch eq 'aarch64' && $i == 0) {
3374 push @$devices, '-serial', "chardev:serial$i";
3376 push @$devices, '-device', "isa-serial,chardev=serial$i";
3379 die "no such serial device\n" if ! -c
$path;
3380 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3381 push @$devices, '-device', "isa-serial,chardev=serial$i";
3387 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3388 if (my $path = $conf->{"parallel$i"}) {
3389 die "no such parallel device\n" if ! -c
$path;
3390 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3391 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3392 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3396 if (min_version
($machine_version, 4, 0) && (my $audio = conf_has_audio
($conf))) {
3397 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3398 my $audio_devs = audio_devs
($audio, $audiopciaddr, $machine_version);
3399 push @$devices, @$audio_devs;
3403 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3404 $sockets = $conf->{sockets
} if $conf->{sockets
};
3406 my $cores = $conf->{cores
} || 1;
3408 my $maxcpus = $sockets * $cores;
3410 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3412 my $allowed_vcpus = $cpuinfo->{cpus
};
3414 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3415 if ($allowed_vcpus < $maxcpus);
3417 if($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3419 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3420 for (my $i = 2; $i <= $vcpus; $i++) {
3421 my $cpustr = print_cpu_device
($conf,$i);
3422 push @$cmd, '-device', $cpustr;
3427 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3429 push @$cmd, '-nodefaults';
3431 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3433 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3435 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3437 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3438 push @$devices, '-device', print_vga_device
(
3439 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3440 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3441 push @$cmd, '-vnc', "unix:$socket,password=on";
3443 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3444 push @$cmd, '-nographic';
3448 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3449 my $useLocaltime = $conf->{localtime};
3451 if ($winversion >= 5) { # windows
3452 $useLocaltime = 1 if !defined($conf->{localtime});
3454 # use time drift fix when acpi is enabled
3455 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3456 $tdf = 1 if !defined($conf->{tdf
});
3460 if ($winversion >= 6) {
3461 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3462 push @$cmd, '-no-hpet';
3465 push @$rtcFlags, 'driftfix=slew' if $tdf;
3467 if ($conf->{startdate
} && $conf->{startdate
} ne 'now') {
3468 push @$rtcFlags, "base=$conf->{startdate}";
3469 } elsif ($useLocaltime) {
3470 push @$rtcFlags, 'base=localtime';
3474 push @$cmd, '-cpu', $forcecpu;
3476 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3479 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3481 push @$cmd, '-S' if $conf->{freeze
};
3483 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3485 my $guest_agent = parse_guest_agent
($conf);
3487 if ($guest_agent->{enabled
}) {
3488 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3489 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
3491 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3492 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3493 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3494 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3495 } elsif ($guest_agent->{type
} eq 'isa') {
3496 push @$devices, '-device', "isa-serial,chardev=qga0";
3500 my $rng = $conf->{rng0
} ? parse_rng
($conf->{rng0
}) : undef;
3501 if ($rng && $version_guard->(4, 1, 2)) {
3502 check_rng_source
($rng->{source
});
3504 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3505 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3506 my $limiter_str = "";
3508 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3511 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3512 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3513 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3521 for (my $i = 1; $i < $qxlnum; $i++){
3522 push @$devices, '-device', print_vga_device
(
3523 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3526 # assume other OS works like Linux
3527 my ($ram, $vram) = ("134217728", "67108864");
3528 if ($vga->{memory
}) {
3529 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3530 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3532 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3533 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3537 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3539 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3540 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3541 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3543 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3544 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3545 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3547 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3548 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3550 my $spice_enhancement_str = $conf->{spice_enhancements
} // '';
3551 my $spice_enhancement = parse_property_string
($spice_enhancements_fmt, $spice_enhancement_str);
3552 if ($spice_enhancement->{foldersharing
}) {
3553 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3554 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3557 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3558 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3559 if $spice_enhancement->{videostreaming
};
3561 push @$devices, '-spice', "$spice_opts";
3564 # enable balloon by default, unless explicitly disabled
3565 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3566 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3567 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3570 if ($conf->{watchdog
}) {
3571 my $wdopts = parse_watchdog
($conf->{watchdog
});
3572 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3573 my $watchdog = $wdopts->{model
} || 'i6300esb';
3574 push @$devices, '-device', "$watchdog$pciaddr";
3575 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3579 my $scsicontroller = {};
3580 my $ahcicontroller = {};
3581 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3583 # Add iscsi initiator name if available
3584 if (my $initiator = get_initiator_name
()) {
3585 push @$devices, '-iscsi', "initiator-name=$initiator";
3588 PVE
::QemuConfig-
>foreach_volume($conf, sub {
3589 my ($ds, $drive) = @_;
3591 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3592 push @$vollist, $drive->{file
};
3595 # ignore efidisk here, already added in bios/fw handling code above
3596 return if $drive->{interface
} eq 'efidisk';
3598 $use_virtio = 1 if $ds =~ m/^virtio/;
3600 $drive->{bootindex
} = $bootorder->{$ds} if $bootorder->{$ds};
3602 if ($drive->{interface
} eq 'virtio'){
3603 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3606 if ($drive->{interface
} eq 'scsi') {
3608 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3610 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3611 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3613 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3614 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3617 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3618 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3619 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3620 } elsif ($drive->{iothread
}) {
3621 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3625 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3626 $queues = ",num_queues=$drive->{queues}";
3629 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
3630 if !$scsicontroller->{$controller};
3631 $scsicontroller->{$controller}=1;
3634 if ($drive->{interface
} eq 'sata') {
3635 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3636 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3637 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
3638 if !$ahcicontroller->{$controller};
3639 $ahcicontroller->{$controller}=1;
3642 my $pbs_conf = $pbs_backing->{$ds};
3643 my $pbs_name = undef;
3645 $pbs_name = "drive-$ds-pbs";
3646 push @$devices, '-blockdev', print_pbs_blockdev
($pbs_conf, $pbs_name);
3649 my $drive_cmd = print_drive_commandline_full
($storecfg, $vmid, $drive, $pbs_name);
3651 # extra protection for templates, but SATA and IDE don't support it..
3652 my $read_only = PVE
::QemuConfig-
>is_template($conf)
3653 && $drive->{interface
} ne 'sata'
3654 && $drive->{interface
} ne 'ide';
3656 $drive_cmd .= ',readonly=on' if $read_only;
3658 push @$devices, '-drive',$drive_cmd;
3659 push @$devices, '-device', print_drivedevice_full
(
3660 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3663 for (my $i = 0; $i < $MAX_NETS; $i++) {
3664 my $netname = "net$i";
3666 next if !$conf->{$netname};
3667 my $d = parse_net
($conf->{$netname});
3670 $use_virtio = 1 if $d->{model
} eq 'virtio';
3672 $d->{bootindex
} = $bootorder->{$netname} if $bootorder->{$netname};
3674 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, $netname);
3675 push @$devices, '-netdev', $netdevfull;
3677 my $netdevicefull = print_netdevice_full
(
3678 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
3680 push @$devices, '-device', $netdevicefull;
3683 if ($conf->{ivshmem
}) {
3684 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3688 $bus = print_pcie_addr
("ivshmem");
3690 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3693 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3694 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3696 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3697 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
3698 .",size=$ivshmem->{size}M";
3701 # pci.4 is nested in pci.1
3702 $bridges->{1} = 1 if $bridges->{4};
3706 if (min_version
($machine_version, 2, 3)) {
3711 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3715 for my $k (sort {$b cmp $a} keys %$bridges) {
3716 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3719 if ($k == 2 && $legacy_igd) {
3722 $pciaddr = print_pci_addr
("pci.$k_name", undef, $arch, $machine_type);
3724 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3726 # add after -readconfig pve-q35.cfg
3727 splice @$devices, 2, 0, '-device', $devstr;
3729 unshift @$devices, '-device', $devstr if $k > 0;
3734 push @$machineFlags, 'accel=tcg';
3737 my $machine_type_min = $machine_type;
3738 if ($add_pve_version) {
3739 $machine_type_min =~ s/\+pve\d+$//;
3740 $machine_type_min .= "+pve$required_pve_version";
3742 push @$machineFlags, "type=${machine_type_min}";
3744 push @$cmd, @$devices;
3745 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
3746 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
3747 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
3749 if (my $vmstate = $conf->{vmstate
}) {
3750 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3751 push @$vollist, $vmstate;
3752 push @$cmd, '-loadstate', $statepath;
3753 print "activating and using '$vmstate' as vmstate\n";
3757 if ($conf->{args
}) {
3758 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3762 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3765 sub check_rng_source
{
3768 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3769 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
3772 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
3773 if ($source eq '/dev/hwrng' && file_read_firstline
($rng_current) eq 'none') {
3774 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
3775 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
3776 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
3777 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
3785 my $res = mon_cmd
($vmid, 'query-spice');
3787 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3790 sub vm_devices_list
{
3793 my $res = mon_cmd
($vmid, 'query-pci');
3794 my $devices_to_check = [];
3796 foreach my $pcibus (@$res) {
3797 push @$devices_to_check, @{$pcibus->{devices
}},
3800 while (@$devices_to_check) {
3802 for my $d (@$devices_to_check) {
3803 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3804 next if !$d->{'pci_bridge'};
3806 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3807 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3809 $devices_to_check = $to_check;
3812 my $resblock = mon_cmd
($vmid, 'query-block');
3813 foreach my $block (@$resblock) {
3814 if($block->{device
} =~ m/^drive-(\S+)/){
3819 my $resmice = mon_cmd
($vmid, 'query-mice');
3820 foreach my $mice (@$resmice) {
3821 if ($mice->{name
} eq 'QEMU HID Tablet') {
3822 $devices->{tablet
} = 1;
3827 # for usb devices there is no query-usb
3828 # but we can iterate over the entries in
3829 # qom-list path=/machine/peripheral
3830 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3831 foreach my $per (@$resperipheral) {
3832 if ($per->{name
} =~ m/^usb\d+$/) {
3833 $devices->{$per->{name
}} = 1;
3841 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3843 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3845 my $devices_list = vm_devices_list
($vmid);
3846 return 1 if defined($devices_list->{$deviceid});
3848 # add PCI bridge if we need it for the device
3849 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
3851 if ($deviceid eq 'tablet') {
3853 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3855 } elsif ($deviceid eq 'keyboard') {
3857 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3859 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3861 die "usb hotplug currently not reliable\n";
3862 # since we can't reliably hot unplug all added usb devices and usb
3863 # passthrough breaks live migration we disable usb hotplugging for now
3864 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
3866 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3868 qemu_iothread_add
($vmid, $deviceid, $device);
3870 qemu_driveadd
($storecfg, $vmid, $device);
3871 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
3873 qemu_deviceadd
($vmid, $devicefull);
3874 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3876 eval { qemu_drivedel
($vmid, $deviceid); };
3881 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3884 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3885 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3886 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3888 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3890 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3891 qemu_iothread_add
($vmid, $deviceid, $device);
3892 $devicefull .= ",iothread=iothread-$deviceid";
3895 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3896 $devicefull .= ",num_queues=$device->{queues}";
3899 qemu_deviceadd
($vmid, $devicefull);
3900 qemu_deviceaddverify
($vmid, $deviceid);
3902 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3904 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
3905 qemu_driveadd
($storecfg, $vmid, $device);
3907 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
3908 eval { qemu_deviceadd
($vmid, $devicefull); };
3910 eval { qemu_drivedel
($vmid, $deviceid); };
3915 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3917 return if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
3919 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
3920 my $use_old_bios_files = undef;
3921 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3923 my $netdevicefull = print_netdevice_full
(
3924 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3925 qemu_deviceadd
($vmid, $netdevicefull);
3927 qemu_deviceaddverify
($vmid, $deviceid);
3928 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
3931 eval { qemu_netdevdel
($vmid, $deviceid); };
3936 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3939 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3940 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3942 qemu_deviceadd
($vmid, $devicefull);
3943 qemu_deviceaddverify
($vmid, $deviceid);
3946 die "can't hotplug device '$deviceid'\n";
3952 # fixme: this should raise exceptions on error!
3953 sub vm_deviceunplug
{
3954 my ($vmid, $conf, $deviceid) = @_;
3956 my $devices_list = vm_devices_list
($vmid);
3957 return 1 if !defined($devices_list->{$deviceid});
3959 my $bootdisks = PVE
::QemuServer
::Drive
::get_bootdisks
($conf);
3960 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
3962 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3964 qemu_devicedel
($vmid, $deviceid);
3966 } elsif ($deviceid =~ m/^usb\d+$/) {
3968 die "usb hotplug currently not reliable\n";
3969 # when unplugging usb devices this way, there may be remaining usb
3970 # controllers/hubs so we disable it for now
3971 #qemu_devicedel($vmid, $deviceid);
3972 #qemu_devicedelverify($vmid, $deviceid);
3974 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3976 qemu_devicedel
($vmid, $deviceid);
3977 qemu_devicedelverify
($vmid, $deviceid);
3978 qemu_drivedel
($vmid, $deviceid);
3979 qemu_iothread_del
($conf, $vmid, $deviceid);
3981 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3983 qemu_devicedel
($vmid, $deviceid);
3984 qemu_devicedelverify
($vmid, $deviceid);
3985 qemu_iothread_del
($conf, $vmid, $deviceid);
3987 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3989 qemu_devicedel
($vmid, $deviceid);
3990 qemu_drivedel
($vmid, $deviceid);
3991 qemu_deletescsihw
($conf, $vmid, $deviceid);
3993 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3995 qemu_devicedel
($vmid, $deviceid);
3996 qemu_devicedelverify
($vmid, $deviceid);
3997 qemu_netdevdel
($vmid, $deviceid);
4000 die "can't unplug device '$deviceid'\n";
4006 sub qemu_deviceadd
{
4007 my ($vmid, $devicefull) = @_;
4009 $devicefull = "driver=".$devicefull;
4010 my %options = split(/[=,]/, $devicefull);
4012 mon_cmd
($vmid, "device_add" , %options);
4015 sub qemu_devicedel
{
4016 my ($vmid, $deviceid) = @_;
4018 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
4021 sub qemu_iothread_add
{
4022 my($vmid, $deviceid, $device) = @_;
4024 if ($device->{iothread
}) {
4025 my $iothreads = vm_iothreads_list
($vmid);
4026 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4030 sub qemu_iothread_del
{
4031 my($conf, $vmid, $deviceid) = @_;
4033 my $confid = $deviceid;
4034 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
4035 $confid = 'scsi' . $1;
4037 my $device = parse_drive
($confid, $conf->{$confid});
4038 if ($device->{iothread
}) {
4039 my $iothreads = vm_iothreads_list
($vmid);
4040 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4044 sub qemu_objectadd
{
4045 my($vmid, $objectid, $qomtype) = @_;
4047 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4052 sub qemu_objectdel
{
4053 my($vmid, $objectid) = @_;
4055 mon_cmd
($vmid, "object-del", id
=> $objectid);
4061 my ($storecfg, $vmid, $device) = @_;
4063 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device);
4064 $drive =~ s/\\/\\\\/g;
4065 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
4067 # If the command succeeds qemu prints: "OK
"
4068 return 1 if $ret =~ m/OK/s;
4070 die "adding drive failed
: $ret\n";
4074 my($vmid, $deviceid) = @_;
4076 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
4079 return 1 if $ret eq "";
4081 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4082 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4084 die "deleting drive
$deviceid failed
: $ret\n";
4087 sub qemu_deviceaddverify {
4088 my ($vmid, $deviceid) = @_;
4090 for (my $i = 0; $i <= 5; $i++) {
4091 my $devices_list = vm_devices_list($vmid);
4092 return 1 if defined($devices_list->{$deviceid});
4096 die "error on hotplug device
'$deviceid'\n";
4100 sub qemu_devicedelverify {
4101 my ($vmid, $deviceid) = @_;
4103 # need to verify that the device is correctly removed as device_del
4104 # is async and empty return is not reliable
4106 for (my $i = 0; $i <= 5; $i++) {
4107 my $devices_list = vm_devices_list($vmid);
4108 return 1 if !defined($devices_list->{$deviceid});
4112 die "error on hot-unplugging device
'$deviceid'\n";
4115 sub qemu_findorcreatescsihw {
4116 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4118 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4120 my $scsihwid="$controller_prefix$controller";
4121 my $devices_list = vm_devices_list($vmid);
4123 if(!defined($devices_list->{$scsihwid})) {
4124 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4130 sub qemu_deletescsihw {
4131 my ($conf, $vmid, $opt) = @_;
4133 my $device = parse_drive($opt, $conf->{$opt});
4135 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4136 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4140 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4142 my $devices_list = vm_devices_list($vmid);
4143 foreach my $opt (keys %{$devices_list}) {
4144 if (is_valid_drivename($opt)) {
4145 my $drive = parse_drive($opt, $conf->{$opt});
4146 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4152 my $scsihwid="scsihw
$controller";
4154 vm_deviceunplug($vmid, $conf, $scsihwid);
4159 sub qemu_add_pci_bridge {
4160 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4166 print_pci_addr($device, $bridges, $arch, $machine_type);
4168 while (my ($k, $v) = each %$bridges) {
4171 return 1 if !defined($bridgeid) || $bridgeid < 1;
4173 my $bridge = "pci
.$bridgeid";
4174 my $devices_list = vm_devices_list($vmid);
4176 if (!defined($devices_list->{$bridge})) {
4177 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4183 sub qemu_set_link_status {
4184 my ($vmid, $device, $up) = @_;
4186 mon_cmd($vmid, "set_link
", name => $device,
4187 up => $up ? JSON::true : JSON::false);
4190 sub qemu_netdevadd {
4191 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4193 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4194 my %options = split(/[=,]/, $netdev);
4196 if (defined(my $vhost = $options{vhost})) {
4197 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4200 if (defined(my $queues = $options{queues})) {
4201 $options{queues} = $queues + 0;
4204 mon_cmd($vmid, "netdev_add
", %options);
4208 sub qemu_netdevdel {
4209 my ($vmid, $deviceid) = @_;
4211 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4214 sub qemu_usb_hotplug {
4215 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4219 # remove the old one first
4220 vm_deviceunplug($vmid, $conf, $deviceid);
4222 # check if xhci controller is necessary and available
4223 if ($device->{usb3}) {
4225 my $devicelist = vm_devices_list($vmid);
4227 if (!$devicelist->{xhci}) {
4228 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4229 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4232 my $d = parse_usb_device($device->{host});
4233 $d->{usb3} = $device->{usb3};
4236 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4239 sub qemu_cpu_hotplug {
4240 my ($vmid, $conf, $vcpus) = @_;
4242 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4245 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4246 $sockets = $conf->{sockets} if $conf->{sockets};
4247 my $cores = $conf->{cores} || 1;
4248 my $maxcpus = $sockets * $cores;
4250 $vcpus = $maxcpus if !$vcpus;
4252 die "you can
't add more vcpus than maxcpus\n"
4253 if $vcpus > $maxcpus;
4255 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4257 if ($vcpus < $currentvcpus) {
4259 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4261 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4262 qemu_devicedel($vmid, "cpu$i");
4264 my $currentrunningvcpus = undef;
4266 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4267 last if scalar(@{$currentrunningvcpus}) == $i-1;
4268 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4272 #update conf after each succesfull cpu unplug
4273 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4274 PVE::QemuConfig->write_config($vmid, $conf);
4277 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4283 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4284 die "vcpus in running vm does not match its configuration\n"
4285 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4287 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4289 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4290 my $cpustr = print_cpu_device($conf, $i);
4291 qemu_deviceadd($vmid, $cpustr);
4294 my $currentrunningvcpus = undef;
4296 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4297 last if scalar(@{$currentrunningvcpus}) == $i;
4298 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4302 #update conf after each succesfull cpu hotplug
4303 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4304 PVE::QemuConfig->write_config($vmid, $conf);
4308 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4309 mon_cmd($vmid, "cpu-add", id => int($i));
4314 sub qemu_block_set_io_throttle {
4315 my ($vmid, $deviceid,
4316 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4317 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4318 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4319 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4321 return if !check_running($vmid) ;
4323 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4325 bps_rd => int($bps_rd),
4326 bps_wr => int($bps_wr),
4328 iops_rd => int($iops_rd),
4329 iops_wr => int($iops_wr),
4330 bps_max => int($bps_max),
4331 bps_rd_max => int($bps_rd_max),
4332 bps_wr_max => int($bps_wr_max),
4333 iops_max => int($iops_max),
4334 iops_rd_max => int($iops_rd_max),
4335 iops_wr_max => int($iops_wr_max),
4336 bps_max_length => int($bps_max_length),
4337 bps_rd_max_length => int($bps_rd_max_length),
4338 bps_wr_max_length => int($bps_wr_max_length),
4339 iops_max_length => int($iops_max_length),
4340 iops_rd_max_length => int($iops_rd_max_length),
4341 iops_wr_max_length => int($iops_wr_max_length),
4346 sub qemu_block_resize {
4347 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4349 my $running = check_running($vmid);
4351 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4353 return if !$running;
4355 my $padding = (1024 - $size % 1024) % 1024;
4356 $size = $size + $padding;
4361 device => $deviceid,
4367 sub qemu_volume_snapshot {
4368 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4370 my $running = check_running($vmid);
4372 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4373 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4375 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4379 sub qemu_volume_snapshot_delete {
4380 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4382 my $running = check_running($vmid);
4387 my $conf = PVE::QemuConfig->load_config($vmid);
4388 PVE::QemuConfig->foreach_volume($conf, sub {
4389 my ($ds, $drive) = @_;
4390 $running = 1 if $drive->{file} eq $volid;
4394 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4395 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4397 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4401 sub set_migration_caps {
4402 my ($vmid, $savevm) = @_;
4404 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4406 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm
' : 'pbs-dirty-bitmap-migration
';
4407 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4412 "auto-converge" => 1,
4414 "x-rdma-pin-all" => 0,
4417 "dirty-bitmaps" => $dirty_bitmaps,
4420 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4422 for my $supported_capability (@$supported_capabilities) {
4424 capability => $supported_capability->{capability},
4425 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4429 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4433 my ($conf, $func, @param) = @_;
4437 my $test_volid = sub {
4438 my ($key, $drive, $snapname) = @_;
4440 my $volid = $drive->{file};
4443 $volhash->{$volid}->{cdrom} //= 1;
4444 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
4446 my $replicate = $drive->{replicate} // 1;
4447 $volhash->{$volid}->{replicate} //= 0;
4448 $volhash->{$volid}->{replicate} = 1 if $replicate;
4450 $volhash->{$volid}->{shared} //= 0;
4451 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
4453 $volhash->{$volid}->{referenced_in_config} //= 0;
4454 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4456 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4457 if defined($snapname);
4459 my $size = $drive->{size};
4460 $volhash->{$volid}->{size} //= $size if $size;
4462 $volhash->{$volid}->{is_vmstate} //= 0;
4463 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate
';
4465 $volhash->{$volid}->{is_unused} //= 0;
4466 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
4468 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
4471 my $include_opts = {
4472 extra_keys => ['vmstate
'],
4473 include_unused => 1,
4476 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
4477 foreach my $snapname (keys %{$conf->{snapshots}}) {
4478 my $snap = $conf->{snapshots}->{$snapname};
4479 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
4482 foreach my $volid (keys %$volhash) {
4483 &$func($volid, $volhash->{$volid}, @param);
4487 my $fast_plug_option = {
4495 'vmstatestorage
' => 1,
4500 # hotplug changes in [PENDING]
4501 # $selection hash can be used to only apply specified options, for
4502 # example: { cores => 1 } (only apply changed 'cores
')
4503 # $errors ref is used to return error messages
4504 sub vmconfig_hotplug_pending {
4505 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4507 my $defaults = load_defaults();
4508 my $arch = get_vm_arch($conf);
4509 my $machine_type = get_vm_machine($conf, undef, $arch);
4511 # commit values which do not have any impact on running VM first
4512 # Note: those option cannot raise errors, we we do not care about
4513 # $selection and always apply them.
4515 my $add_error = sub {
4516 my ($opt, $msg) = @_;
4517 $errors->{$opt} = "hotplug problem - $msg";
4521 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4522 if ($fast_plug_option->{$opt}) {
4523 $conf->{$opt} = $conf->{pending}->{$opt};
4524 delete $conf->{pending}->{$opt};
4530 PVE::QemuConfig->write_config($vmid, $conf);
4533 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4535 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
4536 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4537 foreach my $opt (sort keys %$pending_delete_hash) {
4538 next if $selection && !$selection->{$opt};
4539 my $force = $pending_delete_hash->{$opt}->{force};
4541 if ($opt eq 'hotplug
') {
4542 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4543 } elsif ($opt eq 'tablet
') {
4544 die "skip\n" if !$hotplug_features->{usb};
4545 if ($defaults->{tablet}) {
4546 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4547 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4548 if $arch eq 'aarch64
';
4550 vm_deviceunplug($vmid, $conf, 'tablet
');
4551 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4553 } elsif ($opt =~ m/^usb\d+/) {
4555 # since we cannot reliably hot unplug usb devices we are disabling it
4556 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4557 #vm_deviceunplug($vmid, $conf, $opt);
4558 } elsif ($opt eq 'vcpus
') {
4559 die "skip\n" if !$hotplug_features->{cpu};
4560 qemu_cpu_hotplug($vmid, $conf, undef);
4561 } elsif ($opt eq 'balloon
') {
4562 # enable balloon device is not hotpluggable
4563 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4564 # here we reset the ballooning value to memory
4565 my $balloon = $conf->{memory} || $defaults->{memory};
4566 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4567 } elsif ($fast_plug_option->{$opt}) {
4569 } elsif ($opt =~ m/^net(\d+)$/) {
4570 die "skip\n" if !$hotplug_features->{network};
4571 vm_deviceunplug($vmid, $conf, $opt);
4572 } elsif (is_valid_drivename($opt)) {
4573 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4574 vm_deviceunplug($vmid, $conf, $opt);
4575 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4576 } elsif ($opt =~ m/^memory$/) {
4577 die "skip\n" if !$hotplug_features->{memory};
4578 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4579 } elsif ($opt eq 'cpuunits
') {
4580 $cgroup->change_cpu_shares(undef, $defaults->{cpuunits});
4581 } elsif ($opt eq 'cpulimit
') {
4582 $cgroup->change_cpu_quota(-1, 100000);
4588 &$add_error($opt, $err) if $err ne "skip\n";
4590 delete $conf->{$opt};
4591 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4595 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4596 $apply_pending_cloudinit = sub {
4597 return if $apply_pending_cloudinit_done; # once is enough
4598 $apply_pending_cloudinit_done = 1; # once is enough
4600 my ($key, $value) = @_;
4602 my @cloudinit_opts = keys %$confdesc_cloudinit;
4603 foreach my $opt (keys %{$conf->{pending}}) {
4604 next if !grep { $_ eq $opt } @cloudinit_opts;
4605 $conf->{$opt} = delete $conf->{pending}->{$opt};
4608 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4609 foreach my $opt (sort keys %$pending_delete_hash) {
4610 next if !grep { $_ eq $opt } @cloudinit_opts;
4611 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4612 delete $conf->{$opt};
4615 my $new_conf = { %$conf };
4616 $new_conf->{$key} = $value;
4617 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4620 foreach my $opt (keys %{$conf->{pending}}) {
4621 next if $selection && !$selection->{$opt};
4622 my $value = $conf->{pending}->{$opt};
4624 if ($opt eq 'hotplug
') {
4625 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4626 } elsif ($opt eq 'tablet
') {
4627 die "skip\n" if !$hotplug_features->{usb};
4629 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4630 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4631 if $arch eq 'aarch64
';
4632 } elsif ($value == 0) {
4633 vm_deviceunplug($vmid, $conf, 'tablet
');
4634 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4636 } elsif ($opt =~ m/^usb\d+$/) {
4638 # since we cannot reliably hot unplug usb devices we disable it for now
4639 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4640 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4641 #die "skip\n" if !$d;
4642 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4643 } elsif ($opt eq 'vcpus
') {
4644 die "skip\n" if !$hotplug_features->{cpu};
4645 qemu_cpu_hotplug($vmid, $conf, $value);
4646 } elsif ($opt eq 'balloon
') {
4647 # enable/disable balloning device is not hotpluggable
4648 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4649 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4650 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4652 # allow manual ballooning if shares is set to zero
4653 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4654 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4655 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4657 } elsif ($opt =~ m/^net(\d+)$/) {
4658 # some changes can be done without hotplug
4659 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4660 $vmid, $opt, $value, $arch, $machine_type);
4661 } elsif (is_valid_drivename($opt)) {
4662 die "skip\n" if $opt eq 'efidisk0
';
4663 # some changes can be done without hotplug
4664 my $drive = parse_drive($opt, $value);
4665 if (drive_is_cloudinit($drive)) {
4666 &$apply_pending_cloudinit($opt, $value);
4668 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4669 $vmid, $opt, $value, $arch, $machine_type);
4670 } elsif ($opt =~ m/^memory$/) { #dimms
4671 die "skip\n" if !$hotplug_features->{memory};
4672 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4673 } elsif ($opt eq 'cpuunits
') {
4674 $cgroup->change_cpu_shares($conf->{pending}->{$opt}, $defaults->{cpuunits});
4675 } elsif ($opt eq 'cpulimit
') {
4676 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4677 $cgroup->change_cpu_quota($cpulimit, 100000);
4679 die "skip\n"; # skip non-hot-pluggable options
4683 &$add_error($opt, $err) if $err ne "skip\n";
4685 $conf->{$opt} = $value;
4686 delete $conf->{pending}->{$opt};
4690 PVE::QemuConfig->write_config($vmid, $conf);
4693 sub try_deallocate_drive {
4694 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4696 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4697 my $volid = $drive->{file};
4698 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4699 my $sid = PVE::Storage::parse_volume_id($volid);
4700 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4702 # check if the disk is really unused
4703 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4704 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4705 PVE::Storage::vdisk_free($storecfg, $volid);
4708 # If vm is not owner of this disk remove from config
4716 sub vmconfig_delete_or_detach_drive {
4717 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4719 my $drive = parse_drive($opt, $conf->{$opt});
4721 my $rpcenv = PVE::RPCEnvironment::get();
4722 my $authuser = $rpcenv->get_user();
4725 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4726 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4728 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4734 sub vmconfig_apply_pending {
4735 my ($vmid, $conf, $storecfg, $errors) = @_;
4737 my $add_apply_error = sub {
4738 my ($opt, $msg) = @_;
4739 my $err_msg = "unable to apply pending change $opt : $msg";
4740 $errors->{$opt} = $err_msg;
4746 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4747 foreach my $opt (sort keys %$pending_delete_hash) {
4748 my $force = $pending_delete_hash->{$opt}->{force};
4750 if ($opt =~ m/^unused/) {
4751 die "internal error";
4752 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4753 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4757 $add_apply_error->($opt, $err);
4759 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4760 delete $conf->{$opt};
4764 PVE::QemuConfig->cleanup_pending($conf);
4766 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4767 next if $opt eq 'delete'; # just to be sure
4769 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4770 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4774 $add_apply_error->($opt, $err);
4776 $conf->{$opt} = delete $conf->{pending}->{$opt};
4780 # write all changes at once to avoid unnecessary i/o
4781 PVE::QemuConfig->write_config($vmid, $conf);
4784 sub vmconfig_update_net {
4785 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4787 my $newnet = parse_net($value);
4789 if ($conf->{$opt}) {
4790 my $oldnet = parse_net($conf->{$opt});
4792 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4793 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4794 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4795 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4797 # for non online change, we try to hot-unplug
4798 die "skip\n" if !$hotplug;
4799 vm_deviceunplug($vmid, $conf, $opt);
4802 die "internal error" if $opt !~ m/net(\d+)/;
4803 my $iface = "tap${vmid}i$1";
4805 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4806 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4807 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4808 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4809 PVE::Network::tap_unplug($iface);
4812 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4814 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4816 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4817 # Rate can be applied on its own but any change above needs to
4818 # include the rate in tap_plug since OVS resets everything.
4819 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4822 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4823 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4831 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4837 sub vmconfig_update_disk {
4838 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4840 my $drive = parse_drive($opt, $value);
4842 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
4843 my $media = $drive->{media} || 'disk
';
4844 my $oldmedia = $old_drive->{media} || 'disk
';
4845 die "unable to change media type\n" if $media ne $oldmedia;
4847 if (!drive_is_cdrom($old_drive)) {
4849 if ($drive->{file} ne $old_drive->{file}) {
4851 die "skip\n" if !$hotplug;
4853 # unplug and register as unused
4854 vm_deviceunplug($vmid, $conf, $opt);
4855 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4858 # update existing disk
4860 # skip non hotpluggable value
4861 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4862 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4863 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4864 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4865 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
4870 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4871 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4872 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4873 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4874 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4875 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4876 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4877 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4878 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4879 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4880 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4881 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4882 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4883 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4884 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4885 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4886 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4887 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4889 qemu_block_set_io_throttle(
4891 ($drive->{mbps} || 0)*1024*1024,
4892 ($drive->{mbps_rd} || 0)*1024*1024,
4893 ($drive->{mbps_wr} || 0)*1024*1024,
4894 $drive->{iops} || 0,
4895 $drive->{iops_rd} || 0,
4896 $drive->{iops_wr} || 0,
4897 ($drive->{mbps_max} || 0)*1024*1024,
4898 ($drive->{mbps_rd_max} || 0)*1024*1024,
4899 ($drive->{mbps_wr_max} || 0)*1024*1024,
4900 $drive->{iops_max} || 0,
4901 $drive->{iops_rd_max} || 0,
4902 $drive->{iops_wr_max} || 0,
4903 $drive->{bps_max_length} || 1,
4904 $drive->{bps_rd_max_length} || 1,
4905 $drive->{bps_wr_max_length} || 1,
4906 $drive->{iops_max_length} || 1,
4907 $drive->{iops_rd_max_length} || 1,
4908 $drive->{iops_wr_max_length} || 1,
4918 if ($drive->{file} eq 'none
') {
4919 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4920 if (drive_is_cloudinit($old_drive)) {
4921 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4924 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4926 # force eject if locked
4927 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4930 mon_cmd($vmid, "blockdev-change-medium",
4931 id => "$opt", filename => "$path");
4939 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4941 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4942 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
4945 # called in locked context by incoming migration
4946 sub vm_migrate_get_nbd_disks {
4947 my ($storecfg, $conf, $replicated_volumes) = @_;
4949 my $local_volumes = {};
4950 PVE::QemuConfig->foreach_volume($conf, sub {
4951 my ($ds, $drive) = @_;
4953 return if drive_is_cdrom($drive);
4955 my $volid = $drive->{file};
4959 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4961 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4962 return if $scfg->{shared};
4964 # replicated disks re-use existing state via bitmap
4965 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
4966 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
4968 return $local_volumes;
4971 # called in locked context by incoming migration
4972 sub vm_migrate_alloc_nbd_disks {
4973 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
4978 foreach my $opt (sort keys %$source_volumes) {
4979 my ($volid, $storeid, $volname, $drive, $use_existing) = @{$source_volumes->{$opt}};
4981 if ($use_existing) {
4982 $nbd->{$opt}->{drivestr} = print_drive($drive);
4983 $nbd->{$opt}->{volid} = $volid;
4984 $nbd->{$opt}->{replicated} = 1;
4988 # If a remote storage is specified and the format of the original
4989 # volume is not available there, fall back to the default format.
4990 # Otherwise use the same format as the original.
4991 if (!$storagemap->{identity}) {
4992 $storeid = map_storage($storagemap, $storeid);
4993 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4994 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4995 my $fileFormat = qemu_img_format($scfg, $volname);
4996 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
4998 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4999 $format = qemu_img_format($scfg, $volname);
5002 my $size = $drive->{size} / 1024;
5003 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
5004 my $newdrive = $drive;
5005 $newdrive->{format} = $format;
5006 $newdrive->{file} = $newvolid;
5007 my $drivestr = print_drive($newdrive);
5008 $nbd->{$opt}->{drivestr} = $drivestr;
5009 $nbd->{$opt}->{volid} = $newvolid;
5015 # see vm_start_nolock for parameters, additionally:
5017 # storagemap = parsed storage map for allocating NBD disks
5019 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5021 return PVE::QemuConfig->lock_config($vmid, sub {
5022 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5024 die "you can't start a vm
if it
's a template\n"
5025 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
5027 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended
');
5028 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup
');
5030 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5032 if ($has_backup_lock && $running) {
5033 # a backup is currently running, attempt to start the guest in the
5034 # existing QEMU instance
5035 return vm_resume($vmid);
5038 PVE::QemuConfig->check_lock($conf)
5039 if !($params->{skiplock} || $has_suspended_lock);
5041 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
5043 die "VM $vmid already running\n" if $running;
5045 if (my $storagemap = $migrate_opts->{storagemap}) {
5046 my $replicated = $migrate_opts->{replicated_volumes};
5047 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5048 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5050 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5051 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5055 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
5061 # statefile => 'tcp
', 'unix
' for migration or path/volid for RAM state
5062 # skiplock => 0/1, skip checking for config lock
5063 # skiptemplate => 0/1, skip checking whether VM is template
5064 # forcemachine => to force Qemu machine (rollback/migration)
5065 # forcecpu => a QEMU '-cpu
' argument string to override get_cpu_options
5066 # timeout => in seconds
5067 # paused => start VM in paused state (backup)
5068 # resume => resume from hibernation
5079 # nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
5080 # migratedfrom => source node
5081 # spice_ticket => used for spice migration, passed via tunnel/stdin
5082 # network => CIDR of migration network
5083 # type => secure/insecure - tunnel over encrypted connection or plain-text
5084 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
5085 # replicated_volumes = which volids should be re-used with bitmaps for nbd migration
5086 sub vm_start_nolock {
5087 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
5089 my $statefile = $params->{statefile};
5090 my $resume = $params->{resume};
5092 my $migratedfrom = $migrate_opts->{migratedfrom};
5093 my $migration_type = $migrate_opts->{type};
5097 # clean up leftover reboot request files
5098 eval { clear_reboot_request($vmid); };
5101 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5102 vmconfig_apply_pending($vmid, $conf, $storecfg);
5103 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5106 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5108 my $defaults = load_defaults();
5110 # set environment variable useful inside network script
5111 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5113 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
5115 my $forcemachine = $params->{forcemachine};
5116 my $forcecpu = $params->{forcecpu};
5118 # enforce machine and CPU type on suspended vm to ensure HW compatibility
5119 $forcemachine = $conf->{runningmachine};
5120 $forcecpu = $conf->{runningcpu};
5121 print "Resuming suspended VM\n";
5124 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid,
5125 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing
'});
5128 my $get_migration_ip = sub {
5129 my ($nodename) = @_;
5131 return $migration_ip if defined($migration_ip);
5133 my $cidr = $migrate_opts->{network};
5135 if (!defined($cidr)) {
5136 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5137 $cidr = $dc_conf->{migration}->{network};
5140 if (defined($cidr)) {
5141 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
5143 die "could not get IP: no address configured on local " .
5144 "node for network '$cidr'\n" if scalar(@$ips) == 0;
5146 die "could not get IP: multiple addresses configured on local " .
5147 "node for network '$cidr'\n" if scalar(@$ips) > 1;
5149 $migration_ip = @$ips[0];
5152 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
5153 if !defined($migration_ip);
5155 return $migration_ip;
5160 if ($statefile eq 'tcp
') {
5161 my $localip = "localhost";
5162 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5163 my $nodename = nodename();
5165 if (!defined($migration_type)) {
5166 if (defined($datacenterconf->{migration}->{type})) {
5167 $migration_type = $datacenterconf->{migration}->{type};
5169 $migration_type = 'secure
';
5173 if ($migration_type eq 'insecure
') {
5174 $localip = $get_migration_ip->($nodename);
5175 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5178 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5179 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5180 $migrate_uri = "tcp:${localip}:${migrate_port}";
5181 push @$cmd, '-incoming
', $migrate_uri;
5184 } elsif ($statefile eq 'unix
') {
5185 # should be default for secure migrations as a ssh TCP forward
5186 # tunnel is not deterministic reliable ready and fails regurarly
5187 # to set up in time, so use UNIX socket forwards
5188 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5189 unlink $socket_addr;
5191 $migrate_uri = "unix:$socket_addr";
5193 push @$cmd, '-incoming
', $migrate_uri;
5196 } elsif (-e $statefile) {
5197 push @$cmd, '-loadstate
', $statefile;
5199 my $statepath = PVE::Storage::path($storecfg, $statefile);
5200 push @$vollist, $statefile;
5201 push @$cmd, '-loadstate
', $statepath;
5203 } elsif ($params->{paused}) {
5208 for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
5209 my $d = parse_hostpci($conf->{"hostpci$i"});
5211 my $pcidevices = $d->{pciid};
5212 foreach my $pcidevice (@$pcidevices) {
5213 my $pciid = $pcidevice->{id};
5215 my $info = PVE::SysFSTools::pci_device_info("$pciid");
5216 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5217 die "no pci device info for device '$pciid'\n" if !$info;
5220 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5221 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5223 die "can't unbind
/bind PCI group to VFIO
'$pciid'\n"
5224 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5225 die "can
't reset PCI device '$pciid'\n"
5226 if $info->{has_fl_reset} && !PVE::SysFSTools::pci_dev_reset($info);
5231 PVE::Storage::activate_volumes($storecfg, $vollist);
5234 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5235 outfunc => sub {}, errfunc => sub {});
5237 # Issues with the above 'stop
' not being fully completed are extremely rare, a very low
5238 # timeout should be more than enough here...
5239 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5241 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5242 : $defaults->{cpuunits};
5244 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5246 timeout => $statefile ? undef : $start_timeout,
5251 # when migrating, prefix QEMU output so other side can pick up any
5252 # errors that might occur and show the user
5253 if ($migratedfrom) {
5254 $run_params{quiet} = 1;
5255 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5259 Slice => 'qemu
.slice
',
5263 if (PVE::CGroup::cgroup_mode() == 2) {
5264 $properties{CPUWeight} = $cpuunits;
5266 $properties{CPUShares} = $cpuunits;
5269 if (my $cpulimit = $conf->{cpulimit}) {
5270 $properties{CPUQuota} = int($cpulimit * 100);
5272 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5274 my $run_qemu = sub {
5275 PVE::Tools::run_fork sub {
5276 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5278 my $exitcode = run_command($cmd, %run_params);
5279 die "QEMU exited with code $exitcode\n" if $exitcode;
5283 if ($conf->{hugepages}) {
5286 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5287 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5289 PVE::QemuServer::Memory::hugepages_mount();
5290 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5292 eval { $run_qemu->() };
5294 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology)
5295 if !$conf->{keephugepages};
5299 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology)
5300 if !$conf->{keephugepages};
5302 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5305 eval { $run_qemu->() };
5309 # deactivate volumes if start fails
5310 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5311 die "start failed: $err";
5314 print "migration listens on $migrate_uri\n" if $migrate_uri;
5315 $res->{migrate_uri} = $migrate_uri;
5317 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5318 eval { mon_cmd($vmid, "cont"); };
5322 #start nbd server for storage migration
5323 if (my $nbd = $migrate_opts->{nbd}) {
5324 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
5326 my $migrate_storage_uri;
5327 # nbd_protocol_version > 0 for unix socket support
5328 if ($nbd_protocol_version > 0 && $migration_type eq 'secure
') {
5329 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5330 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix
', data => { path => $socket_path } } );
5331 $migrate_storage_uri = "nbd:unix:$socket_path";
5333 my $nodename = nodename();
5334 my $localip = $get_migration_ip->($nodename);
5335 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5336 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5338 mon_cmd($vmid, "nbd-server-start", addr => {
5341 host => "${localip}",
5342 port => "${storage_migrate_port}",
5345 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5346 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5349 $res->{migrate_storage_uri} = $migrate_storage_uri;
5351 foreach my $opt (sort keys %$nbd) {
5352 my $drivestr = $nbd->{$opt}->{drivestr};
5353 my $volid = $nbd->{$opt}->{volid};
5354 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5355 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5356 print "storage migration listens on $nbd_uri volume:$drivestr\n";
5357 print "re-using replicated volume: $opt - $volid\n"
5358 if $nbd->{$opt}->{replicated};
5360 $res->{drives}->{$opt} = $nbd->{$opt};
5361 $res->{drives}->{$opt}->{nbd_uri} = $nbd_uri;
5365 if ($migratedfrom) {
5367 set_migration_caps($vmid);
5372 print "spice listens on port $spice_port\n";
5373 $res->{spice_port} = $spice_port;
5374 if ($migrate_opts->{spice_ticket}) {
5375 mon_cmd($vmid, "set_password", protocol => 'spice
', password =>
5376 $migrate_opts->{spice_ticket});
5377 mon_cmd($vmid, "expire_password", protocol => 'spice
', time => "+30");
5382 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5383 if !$statefile && $conf->{balloon};
5385 foreach my $opt (keys %$conf) {
5386 next if $opt !~ m/^net\d+$/;
5387 my $nicconf = parse_net($conf->{$opt});
5388 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5392 mon_cmd($vmid, 'qom-set
',
5393 path => "machine/peripheral/balloon0",
5394 property => "guest-stats-polling-interval",
5395 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5398 print "Resumed VM, removing state\n";
5399 if (my $vmstate = $conf->{vmstate}) {
5400 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5401 PVE::Storage::vdisk_free($storecfg, $vmstate);
5403 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
5404 PVE
::QemuConfig-
>write_config($vmid, $conf);
5407 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5412 sub vm_commandline
{
5413 my ($storecfg, $vmid, $snapname) = @_;
5415 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5420 my $snapshot = $conf->{snapshots
}->{$snapname};
5421 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5423 # check for machine or CPU overrides in snapshot
5424 $forcemachine = $snapshot->{runningmachine
};
5425 $forcecpu = $snapshot->{runningcpu
};
5427 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5432 my $defaults = load_defaults
();
5434 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults,
5435 $forcemachine, $forcecpu);
5437 return PVE
::Tools
::cmd2string
($cmd);
5441 my ($vmid, $skiplock) = @_;
5443 PVE
::QemuConfig-
>lock_config($vmid, sub {
5445 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5447 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5449 mon_cmd
($vmid, "system_reset");
5453 sub get_vm_volumes
{
5457 foreach_volid
($conf, sub {
5458 my ($volid, $attr) = @_;
5460 return if $volid =~ m
|^/|;
5462 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5465 push @$vollist, $volid;
5471 sub vm_stop_cleanup
{
5472 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5477 my $vollist = get_vm_volumes
($conf);
5478 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5481 foreach my $ext (qw(mon qmp pid vnc qga)) {
5482 unlink "/var/run/qemu-server/${vmid}.$ext";
5485 if ($conf->{ivshmem
}) {
5486 my $ivshmem = parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5487 # just delete it for now, VMs which have this already open do not
5488 # are affected, but new VMs will get a separated one. If this
5489 # becomes an issue we either add some sort of ref-counting or just
5490 # add a "don't delete on stop" flag to the ivshmem format.
5491 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5494 foreach my $key (keys %$conf) {
5495 next if $key !~ m/^hostpci(\d+)$/;
5496 my $hostpciindex = $1;
5497 my $d = parse_hostpci
($conf->{$key});
5498 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5500 foreach my $pci (@{$d->{pciid
}}) {
5501 my $pciid = $pci->{id
};
5502 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5506 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5508 warn $@ if $@; # avoid errors - just warn
5511 # call only in locked context
5513 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5515 my $pid = check_running
($vmid, $nocheck);
5520 $conf = PVE
::QemuConfig-
>load_config($vmid);
5521 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5522 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5523 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5524 $timeout = $opts->{down
} if $opts->{down
};
5526 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5531 if (defined($conf) && get_qga_key
($conf, 'enabled')) {
5532 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5534 mon_cmd
($vmid, "system_powerdown");
5537 mon_cmd
($vmid, "quit");
5543 $timeout = 60 if !defined($timeout);
5546 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5551 if ($count >= $timeout) {
5553 warn "VM still running - terminating now with SIGTERM\n";
5556 die "VM quit/powerdown failed - got timeout\n";
5559 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5563 if (!check_running
($vmid, $nocheck)) {
5564 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
5568 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5571 die "VM quit/powerdown failed\n";
5579 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5584 if ($count >= $timeout) {
5585 warn "VM still running - terminating now with SIGKILL\n";
5590 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5593 # Note: use $nocheck to skip tests if VM configuration file exists.
5594 # We need that when migration VMs to other nodes (files already moved)
5595 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5597 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5599 $force = 1 if !defined($force) && !$shutdown;
5602 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5603 kill 15, $pid if $pid;
5604 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5605 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5609 PVE
::QemuConfig-
>lock_config($vmid, sub {
5610 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5615 my ($vmid, $timeout) = @_;
5617 PVE
::QemuConfig-
>lock_config($vmid, sub {
5620 # only reboot if running, as qmeventd starts it again on a stop event
5621 return if !check_running
($vmid);
5623 create_reboot_request
($vmid);
5625 my $storecfg = PVE
::Storage
::config
();
5626 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5630 # avoid that the next normal shutdown will be confused for a reboot
5631 clear_reboot_request
($vmid);
5637 # note: if using the statestorage parameter, the caller has to check privileges
5639 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5646 PVE
::QemuConfig-
>lock_config($vmid, sub {
5648 $conf = PVE
::QemuConfig-
>load_config($vmid);
5650 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5651 PVE
::QemuConfig-
>check_lock($conf)
5652 if !($skiplock || $is_backing_up);
5654 die "cannot suspend to disk during backup\n"
5655 if $is_backing_up && $includestate;
5657 if ($includestate) {
5658 $conf->{lock} = 'suspending';
5659 my $date = strftime
("%Y-%m-%d", localtime(time()));
5660 $storecfg = PVE
::Storage
::config
();
5661 if (!$statestorage) {
5662 $statestorage = find_vmstate_storage
($conf, $storecfg);
5663 # check permissions for the storage
5664 my $rpcenv = PVE
::RPCEnvironment
::get
();
5665 if ($rpcenv->{type
} ne 'cli') {
5666 my $authuser = $rpcenv->get_user();
5667 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5672 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate(
5673 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5674 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5675 PVE
::QemuConfig-
>write_config($vmid, $conf);
5677 mon_cmd
($vmid, "stop");
5681 if ($includestate) {
5683 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5686 set_migration_caps
($vmid, 1);
5687 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5689 my $state = mon_cmd
($vmid, "query-savevm");
5690 if (!$state->{status
}) {
5691 die "savevm not active\n";
5692 } elsif ($state->{status
} eq 'active') {
5695 } elsif ($state->{status
} eq 'completed') {
5696 print "State saved, quitting\n";
5698 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5699 die "query-savevm failed with error '$state->{error}'\n"
5701 die "query-savevm returned status '$state->{status}'\n";
5707 PVE
::QemuConfig-
>lock_config($vmid, sub {
5708 $conf = PVE
::QemuConfig-
>load_config($vmid);
5710 # cleanup, but leave suspending lock, to indicate something went wrong
5712 mon_cmd
($vmid, "savevm-end");
5713 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5714 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5715 delete $conf->@{qw(vmstate runningmachine runningcpu)};
5716 PVE
::QemuConfig-
>write_config($vmid, $conf);
5722 die "lock changed unexpectedly\n"
5723 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5725 mon_cmd
($vmid, "quit");
5726 $conf->{lock} = 'suspended';
5727 PVE
::QemuConfig-
>write_config($vmid, $conf);
5733 my ($vmid, $skiplock, $nocheck) = @_;
5735 PVE
::QemuConfig-
>lock_config($vmid, sub {
5736 my $res = mon_cmd
($vmid, 'query-status');
5737 my $resume_cmd = 'cont';
5740 if ($res->{status
}) {
5741 return if $res->{status
} eq 'running'; # job done, go home
5742 $resume_cmd = 'system_wakeup' if $res->{status
} eq 'suspended';
5743 $reset = 1 if $res->{status
} eq 'shutdown';
5748 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5750 PVE
::QemuConfig-
>check_lock($conf)
5751 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5755 # required if a VM shuts down during a backup and we get a resume
5756 # request before the backup finishes for example
5757 mon_cmd
($vmid, "system_reset");
5759 mon_cmd
($vmid, $resume_cmd);
5764 my ($vmid, $skiplock, $key) = @_;
5766 PVE
::QemuConfig-
>lock_config($vmid, sub {
5768 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5770 # there is no qmp command, so we use the human monitor command
5771 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5772 die $res if $res ne '';
5776 # vzdump restore implementaion
5778 sub tar_archive_read_firstfile
{
5779 my $archive = shift;
5781 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5783 # try to detect archive type first
5784 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5785 die "unable to open file '$archive'\n";
5786 my $firstfile = <$fh>;
5790 die "ERROR: archive contaions no data\n" if !$firstfile;
5796 sub tar_restore_cleanup
{
5797 my ($storecfg, $statfile) = @_;
5799 print STDERR
"starting cleanup\n";
5801 if (my $fd = IO
::File-
>new($statfile, "r")) {
5802 while (defined(my $line = <$fd>)) {
5803 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5806 if ($volid =~ m
|^/|) {
5807 unlink $volid || die 'unlink failed\n';
5809 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5811 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5813 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5815 print STDERR
"unable to parse line in statfile - $line";
5822 sub restore_file_archive
{
5823 my ($archive, $vmid, $user, $opts) = @_;
5825 return restore_vma_archive
($archive, $vmid, $user, $opts)
5828 my $info = PVE
::Storage
::archive_info
($archive);
5829 my $format = $opts->{format
} // $info->{format
};
5830 my $comp = $info->{compression
};
5832 # try to detect archive format
5833 if ($format eq 'tar') {
5834 return restore_tar_archive
($archive, $vmid, $user, $opts);
5836 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5840 # hepler to remove disks that will not be used after restore
5841 my $restore_cleanup_oldconf = sub {
5842 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5844 PVE
::QemuConfig-
>foreach_volume($oldconf, sub {
5845 my ($ds, $drive) = @_;
5847 return if drive_is_cdrom
($drive, 1);
5849 my $volid = $drive->{file
};
5850 return if !$volid || $volid =~ m
|^/|;
5852 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
5853 return if !$path || !$owner || ($owner != $vmid);
5855 # Note: only delete disk we want to restore
5856 # other volumes will become unused
5857 if ($virtdev_hash->{$ds}) {
5858 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
5865 # delete vmstate files, after the restore we have no snapshots anymore
5866 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5867 my $snap = $oldconf->{snapshots
}->{$snapname};
5868 if ($snap->{vmstate
}) {
5869 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
5877 # Helper to parse vzdump backup device hints
5879 # $rpcenv: Environment, used to ckeck storage permissions
5880 # $user: User ID, to check storage permissions
5881 # $storecfg: Storage configuration
5882 # $fh: the file handle for reading the configuration
5883 # $devinfo: should contain device sizes for all backu-up'ed devices
5884 # $options: backup options (pool, default storage)
5886 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5887 my $parse_backup_hints = sub {
5888 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
5890 my $virtdev_hash = {};
5892 while (defined(my $line = <$fh>)) {
5893 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5894 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5895 die "archive does not contain data for drive '$virtdev'\n"
5896 if !$devinfo->{$devname};
5898 if (defined($options->{storage
})) {
5899 $storeid = $options->{storage
} || 'local';
5900 } elsif (!$storeid) {
5903 $format = 'raw' if !$format;
5904 $devinfo->{$devname}->{devname
} = $devname;
5905 $devinfo->{$devname}->{virtdev
} = $virtdev;
5906 $devinfo->{$devname}->{format
} = $format;
5907 $devinfo->{$devname}->{storeid
} = $storeid;
5909 # check permission on storage
5910 my $pool = $options->{pool
}; # todo: do we need that?
5911 if ($user ne 'root@pam') {
5912 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5915 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5916 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5918 my $drive = parse_drive
($virtdev, $2);
5919 if (drive_is_cloudinit
($drive)) {
5920 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5921 $storeid = $options->{storage
} if defined ($options->{storage
});
5922 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5923 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
5925 $virtdev_hash->{$virtdev} = {
5927 storeid
=> $storeid,
5928 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
5935 return $virtdev_hash;
5938 # Helper to allocate and activate all volumes required for a restore
5940 # $storecfg: Storage configuration
5941 # $virtdev_hash: as returned by parse_backup_hints()
5943 # Returns: { $virtdev => $volid }
5944 my $restore_allocate_devices = sub {
5945 my ($storecfg, $virtdev_hash, $vmid) = @_;
5948 foreach my $virtdev (sort keys %$virtdev_hash) {
5949 my $d = $virtdev_hash->{$virtdev};
5950 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5951 my $storeid = $d->{storeid
};
5952 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5954 # test if requested format is supported
5955 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5956 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5957 $d->{format
} = $defFormat if !$supported;
5960 if ($d->{is_cloudinit
}) {
5961 $name = "vm-$vmid-cloudinit";
5962 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5963 if ($scfg->{path
}) {
5964 $name .= ".$d->{format}";
5968 my $volid = PVE
::Storage
::vdisk_alloc
(
5969 $storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
5971 print STDERR
"new volume ID is '$volid'\n";
5972 $d->{volid
} = $volid;
5974 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
5976 $map->{$virtdev} = $volid;
5982 sub restore_update_config_line
{
5983 my ($cookie, $map, $line, $unique) = @_;
5985 return '' if $line =~ m/^\#qmdump\#/;
5986 return '' if $line =~ m/^\#vzdump\#/;
5987 return '' if $line =~ m/^lock:/;
5988 return '' if $line =~ m/^unused\d+:/;
5989 return '' if $line =~ m/^parent:/;
5993 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5994 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5995 # try to convert old 1.X settings
5996 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5997 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5998 my ($model, $macaddr) = split(/\=/, $devconfig);
5999 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
6002 bridge
=> "vmbr$ind",
6003 macaddr
=> $macaddr,
6005 my $netstr = print_net
($net);
6007 $res .= "net$cookie->{netcount}: $netstr\n";
6008 $cookie->{netcount
}++;
6010 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6011 my ($id, $netstr) = ($1, $2);
6012 my $net = parse_net
($netstr);
6013 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
6014 $netstr = print_net
($net);
6015 $res .= "$id: $netstr\n";
6016 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
6019 my $di = parse_drive
($virtdev, $value);
6020 if (defined($di->{backup
}) && !$di->{backup
}) {
6022 } elsif ($map->{$virtdev}) {
6023 delete $di->{format
}; # format can change on restore
6024 $di->{file
} = $map->{$virtdev};
6025 $value = print_drive
($di);
6026 $res .= "$virtdev: $value\n";
6030 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6032 if ($vmgenid ne '0') {
6033 # always generate a new vmgenid if there was a valid one setup
6034 $vmgenid = generate_uuid
();
6036 $res .= "vmgenid: $vmgenid\n";
6037 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6038 my ($uuid, $uuid_str);
6039 UUID
::generate
($uuid);
6040 UUID
::unparse
($uuid, $uuid_str);
6041 my $smbios1 = parse_smbios1
($2);
6042 $smbios1->{uuid
} = $uuid_str;
6043 $res .= $1.print_smbios1
($smbios1)."\n";
6051 my $restore_deactivate_volumes = sub {
6052 my ($storecfg, $devinfo) = @_;
6055 foreach my $devname (keys %$devinfo) {
6056 my $volid = $devinfo->{$devname}->{volid
};
6057 push @$vollist, $volid if $volid;
6060 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
6063 my $restore_destroy_volumes = sub {
6064 my ($storecfg, $devinfo) = @_;
6066 foreach my $devname (keys %$devinfo) {
6067 my $volid = $devinfo->{$devname}->{volid
};
6070 if ($volid =~ m
|^/|) {
6071 unlink $volid || die 'unlink failed\n';
6073 PVE
::Storage
::vdisk_free
($storecfg, $volid);
6075 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6077 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6081 # FIXME For PVE 7.0, remove $content_type and always use 'images'
6083 my ($cfg, $vmid, $content_type) = @_;
6085 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid, undef, $content_type);
6087 my $volid_hash = {};
6088 foreach my $storeid (keys %$info) {
6089 foreach my $item (@{$info->{$storeid}}) {
6090 next if !($item->{volid
} && $item->{size
});
6091 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6092 $volid_hash->{$item->{volid
}} = $item;
6099 sub update_disk_config
{
6100 my ($vmid, $conf, $volid_hash) = @_;
6103 my $prefix = "VM $vmid";
6105 # used and unused disks
6106 my $referenced = {};
6108 # Note: it is allowed to define multiple storages with same path (alias), so
6109 # we need to check both 'volid' and real 'path' (two different volid can point
6110 # to the same path).
6112 my $referencedpath = {};
6115 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6116 my ($opt, $drive) = @_;
6118 my $volid = $drive->{file
};
6120 my $volume = $volid_hash->{$volid};
6122 # mark volid as "in-use" for next step
6123 $referenced->{$volid} = 1;
6124 if ($volume && (my $path = $volume->{path
})) {
6125 $referencedpath->{$path} = 1;
6128 return if drive_is_cdrom
($drive);
6131 my ($updated, $msg) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volume->{size
});
6132 if (defined($updated)) {
6134 $conf->{$opt} = print_drive
($updated);
6135 print "$prefix ($opt): $msg\n";
6139 # remove 'unusedX' entry if volume is used
6140 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
6141 my ($opt, $drive) = @_;
6143 my $volid = $drive->{file
};
6147 $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6148 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6149 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
6151 delete $conf->{$opt};
6154 $referenced->{$volid} = 1;
6155 $referencedpath->{$path} = 1 if $path;
6158 foreach my $volid (sort keys %$volid_hash) {
6159 next if $volid =~ m/vm-$vmid-state-/;
6160 next if $referenced->{$volid};
6161 my $path = $volid_hash->{$volid}->{path
};
6162 next if !$path; # just to be sure
6163 next if $referencedpath->{$path};
6165 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6166 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
6167 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6174 my ($vmid, $nolock, $dryrun) = @_;
6176 my $cfg = PVE
::Storage
::config
();
6178 print "rescan volumes...\n";
6179 my $volid_hash = scan_volids
($cfg, $vmid, 'images');
6181 my $updatefn = sub {
6184 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6186 PVE
::QemuConfig-
>check_lock($conf);
6189 foreach my $volid (keys %$volid_hash) {
6190 my $info = $volid_hash->{$volid};
6191 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6194 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
6196 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6199 if (defined($vmid)) {
6203 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6206 my $vmlist = config_list
();
6207 foreach my $vmid (keys %$vmlist) {
6211 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6217 sub restore_proxmox_backup_archive
{
6218 my ($archive, $vmid, $user, $options) = @_;
6220 my $storecfg = PVE
::Storage
::config
();
6222 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
6223 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6225 my $fingerprint = $scfg->{fingerprint
};
6226 my $keyfile = PVE
::Storage
::PBSPlugin
::pbs_encryption_key_file_name
($storecfg, $storeid);
6228 my $repo = PVE
::PBSClient
::get_repository
($scfg);
6230 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
6231 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
6232 local $ENV{PBS_PASSWORD
} = $password;
6233 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
6235 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6236 PVE
::Storage
::parse_volname
($storecfg, $archive);
6238 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6240 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6242 my $tmpdir = "/var/tmp/vzdumptmp$$";
6246 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6247 # disable interrupts (always do cleanups)
6251 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6253 # Note: $oldconf is undef if VM does not exists
6254 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6255 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6256 my $new_conf_raw = '';
6258 my $rpcenv = PVE
::RPCEnvironment
::get
();
6267 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6269 my $cfgfn = "$tmpdir/qemu-server.conf";
6270 my $firewall_config_fn = "$tmpdir/fw.conf";
6271 my $index_fn = "$tmpdir/index.json";
6273 my $cmd = "restore";
6275 my $param = [$pbs_backup_name, "index.json", $index_fn];
6276 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6277 my $index = PVE
::Tools
::file_get_contents
($index_fn);
6278 $index = decode_json
($index);
6280 # print Dumper($index);
6281 foreach my $info (@{$index->{files
}}) {
6282 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
6284 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
6285 $devinfo->{$devname}->{size
} = $1;
6287 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6292 my $is_qemu_server_backup = scalar(
6293 grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}}
6295 if (!$is_qemu_server_backup) {
6296 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6298 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
6300 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6301 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6303 if ($has_firewall_config) {
6304 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6305 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
6307 my $pve_firewall_dir = '/etc/pve/firewall';
6308 mkdir $pve_firewall_dir; # make sure the dir exists
6309 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6312 my $fh = IO
::File-
>new($cfgfn, "r") ||
6313 die "unable to read qemu-server.conf - $!\n";
6315 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6317 # fixme: rate limit?
6319 # create empty/temp config
6320 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6322 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6325 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6327 if (!$options->{live
}) {
6328 foreach my $virtdev (sort keys %$virtdev_hash) {
6329 my $d = $virtdev_hash->{$virtdev};
6330 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6332 my $volid = $d->{volid
};
6334 my $path = PVE
::Storage
::path
($storecfg, $volid);
6336 my $pbs_restore_cmd = [
6337 '/usr/bin/pbs-restore',
6338 '--repository', $repo,
6340 "$d->{devname}.img.fidx",
6345 push @$pbs_restore_cmd, '--format', $d->{format
} if $d->{format
};
6346 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e
$keyfile;
6348 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6349 push @$pbs_restore_cmd, '--skip-zero';
6352 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6353 print "restore proxmox backup image: $dbg_cmdstring\n";
6354 run_command
($pbs_restore_cmd);
6358 $fh->seek(0, 0) || die "seek failed - $!\n";
6360 my $cookie = { netcount
=> 0 };
6361 while (defined(my $line = <$fh>)) {
6362 $new_conf_raw .= restore_update_config_line
(
6374 if ($err || !$options->{live
}) {
6375 $restore_deactivate_volumes->($storecfg, $devinfo);
6381 $restore_destroy_volumes->($storecfg, $devinfo);
6385 if ($options->{live
}) {
6386 # keep lock during live-restore
6387 $new_conf_raw .= "\nlock: create";
6390 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6392 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6394 eval { rescan
($vmid, 1); };
6397 PVE
::AccessControl
::add_vm_to_pool
($vmid, $options->{pool
}) if $options->{pool
};
6399 if ($options->{live
}) {
6405 local $SIG{PIPE
} = sub { die "got signal ($!) - abort\n"; };
6407 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6408 die "cannot do live-restore for template\n" if PVE
::QemuConfig-
>is_template($conf);
6410 pbs_live_restore
($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
6412 PVE
::QemuConfig-
>remove_lock($vmid, "create");
6416 sub pbs_live_restore
{
6417 my ($vmid, $conf, $storecfg, $restored_disks, $repo, $keyfile, $snap) = @_;
6419 print "Starting VM for live-restore\n";
6421 my $pbs_backing = {};
6422 for my $ds (keys %$restored_disks) {
6423 $ds =~ m/^drive-(.*)$/;
6424 $pbs_backing->{$1} = {
6425 repository
=> $repo,
6427 archive
=> "$ds.img.fidx",
6429 $pbs_backing->{$1}->{keyfile
} = $keyfile if -e
$keyfile;
6432 my $drives_streamed = 0;
6434 # make sure HA doesn't interrupt our restore by stopping the VM
6435 if (PVE
::HA
::Config
::vm_is_ha_managed
($vmid)) {
6436 run_command
(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
6439 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6440 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
6441 vm_start_nolock
($storecfg, $vmid, $conf, {paused
=> 1, 'pbs-backing' => $pbs_backing}, {});
6443 my $qmeventd_fd = register_qmeventd_handle
($vmid);
6445 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6446 # this will effectively collapse the backing image chain consisting of
6447 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6448 # removes itself once all backing images vanish with 'auto-remove=on')
6450 for my $ds (sort keys %$restored_disks) {
6451 my $job_id = "restore-$ds";
6452 mon_cmd
($vmid, 'block-stream',
6453 'job-id' => $job_id,
6456 $jobs->{$job_id} = {};
6459 mon_cmd
($vmid, 'cont');
6460 qemu_drive_mirror_monitor
($vmid, undef, $jobs, 'auto', 0, 'stream');
6462 print "restore-drive jobs finished successfully, removing all tracking block devices"
6463 ." to disconnect from Proxmox Backup Server\n";
6465 for my $ds (sort keys %$restored_disks) {
6466 mon_cmd
($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6469 close($qmeventd_fd);
6475 warn "An error occured during live-restore: $err\n";
6476 _do_vm_stop
($storecfg, $vmid, 1, 1, 10, 0, 1);
6477 die "live-restore failed\n";
6481 sub restore_vma_archive
{
6482 my ($archive, $vmid, $user, $opts, $comp) = @_;
6484 my $readfrom = $archive;
6486 my $cfg = PVE
::Storage
::config
();
6488 my $bwlimit = $opts->{bwlimit
};
6490 my $dbg_cmdstring = '';
6491 my $add_pipe = sub {
6493 push @$commands, $cmd;
6494 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6495 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6500 if ($archive eq '-') {
6503 # If we use a backup from a PVE defined storage we also consider that
6504 # storage's rate limit:
6505 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6506 if (defined($volid)) {
6507 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6508 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6510 print STDERR
"applying read rate limit: $readlimit\n";
6511 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6512 $add_pipe->($cstream);
6518 my $info = PVE
::Storage
::decompressor_info
('vma', $comp);
6519 my $cmd = $info->{decompressor
};
6520 push @$cmd, $readfrom;
6524 my $tmpdir = "/var/tmp/vzdumptmp$$";
6527 # disable interrupts (always do cleanups)
6531 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6533 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6534 POSIX
::mkfifo
($mapfifo, 0600);
6536 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
6538 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6545 my $rpcenv = PVE
::RPCEnvironment
::get
();
6547 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6549 # Note: $oldconf is undef if VM does not exist
6550 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6551 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6552 my $new_conf_raw = '';
6556 my $print_devmap = sub {
6557 my $cfgfn = "$tmpdir/qemu-server.conf";
6559 # we can read the config - that is already extracted
6560 my $fh = IO
::File-
>new($cfgfn, "r") ||
6561 die "unable to read qemu-server.conf - $!\n";
6563 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6565 my $pve_firewall_dir = '/etc/pve/firewall';
6566 mkdir $pve_firewall_dir; # make sure the dir exists
6567 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6570 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6572 foreach my $info (values %{$virtdev_hash}) {
6573 my $storeid = $info->{storeid
};
6574 next if defined($storage_limits{$storeid});
6576 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$storeid], $bwlimit) // 0;
6577 print STDERR
"rate limit for storage $storeid: $limit KiB/s\n" if $limit;
6578 $storage_limits{$storeid} = $limit * 1024;
6581 foreach my $devname (keys %$devinfo) {
6582 die "found no device mapping information for device '$devname'\n"
6583 if !$devinfo->{$devname}->{virtdev
};
6586 # create empty/temp config
6588 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6589 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6593 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6595 # print restore information to $fifofh
6596 foreach my $virtdev (sort keys %$virtdev_hash) {
6597 my $d = $virtdev_hash->{$virtdev};
6598 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6600 my $storeid = $d->{storeid
};
6601 my $volid = $d->{volid
};
6604 if (my $limit = $storage_limits{$storeid}) {
6605 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6608 my $write_zeros = 1;
6609 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6613 my $path = PVE
::Storage
::path
($cfg, $volid);
6615 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6617 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6620 $fh->seek(0, 0) || die "seek failed - $!\n";
6622 my $cookie = { netcount
=> 0 };
6623 while (defined(my $line = <$fh>)) {
6624 $new_conf_raw .= restore_update_config_line
(
6641 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6642 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6644 $oldtimeout = alarm($timeout);
6651 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6652 my ($dev_id, $size, $devname) = ($1, $2, $3);
6653 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6654 } elsif ($line =~ m/^CTIME: /) {
6655 # we correctly received the vma config, so we can disable
6656 # the timeout now for disk allocation (set to 10 minutes, so
6657 # that we always timeout if something goes wrong)
6660 print $fifofh "done\n";
6661 my $tmp = $oldtimeout || 0;
6662 $oldtimeout = undef;
6669 print "restore vma archive: $dbg_cmdstring\n";
6670 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6674 alarm($oldtimeout) if $oldtimeout;
6676 $restore_deactivate_volumes->($cfg, $devinfo);
6678 close($fifofh) if $fifofh;
6683 $restore_destroy_volumes->($cfg, $devinfo);
6687 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6689 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6691 eval { rescan
($vmid, 1); };
6694 PVE
::AccessControl
::add_vm_to_pool
($vmid, $opts->{pool
}) if $opts->{pool
};
6697 sub restore_tar_archive
{
6698 my ($archive, $vmid, $user, $opts) = @_;
6700 if ($archive ne '-') {
6701 my $firstfile = tar_archive_read_firstfile
($archive);
6702 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
6703 if $firstfile ne 'qemu-server.conf';
6706 my $storecfg = PVE
::Storage
::config
();
6708 # avoid zombie disks when restoring over an existing VM -> cleanup first
6709 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6710 # skiplock=1 because qmrestore has set the 'create' lock itself already
6711 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6712 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6714 my $tocmd = "/usr/lib/qemu-server/qmextract";
6716 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6717 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6718 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6719 $tocmd .= ' --info' if $opts->{info
};
6721 # tar option "xf" does not autodetect compression when read from STDIN,
6722 # so we pipe to zcat
6723 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6724 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6726 my $tmpdir = "/var/tmp/vzdumptmp$$";
6729 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6730 local $ENV{VZDUMP_VMID
} = $vmid;
6731 local $ENV{VZDUMP_USER
} = $user;
6733 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6734 my $new_conf_raw = '';
6736 # disable interrupts (always do cleanups)
6740 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6748 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6750 if ($archive eq '-') {
6751 print "extracting archive from STDIN\n";
6752 run_command
($cmd, input
=> "<&STDIN");
6754 print "extracting archive '$archive'\n";
6758 return if $opts->{info
};
6762 my $statfile = "$tmpdir/qmrestore.stat";
6763 if (my $fd = IO
::File-
>new($statfile, "r")) {
6764 while (defined (my $line = <$fd>)) {
6765 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6766 $map->{$1} = $2 if $1;
6768 print STDERR
"unable to parse line in statfile - $line\n";
6774 my $confsrc = "$tmpdir/qemu-server.conf";
6776 my $srcfd = IO
::File-
>new($confsrc, "r") || die "unable to open file '$confsrc'\n";
6778 my $cookie = { netcount
=> 0 };
6779 while (defined (my $line = <$srcfd>)) {
6780 $new_conf_raw .= restore_update_config_line
(
6791 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6797 PVE
::Tools
::file_set_contents
($conffile, $new_conf_raw);
6799 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6801 eval { rescan
($vmid, 1); };
6805 sub foreach_storage_used_by_vm
{
6806 my ($conf, $func) = @_;
6810 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6811 my ($ds, $drive) = @_;
6812 return if drive_is_cdrom
($drive);
6814 my $volid = $drive->{file
};
6816 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6817 $sidhash->{$sid} = $sid if $sid;
6820 foreach my $sid (sort keys %$sidhash) {
6825 my $qemu_snap_storage = {
6828 sub do_snapshots_with_qemu
{
6829 my ($storecfg, $volid) = @_;
6831 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6832 my $scfg = $storecfg->{ids
}->{$storage_name};
6833 die "could not find storage '$storage_name'\n" if !defined($scfg);
6835 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6839 if ($volid =~ m/\.(qcow2|qed)$/){
6846 sub qga_check_running
{
6847 my ($vmid, $nowarn) = @_;
6849 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6851 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6857 sub template_create
{
6858 my ($vmid, $conf, $disk) = @_;
6860 my $storecfg = PVE
::Storage
::config
();
6862 PVE
::QemuConfig-
>foreach_volume($conf, sub {
6863 my ($ds, $drive) = @_;
6865 return if drive_is_cdrom
($drive);
6866 return if $disk && $ds ne $disk;
6868 my $volid = $drive->{file
};
6869 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6871 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6872 $drive->{file
} = $voliddst;
6873 $conf->{$ds} = print_drive
($drive);
6874 PVE
::QemuConfig-
>write_config($vmid, $conf);
6878 sub convert_iscsi_path
{
6881 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6886 my $initiator_name = get_initiator_name
();
6888 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6889 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6892 die "cannot convert iscsi path '$path', unkown format\n";
6895 sub qemu_img_convert
{
6896 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6898 my $storecfg = PVE
::Storage
::config
();
6899 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6900 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6902 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6906 my $src_is_iscsi = 0;
6910 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6911 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6912 $src_format = qemu_img_format
($src_scfg, $src_volname);
6913 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6914 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6915 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
6916 } elsif (-f
$src_volid) {
6917 $src_path = $src_volid;
6918 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6923 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
6925 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6926 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6927 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6928 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6931 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6932 push @$cmd, '-l', "snapshot.name=$snapname"
6933 if $snapname && $src_format && $src_format eq "qcow2";
6934 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6935 push @$cmd, '-T', $cachemode if defined($cachemode);
6937 if ($src_is_iscsi) {
6938 push @$cmd, '--image-opts';
6939 $src_path = convert_iscsi_path
($src_path);
6940 } elsif ($src_format) {
6941 push @$cmd, '-f', $src_format;
6944 if ($dst_is_iscsi) {
6945 push @$cmd, '--target-image-opts';
6946 $dst_path = convert_iscsi_path
($dst_path);
6948 push @$cmd, '-O', $dst_format;
6951 push @$cmd, $src_path;
6953 if (!$dst_is_iscsi && $is_zero_initialized) {
6954 push @$cmd, "zeroinit:$dst_path";
6956 push @$cmd, $dst_path;
6961 if($line =~ m/\((\S+)\/100\
%\)/){
6963 my $transferred = int($size * $percent / 100);
6964 my $total_h = render_bytes
($size, 1);
6965 my $transferred_h = render_bytes
($transferred, 1);
6967 print "transferred $transferred_h of $total_h ($percent%)\n";
6972 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6974 die "copy failed: $err" if $err;
6977 sub qemu_img_format
{
6978 my ($scfg, $volname) = @_;
6980 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6987 sub qemu_drive_mirror
{
6988 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
6990 $jobs = {} if !$jobs;
6994 $jobs->{"drive-$drive"} = {};
6996 if ($dst_volid =~ /^nbd:/) {
6997 $qemu_target = $dst_volid;
7000 my $storecfg = PVE
::Storage
::config
();
7001 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
7003 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
7005 $format = qemu_img_format
($dst_scfg, $dst_volname);
7007 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
7009 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
7012 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
7013 $opts->{format
} = $format if $format;
7015 if (defined($src_bitmap)) {
7016 $opts->{sync
} = 'incremental';
7017 $opts->{bitmap
} = $src_bitmap;
7018 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7021 if (defined($bwlimit)) {
7022 $opts->{speed
} = $bwlimit * 1024;
7023 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
7025 print "drive mirror is starting for drive-$drive\n";
7028 # if a job already runs for this device we get an error, catch it for cleanup
7029 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
7031 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7033 die "mirroring error: $err\n";
7036 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
7039 # $completion can be either
7040 # 'complete': wait until all jobs are ready, block-job-complete them (default)
7041 # 'cancel': wait until all jobs are ready, block-job-cancel them
7042 # 'skip': wait until all jobs are ready, return with block jobs in ready state
7043 # 'auto': wait until all jobs disappear, only use for jobs which complete automatically
7044 sub qemu_drive_mirror_monitor
{
7045 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
7047 $completion //= 'complete';
7051 my $err_complete = 0;
7053 my $starttime = time ();
7055 die "block job ('$op') timed out\n" if $err_complete > 300;
7057 my $stats = mon_cmd
($vmid, "query-block-jobs");
7060 my $running_jobs = {};
7061 for my $stat (@$stats) {
7062 next if $stat->{type
} ne $op;
7063 $running_jobs->{$stat->{device
}} = $stat;
7066 my $readycounter = 0;
7068 for my $job_id (sort keys %$jobs) {
7069 my $job = $running_jobs->{$job_id};
7071 my $vanished = !defined($job);
7072 my $complete = defined($jobs->{$job_id}->{complete
}) && $vanished;
7073 if($complete || ($vanished && $completion eq 'auto')) {
7074 print "$job_id: $op-job finished\n";
7075 delete $jobs->{$job_id};
7079 die "$job_id: '$op' has been cancelled\n" if !defined($job);
7081 my $busy = $job->{busy
};
7082 my $ready = $job->{ready
};
7083 if (my $total = $job->{len
}) {
7084 my $transferred = $job->{offset
} || 0;
7085 my $remaining = $total - $transferred;
7086 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
7088 my $duration = $ctime - $starttime;
7089 my $total_h = render_bytes
($total, 1);
7090 my $transferred_h = render_bytes
($transferred, 1);
7092 my $status = sprintf(
7093 "transferred $transferred_h of $total_h ($percent%%) in %s",
7094 render_duration
($duration),
7099 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7101 $status .= ", ready";
7104 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready
};
7105 $jobs->{$job_id}->{ready
} = $ready;
7108 $readycounter++ if $job->{ready
};
7111 last if scalar(keys %$jobs) == 0;
7113 if ($readycounter == scalar(keys %$jobs)) {
7114 print "all '$op' jobs are ready\n";
7116 # do the complete later (or has already been done)
7117 last if $completion eq 'skip' || $completion eq 'auto';
7119 if ($vmiddst && $vmiddst != $vmid) {
7120 my $agent_running = $qga && qga_check_running
($vmid);
7121 if ($agent_running) {
7122 print "freeze filesystem\n";
7123 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
7125 print "suspend vm\n";
7126 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
7129 # if we clone a disk for a new target vm, we don't switch the disk
7130 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
7132 if ($agent_running) {
7133 print "unfreeze filesystem\n";
7134 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
7136 print "resume vm\n";
7137 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
7143 for my $job_id (sort keys %$jobs) {
7144 # try to switch the disk if source and destination are on the same guest
7145 print "$job_id: Completing block job_id...\n";
7148 if ($completion eq 'complete') {
7149 $op = 'block-job-complete';
7150 } elsif ($completion eq 'cancel') {
7151 $op = 'block-job-cancel';
7153 die "invalid completion value: $completion\n";
7155 eval { mon_cmd
($vmid, $op, device
=> $job_id) };
7156 if ($@ =~ m/cannot be completed/) {
7157 print "$job_id: block job cannot be completed, trying again.\n";
7160 print "$job_id: Completed successfully.\n";
7161 $jobs->{$job_id}->{complete
} = 1;
7172 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
7173 die "block job ($op) error: $err";
7177 sub qemu_blockjobs_cancel
{
7178 my ($vmid, $jobs) = @_;
7180 foreach my $job (keys %$jobs) {
7181 print "$job: Cancelling block job\n";
7182 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
7183 $jobs->{$job}->{cancel
} = 1;
7187 my $stats = mon_cmd
($vmid, "query-block-jobs");
7189 my $running_jobs = {};
7190 foreach my $stat (@$stats) {
7191 $running_jobs->{$stat->{device
}} = $stat;
7194 foreach my $job (keys %$jobs) {
7196 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
7197 print "$job: Done.\n";
7198 delete $jobs->{$job};
7202 last if scalar(keys %$jobs) == 0;
7209 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7210 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
7215 print "create linked clone of drive $drivename ($drive->{file})\n";
7216 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
7217 push @$newvollist, $newvolid;
7220 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7221 $storeid = $storage if $storage;
7223 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7225 print "create full clone of drive $drivename ($drive->{file})\n";
7228 if (drive_is_cloudinit
($drive)) {
7229 $name = "vm-$newvmid-cloudinit";
7230 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7231 if ($scfg->{path
}) {
7232 $name .= ".$dst_format";
7235 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
7236 } elsif ($drivename eq 'efidisk0') {
7237 $size = get_efivars_size
($conf);
7239 ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 10);
7241 $newvolid = PVE
::Storage
::vdisk_alloc
(
7242 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7244 push @$newvollist, $newvolid;
7246 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7248 if (drive_is_cloudinit
($drive)) {
7249 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7250 # if this is the case, we have to complete any block-jobs still there from
7251 # previous drive-mirrors
7252 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7253 qemu_drive_mirror_monitor
($vmid, $newvmid, $jobs, $completion, $qga);
7258 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7259 if (!$running || $snapname) {
7260 # TODO: handle bwlimits
7261 if ($drivename eq 'efidisk0') {
7262 # the relevant data on the efidisk may be smaller than the source
7263 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7264 # that is given by the OVMF_VARS.fd
7265 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
7266 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
7268 # better for Ceph if block size is not too small, see bug #3324
7271 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=$bs", "osize=$size",
7272 "if=$src_path", "of=$dst_path"]);
7274 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7278 my $kvmver = get_running_qemu_version
($vmid);
7279 if (!min_version
($kvmver, 2, 7)) {
7280 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7281 if $drive->{iothread
};
7284 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7285 $completion, $qga, $bwlimit);
7290 my ($size) = eval { PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 10) };
7293 $disk->{format
} = undef;
7294 $disk->{file
} = $newvolid;
7295 $disk->{size
} = $size if defined($size);
7300 sub get_running_qemu_version
{
7302 my $res = mon_cmd
($vmid, "query-version");
7303 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7306 sub qemu_use_old_bios_files
{
7307 my ($machine_type) = @_;
7309 return if !$machine_type;
7311 my $use_old_bios_files = undef;
7313 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7315 $use_old_bios_files = 1;
7317 my $version = extract_version
($machine_type, kvm_user_version
());
7318 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7319 # load new efi bios files on migration. So this hack is required to allow
7320 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7321 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7322 $use_old_bios_files = !min_version
($version, 2, 4);
7325 return ($use_old_bios_files, $machine_type);
7328 sub get_efivars_size
{
7330 my $arch = get_vm_arch
($conf);
7331 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
7332 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
7333 return -s
$ovmf_vars;
7336 sub update_efidisk_size
{
7339 return if !defined($conf->{efidisk0
});
7341 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
7342 $disk->{size
} = get_efivars_size
($conf);
7343 $conf->{efidisk0
} = print_drive
($disk);
7348 sub create_efidisk
($$$$$) {
7349 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
7351 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
7352 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7354 my $vars_size_b = -s
$ovmf_vars;
7355 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
7356 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7357 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7359 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
7360 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
7362 return ($volid, $size/1024);
7365 sub vm_iothreads_list
{
7368 my $res = mon_cmd
($vmid, 'query-iothreads');
7371 foreach my $iothread (@$res) {
7372 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7379 my ($conf, $drive) = @_;
7383 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7385 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7391 my $controller = int($drive->{index} / $maxdev);
7392 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single')
7396 return ($maxdev, $controller, $controller_prefix);
7399 sub windows_version
{
7402 return 0 if !$ostype;
7406 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7408 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7410 } elsif ($ostype =~ m/^win(\d+)$/) {
7417 sub resolve_dst_disk_format
{
7418 my ($storecfg, $storeid, $src_volname, $format) = @_;
7419 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7422 # if no target format is specified, use the source disk format as hint
7424 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7425 $format = qemu_img_format
($scfg, $src_volname);
7431 # test if requested format is supported - else use default
7432 my $supported = grep { $_ eq $format } @$validFormats;
7433 $format = $defFormat if !$supported;
7437 # NOTE: if this logic changes, please update docs & possibly gui logic
7438 sub find_vmstate_storage
{
7439 my ($conf, $storecfg) = @_;
7441 # first, return storage from conf if set
7442 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
7444 my ($target, $shared, $local);
7446 foreach_storage_used_by_vm
($conf, sub {
7448 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7449 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7450 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7453 # second, use shared storage where VM has at least one disk
7454 # third, use local storage where VM has at least one disk
7455 # fall back to local storage
7456 $target = $shared // $local // 'local';
7462 my ($uuid, $uuid_str);
7463 UUID
::generate
($uuid);
7464 UUID
::unparse
($uuid, $uuid_str);
7468 sub generate_smbios1_uuid
{
7469 return "uuid=".generate_uuid
();
7475 mon_cmd
($vmid, 'nbd-server-stop');
7478 sub create_reboot_request
{
7480 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7481 or die "failed to create reboot trigger file: $!\n";
7485 sub clear_reboot_request
{
7487 my $path = "/run/qemu-server/$vmid.reboot";
7490 $res = unlink($path);
7491 die "could not remove reboot request for $vmid: $!"
7492 if !$res && $! != POSIX
::ENOENT
;
7497 sub bootorder_from_legacy
{
7498 my ($conf, $bootcfg) = @_;
7500 my $boot = $bootcfg->{legacy
} || $boot_fmt->{legacy
}->{default};
7501 my $bootindex_hash = {};
7503 foreach my $o (split(//, $boot)) {
7504 $bootindex_hash->{$o} = $i*100;
7510 PVE
::QemuConfig-
>foreach_volume($conf, sub {
7511 my ($ds, $drive) = @_;
7513 if (drive_is_cdrom
($drive, 1)) {
7514 if ($bootindex_hash->{d
}) {
7515 $bootorder->{$ds} = $bootindex_hash->{d
};
7516 $bootindex_hash->{d
} += 1;
7518 } elsif ($bootindex_hash->{c
}) {
7519 $bootorder->{$ds} = $bootindex_hash->{c
}
7520 if $conf->{bootdisk
} && $conf->{bootdisk
} eq $ds;
7521 $bootindex_hash->{c
} += 1;
7525 if ($bootindex_hash->{n
}) {
7526 for (my $i = 0; $i < $MAX_NETS; $i++) {
7527 my $netname = "net$i";
7528 next if !$conf->{$netname};
7529 $bootorder->{$netname} = $bootindex_hash->{n
};
7530 $bootindex_hash->{n
} += 1;
7537 # Generate default device list for 'boot: order=' property. Matches legacy
7538 # default boot order, but with explicit device names. This is important, since
7539 # the fallback for when neither 'order' nor the old format is specified relies
7540 # on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
7541 sub get_default_bootdevices
{
7547 my $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 0);
7548 push @ret, $first if $first;
7551 $first = PVE
::QemuServer
::Drive
::resolve_first_disk
($conf, 1);
7552 push @ret, $first if $first;
7555 for (my $i = 0; $i < $MAX_NETS; $i++) {
7556 my $netname = "net$i";
7557 next if !$conf->{$netname};
7558 push @ret, $netname;
7565 sub device_bootorder
{
7568 return bootorder_from_legacy
($conf) if !defined($conf->{boot
});
7570 my $boot = parse_property_string
($boot_fmt, $conf->{boot
});
7573 if (!defined($boot) || $boot->{legacy
}) {
7574 $bootorder = bootorder_from_legacy
($conf, $boot);
7575 } elsif ($boot->{order
}) {
7576 my $i = 100; # start at 100 to allow user to insert devices before us with -args
7577 for my $dev (PVE
::Tools
::split_list
($boot->{order
})) {
7578 $bootorder->{$dev} = $i++;
7585 sub register_qmeventd_handle
{
7589 my $peer = "/var/run/qmeventd.sock";
7594 $fh = IO
::Socket
::UNIX-
>new(Peer
=> $peer, Blocking
=> 0, Timeout
=> 1);
7596 if ($! != EINTR
&& $! != EAGAIN
) {
7597 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
7600 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
7601 . "after $count retries\n";
7606 # send handshake to mark VM as backing up
7607 print $fh to_json
({vzdump
=> {vmid
=> "$vmid"}});
7609 # return handle to be closed later when inhibit is no longer required
7613 # bash completion helper
7615 sub complete_backup_archives
{
7616 my ($cmdname, $pname, $cvalue) = @_;
7618 my $cfg = PVE
::Storage
::config
();
7622 if ($cvalue =~ m/^([^:]+):/) {
7626 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7629 foreach my $id (keys %$data) {
7630 foreach my $item (@{$data->{$id}}) {
7631 next if $item->{format
} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
7632 push @$res, $item->{volid
} if defined($item->{volid
});
7639 my $complete_vmid_full = sub {
7642 my $idlist = vmstatus
();
7646 foreach my $id (keys %$idlist) {
7647 my $d = $idlist->{$id};
7648 if (defined($running)) {
7649 next if $d->{template
};
7650 next if $running && $d->{status
} ne 'running';
7651 next if !$running && $d->{status
} eq 'running';
7660 return &$complete_vmid_full();
7663 sub complete_vmid_stopped
{
7664 return &$complete_vmid_full(0);
7667 sub complete_vmid_running
{
7668 return &$complete_vmid_full(1);
7671 sub complete_storage
{
7673 my $cfg = PVE
::Storage
::config
();
7674 my $ids = $cfg->{ids
};
7677 foreach my $sid (keys %$ids) {
7678 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7679 next if !$ids->{$sid}->{content
}->{images
};
7686 sub complete_migration_storage
{
7687 my ($cmd, $param, $current_value, $all_args) = @_;
7689 my $targetnode = @$all_args[1];
7691 my $cfg = PVE
::Storage
::config
();
7692 my $ids = $cfg->{ids
};
7695 foreach my $sid (keys %$ids) {
7696 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7697 next if !$ids->{$sid}->{content
}->{images
};
7706 my $qmpstatus = eval {
7707 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid);
7708 mon_cmd
($vmid, "query-status");
7711 return $qmpstatus && $qmpstatus->{status
} eq "paused";