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 cfs_lock_file);
30 use PVE
::DataCenterConfig
;
31 use PVE
::Exception
qw(raise raise_param_exc);
32 use PVE
::GuestHelpers
qw(safe_string_ne safe_num_ne safe_boolean_ne);
34 use PVE
::JSONSchema
qw(get_standard_option);
36 use PVE
::RPCEnvironment
;
40 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
44 use PVE
::QemuServer
::Helpers
qw(min_version config_aware_timeout);
45 use PVE
::QemuServer
::Cloudinit
;
46 use PVE
::QemuServer
::CPUConfig
qw(print_cpu_device get_cpu_options);
47 use PVE
::QemuServer
::Drive
qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom parse_drive print_drive foreach_drive foreach_volid);
48 use PVE
::QemuServer
::Machine
;
49 use PVE
::QemuServer
::Memory
;
50 use PVE
::QemuServer
::Monitor
qw(mon_cmd);
51 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr print_pcie_root_port);
52 use PVE
::QemuServer
::USB
qw(parse_usb_device);
56 require PVE
::Network
::SDN
::Zones
;
60 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
63 "$EDK2_FW_BASE/OVMF_CODE.fd",
64 "$EDK2_FW_BASE/OVMF_VARS.fd"
67 "$EDK2_FW_BASE/AAVMF_CODE.fd",
68 "$EDK2_FW_BASE/AAVMF_VARS.fd"
72 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
74 # Note about locking: we use flock on the config file protect
75 # against concurent actions.
76 # Aditionaly, we have a 'lock' setting in the config file. This
77 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
78 # allowed when such lock is set. But you can ignore this kind of
79 # lock with the --skiplock flag.
81 cfs_register_file
('/qemu-server/',
85 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
86 description
=> "Some command save/restore state from this location.",
92 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
93 description
=> "Specifies the Qemu machine type.",
95 pattern
=> '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
100 #no warnings 'redefine';
103 my ($controller, $vmid, $option, $value) = @_;
105 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
106 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
112 $nodename_cache //= PVE
::INotify
::nodename
();
113 return $nodename_cache;
120 enum
=> [qw(i6300esb ib700)],
121 description
=> "Watchdog type to emulate.",
122 default => 'i6300esb',
127 enum
=> [qw(reset shutdown poweroff pause debug none)],
128 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
132 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
136 description
=> "Enable/disable Qemu GuestAgent.",
141 fstrim_cloned_disks
=> {
142 description
=> "Run fstrim after cloning/moving a disk.",
148 description
=> "Select the agent type",
152 enum
=> [qw(virtio isa)],
158 description
=> "Select the VGA type.",
163 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
166 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
178 description
=> "The size of the file in MB.",
182 pattern
=> '[a-zA-Z0-9\-]+',
184 format_description
=> 'string',
185 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
192 enum
=> [qw(ich9-intel-hda intel-hda AC97)],
193 description
=> "Configure an audio device."
200 description
=> "Driver backend for the audio device."
204 my $spice_enhancements_fmt = {
209 description
=> "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
213 enum
=> ['off', 'all', 'filter'],
216 description
=> "Enable video streaming. Uses compression for detected video streams."
223 enum
=> ['/dev/urandom', '/dev/random', '/dev/hwrng'],
225 description
=> "The file on the host to gather entropy from. In most"
226 . " cases /dev/urandom should be preferred over /dev/random"
227 . " to avoid entropy-starvation issues on the host. Using"
228 . " urandom does *not* decrease security in any meaningful"
229 . " way, as it's still seeded from real entropy, and the"
230 . " bytes provided will most likely be mixed with real"
231 . " entropy on the guest as well. /dev/hwrng can be used"
232 . " to pass through a hardware RNG from the host.",
236 description
=> "Maximum bytes of entropy injected into the guest every"
237 . " 'period' milliseconds. Prefer a lower value when using"
238 . " /dev/random as source. Use 0 to disable limiting"
239 . " (potentially dangerous!).",
242 # default is 1 KiB/s, provides enough entropy to the guest to avoid
243 # boot-starvation issues (e.g. systemd etc...) while allowing no chance
244 # of overwhelming the host, provided we're reading from /dev/urandom
249 description
=> "Every 'period' milliseconds the entropy-injection quota"
250 . " is reset, allowing the guest to retrieve another"
251 . " 'max_bytes' of entropy.",
261 description
=> "Specifies whether a VM will be started during system bootup.",
267 description
=> "Automatic restart after crash (currently ignored).",
272 type
=> 'string', format
=> 'pve-hotplug-features',
273 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'.",
274 default => 'network,disk,usb',
279 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
285 description
=> "Lock/unlock the VM.",
286 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
291 description
=> "Limit of CPU usage.",
292 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.",
300 description
=> "CPU weight for a VM.",
301 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.",
309 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
316 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
322 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.",
330 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
331 "It should not be necessary to set it.",
332 enum
=> PVE
::Tools
::kvmkeymaplist
(),
337 type
=> 'string', format
=> 'dns-name',
338 description
=> "Set a name for the VM. Only used on the configuration web interface.",
343 description
=> "SCSI controller model",
344 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
350 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
355 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
356 description
=> "Specify guest operating system.",
357 verbose_description
=> <<EODESC,
358 Specify guest operating system. This is used to enable special
359 optimization/features for specific operating systems:
362 other;; unspecified OS
363 wxp;; Microsoft Windows XP
364 w2k;; Microsoft Windows 2000
365 w2k3;; Microsoft Windows 2003
366 w2k8;; Microsoft Windows 2008
367 wvista;; Microsoft Windows Vista
368 win7;; Microsoft Windows 7
369 win8;; Microsoft Windows 8/2012/2012r2
370 win10;; Microsoft Windows 10/2016
371 l24;; Linux 2.4 Kernel
372 l26;; Linux 2.6 - 5.X Kernel
373 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
379 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
380 pattern
=> '[acdn]{1,4}',
385 type
=> 'string', format
=> 'pve-qm-bootdisk',
386 description
=> "Enable booting from specified disk.",
387 pattern
=> '(ide|sata|scsi|virtio)\d+',
392 description
=> "The number of CPUs. Please use option -sockets instead.",
399 description
=> "The number of CPU sockets.",
406 description
=> "The number of cores per socket.",
413 description
=> "Enable/disable NUMA.",
419 description
=> "Enable/disable hugepages memory.",
420 enum
=> [qw(any 2 1024)],
425 description
=> "Number of hotplugged vcpus.",
432 description
=> "Enable/disable ACPI.",
437 description
=> "Enable/disable Qemu GuestAgent and its properties.",
439 format
=> $agent_fmt,
444 description
=> "Enable/disable KVM hardware virtualization.",
450 description
=> "Enable/disable time drift fix.",
456 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
461 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
465 type
=> 'string', format
=> $vga_fmt,
466 description
=> "Configure the VGA hardware.",
467 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
468 "high resolution modes (>= 1280x1024x16) you may need to increase " .
469 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
470 "is 'std' for all OS types besides some Windows versions (XP and " .
471 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
472 "display server. For win* OS you can select how many independent " .
473 "displays you want, Linux guests can add displays them self.\n".
474 "You can also run without any graphic card, using a serial device as terminal.",
478 type
=> 'string', format
=> 'pve-qm-watchdog',
479 description
=> "Create a virtual hardware watchdog device.",
480 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
481 " (by a guest action), the watchdog must be periodically polled " .
482 "by an agent inside the guest or else the watchdog will reset " .
483 "the guest (or execute the respective action specified)",
488 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
489 description
=> "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
490 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
493 startup
=> get_standard_option
('pve-startup-order'),
497 description
=> "Enable/disable Template.",
503 description
=> "Arbitrary arguments passed to kvm.",
504 verbose_description
=> <<EODESCR,
505 Arbitrary arguments passed to kvm, for example:
507 args: -no-reboot -no-hpet
509 NOTE: this option is for experts only.
516 description
=> "Enable/disable the USB tablet device.",
517 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
518 "usually needed to allow absolute mouse positioning with VNC. " .
519 "Else the mouse runs out of sync with normal VNC clients. " .
520 "If you're running lots of console-only guests on one host, " .
521 "you may consider disabling this to save some context switches. " .
522 "This is turned off by default if you use spice (-vga=qxl).",
527 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
531 migrate_downtime
=> {
534 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
540 type
=> 'string', format
=> 'pve-qm-ide',
541 typetext
=> '<volume>',
542 description
=> "This is an alias for option -ide2",
546 description
=> "Emulated CPU type.",
548 format
=> 'pve-vm-cpu-conf',
550 parent
=> get_standard_option
('pve-snapshot-name', {
552 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
556 description
=> "Timestamp for snapshots.",
562 type
=> 'string', format
=> 'pve-volume-id',
563 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
565 vmstatestorage
=> get_standard_option
('pve-storage-id', {
566 description
=> "Default storage for VM state volumes/files.",
569 runningmachine
=> get_standard_option
('pve-qemu-machine', {
570 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
572 machine
=> get_standard_option
('pve-qemu-machine'),
574 description
=> "Virtual processor architecture. Defaults to the host.",
577 enum
=> [qw(x86_64 aarch64)],
580 description
=> "Specify SMBIOS type 1 fields.",
581 type
=> 'string', format
=> 'pve-qm-smbios1',
588 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
594 enum
=> [ qw(seabios ovmf) ],
595 description
=> "Select BIOS implementation.",
596 default => 'seabios',
600 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
601 format_description
=> 'UUID',
602 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
603 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
604 " 128-bit integer value identifier to the guest OS. This allows to".
605 " notify the guest operating system when the virtual machine is".
606 " executed with a different configuration (e.g. snapshot execution".
607 " or creation from a template). The guest operating system notices".
608 " the change, and is then able to react as appropriate by marking".
609 " its copies of distributed databases as dirty, re-initializing its".
610 " random number generator, etc.\n".
611 "Note that auto-creation only works when done throug API/CLI create".
612 " or update methods, but not when manually editing the config file.",
613 default => "1 (autogenerated)",
618 format
=> 'pve-volume-id',
620 description
=> "Script that will be executed during various steps in the vms lifetime.",
624 format
=> $ivshmem_fmt,
625 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
630 format
=> $audio_fmt,
631 description
=> "Configure a audio device, useful in combination with QXL/Spice.",
634 spice_enhancements
=> {
636 format
=> $spice_enhancements_fmt,
637 description
=> "Configure additional enhancements for SPICE.",
641 type
=> 'string', format
=> 'pve-tag-list',
642 description
=> 'Tags of the VM. This is only meta information.',
648 description
=> "Configure a VirtIO-based Random Number Generator.",
657 description
=> 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
658 format
=> 'pve-volume-id',
659 format_description
=> 'volume',
664 description
=> 'Specify a custom file containing all network data passed to the VM via cloud-init.',
665 format
=> 'pve-volume-id',
666 format_description
=> 'volume',
671 description
=> 'Specify a custom file containing all user data passed to the VM via cloud-init.',
672 format
=> 'pve-volume-id',
673 format_description
=> 'volume',
676 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
678 my $confdesc_cloudinit = {
682 description
=> 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
683 enum
=> ['configdrive2', 'nocloud'],
688 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
693 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
698 description
=> 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
699 format
=> 'pve-qm-cicustom',
704 description
=> "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
708 type
=> 'string', format
=> 'address-list',
709 description
=> "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
714 format
=> 'urlencoded',
715 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
719 # what about other qemu settings ?
721 #machine => 'string',
734 ##soundhw => 'string',
736 while (my ($k, $v) = each %$confdesc) {
737 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
740 my $MAX_USB_DEVICES = 5;
742 my $MAX_HOSTPCI_DEVICES = 16;
743 my $MAX_SERIAL_PORTS = 4;
744 my $MAX_PARALLEL_PORTS = 3;
750 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
751 description
=> "CPUs accessing this NUMA node.",
752 format_description
=> "id[-id];...",
756 description
=> "Amount of memory this NUMA node provides.",
761 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
762 description
=> "Host NUMA nodes to use.",
763 format_description
=> "id[-id];...",
768 enum
=> [qw(preferred bind interleave)],
769 description
=> "NUMA allocation policy.",
773 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
776 type
=> 'string', format
=> $numa_fmt,
777 description
=> "NUMA topology.",
779 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
781 for (my $i = 0; $i < $MAX_NUMA; $i++) {
782 $confdesc->{"numa$i"} = $numadesc;
785 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
786 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
787 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
788 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
790 my $net_fmt_bridge_descr = <<__EOD__;
791 Bridge to attach the network device to. The Proxmox VE standard bridge
794 If you do not specify a bridge, we create a kvm user (NATed) network
795 device, which provides DHCP and DNS services. The following addresses
802 The DHCP server assign addresses to the guest starting from 10.0.2.15.
806 macaddr
=> get_standard_option
('mac-addr', {
807 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
811 description
=> "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
812 enum
=> $nic_model_list,
815 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
818 description
=> $net_fmt_bridge_descr,
819 format_description
=> 'bridge',
824 minimum
=> 0, maximum
=> 16,
825 description
=> 'Number of packet queues to be used on the device.',
831 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
836 minimum
=> 1, maximum
=> 4094,
837 description
=> 'VLAN tag to apply to packets on this interface.',
842 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
843 description
=> 'VLAN trunks to pass through this interface.',
844 format_description
=> 'vlanid[;vlanid...]',
849 description
=> 'Whether this interface should be protected by the firewall.',
854 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
861 type
=> 'string', format
=> $net_fmt,
862 description
=> "Specify network devices.",
865 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
870 format
=> 'pve-ipv4-config',
871 format_description
=> 'IPv4Format/CIDR',
872 description
=> 'IPv4 address in CIDR format.',
879 format_description
=> 'GatewayIPv4',
880 description
=> 'Default gateway for IPv4 traffic.',
886 format
=> 'pve-ipv6-config',
887 format_description
=> 'IPv6Format/CIDR',
888 description
=> 'IPv6 address in CIDR format.',
895 format_description
=> 'GatewayIPv6',
896 description
=> 'Default gateway for IPv6 traffic.',
901 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
904 type
=> 'string', format
=> 'pve-qm-ipconfig',
905 description
=> <<'EODESCR',
906 cloud-init: Specify IP addresses and gateways for the corresponding interface.
908 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
910 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
911 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
913 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
916 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
918 for (my $i = 0; $i < $MAX_NETS; $i++) {
919 $confdesc->{"net$i"} = $netdesc;
920 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
923 foreach my $key (keys %$confdesc_cloudinit) {
924 $confdesc->{$key} = $confdesc_cloudinit->{$key};
927 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
928 sub verify_volume_id_or_qm_path
{
929 my ($volid, $noerr) = @_;
931 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
935 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
936 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
938 return undef if $noerr;
947 type
=> 'string', format
=> 'pve-qm-usb-device',
948 format_description
=> 'HOSTUSBDEVICE|spice',
949 description
=> <<EODESCR,
950 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
952 'bus-port(.port)*' (decimal numbers) or
953 'vendor_id:product_id' (hexadeciaml numbers) or
956 You can use the 'lsusb -t' command to list existing usb devices.
958 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
960 The value 'spice' can be used to add a usb redirection devices for spice.
966 description
=> "Specifies whether if given host option is a USB3 device or port.",
973 type
=> 'string', format
=> $usb_fmt,
974 description
=> "Configure an USB device (n is 0 to 4).",
976 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
978 my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
983 pattern
=> qr/$PCIRE(;$PCIRE)*/,
984 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
985 description
=> <<EODESCR,
986 Host PCI device pass through. The PCI ID of a host's PCI device or a list
987 of PCI virtual functions of the host. HOSTPCIID syntax is:
989 'bus:dev.func' (hexadecimal numbers)
991 You can us the 'lspci' command to list existing PCI devices.
996 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1002 pattern
=> '[^,;]+',
1003 format_description
=> 'string',
1004 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1009 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1015 description
=> "Enable vfio-vga device support.",
1021 format_description
=> 'string',
1022 pattern
=> '[^/\.:]+',
1024 description
=> <<EODESCR
1025 The type of mediated device to use.
1026 An instance of this type will be created on startup of the VM and
1027 will be cleaned up when the VM stops.
1031 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1035 type
=> 'string', format
=> 'pve-qm-hostpci',
1036 description
=> "Map host PCI devices into guest.",
1037 verbose_description
=> <<EODESCR,
1038 Map host PCI devices into guest.
1040 NOTE: This option allows direct access to host hardware. So it is no longer
1041 possible to migrate such machines - use with special care.
1043 CAUTION: Experimental! User reported problems with this option.
1046 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1051 pattern
=> '(/dev/.+|socket)',
1052 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1053 verbose_description
=> <<EODESCR,
1054 Create a serial device inside the VM (n is 0 to 3), and pass through a
1055 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1056 host side (use 'qm terminal' to open a terminal connection).
1058 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1060 CAUTION: Experimental! User reported problems with this option.
1067 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1068 description
=> "Map host parallel devices (n is 0 to 2).",
1069 verbose_description
=> <<EODESCR,
1070 Map host parallel devices (n is 0 to 2).
1072 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1074 CAUTION: Experimental! User reported problems with this option.
1078 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1079 $confdesc->{"parallel$i"} = $paralleldesc;
1082 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1083 $confdesc->{"serial$i"} = $serialdesc;
1086 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1087 $confdesc->{"hostpci$i"} = $hostpcidesc;
1090 for my $key (keys %{$PVE::QemuServer
::Drive
::drivedesc_hash
}) {
1091 $confdesc->{$key} = $PVE::QemuServer
::Drive
::drivedesc_hash-
>{$key};
1094 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1095 $confdesc->{"usb$i"} = $usbdesc;
1098 my $kvm_api_version = 0;
1101 return $kvm_api_version if $kvm_api_version;
1103 open my $fh, '<', '/dev/kvm'
1106 # 0xae00 => KVM_GET_API_VERSION
1107 $kvm_api_version = ioctl($fh, 0xae00, 0);
1109 return $kvm_api_version;
1112 my $kvm_user_version = {};
1115 sub kvm_user_version
{
1118 $binary //= get_command_for_arch
(get_host_arch
()); # get the native arch by default
1119 my $st = stat($binary);
1121 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1122 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1123 $cachedmtime == $st->mtime;
1125 $kvm_user_version->{$binary} = 'unknown';
1126 $kvm_mtime->{$binary} = $st->mtime;
1130 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1131 $kvm_user_version->{$binary} = $2;
1135 eval { run_command
([$binary, '--version'], outfunc
=> $code); };
1138 return $kvm_user_version->{$binary};
1142 sub kernel_has_vhost_net
{
1143 return -c
'/dev/vhost-net';
1148 return defined($confdesc->{$key});
1152 sub get_cdrom_path
{
1154 return $cdrom_path if $cdrom_path;
1156 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1157 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1158 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1162 my ($storecfg, $vmid, $cdrom) = @_;
1164 if ($cdrom eq 'cdrom') {
1165 return get_cdrom_path
();
1166 } elsif ($cdrom eq 'none') {
1168 } elsif ($cdrom =~ m
|^/|) {
1171 return PVE
::Storage
::path
($storecfg, $cdrom);
1175 # try to convert old style file names to volume IDs
1176 sub filename_to_volume_id
{
1177 my ($vmid, $file, $media) = @_;
1179 if (!($file eq 'none' || $file eq 'cdrom' ||
1180 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1182 return undef if $file =~ m
|/|;
1184 if ($media && $media eq 'cdrom') {
1185 $file = "local:iso/$file";
1187 $file = "local:$vmid/$file";
1194 sub verify_media_type
{
1195 my ($opt, $vtype, $media) = @_;
1200 if ($media eq 'disk') {
1202 } elsif ($media eq 'cdrom') {
1205 die "internal error";
1208 return if ($vtype eq $etype);
1210 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1213 sub cleanup_drive_path
{
1214 my ($opt, $storecfg, $drive) = @_;
1216 # try to convert filesystem paths to volume IDs
1218 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1219 ($drive->{file
} !~ m
|^/dev/.+|) &&
1220 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1221 ($drive->{file
} !~ m/^\d+$/)) {
1222 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1223 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1224 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1225 verify_media_type
($opt, $vtype, $drive->{media
});
1226 $drive->{file
} = $volid;
1229 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1232 sub parse_hotplug_features
{
1237 return $res if $data eq '0';
1239 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1241 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1242 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1245 die "invalid hotplug feature '$feature'\n";
1251 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1252 sub pve_verify_hotplug_features
{
1253 my ($value, $noerr) = @_;
1255 return $value if parse_hotplug_features
($value);
1257 return undef if $noerr;
1259 die "unable to parse hotplug option\n";
1263 my($fh, $noerr) = @_;
1266 my $SG_GET_VERSION_NUM = 0x2282;
1268 my $versionbuf = "\x00" x
8;
1269 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1271 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1274 my $version = unpack("I", $versionbuf);
1275 if ($version < 30000) {
1276 die "scsi generic interface too old\n" if !$noerr;
1280 my $buf = "\x00" x
36;
1281 my $sensebuf = "\x00" x
8;
1282 my $cmd = pack("C x3 C x1", 0x12, 36);
1284 # see /usr/include/scsi/sg.h
1285 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";
1287 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1288 length($sensebuf), 0, length($buf), $buf,
1289 $cmd, $sensebuf, 6000);
1291 $ret = ioctl($fh, $SG_IO, $packet);
1293 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1297 my @res = unpack($sg_io_hdr_t, $packet);
1298 if ($res[17] || $res[18]) {
1299 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1304 (my $byte0, my $byte1, $res->{vendor
},
1305 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1307 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1308 $res->{type
} = $byte0 & 31;
1316 my $fh = IO
::File-
>new("+<$path") || return undef;
1317 my $res = scsi_inquiry
($fh, 1);
1323 sub print_tabletdevice_full
{
1324 my ($conf, $arch) = @_;
1326 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1328 # we use uhci for old VMs because tablet driver was buggy in older qemu
1330 if (PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1336 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1339 sub print_keyboarddevice_full
{
1340 my ($conf, $arch, $machine) = @_;
1342 return undef if $arch ne 'aarch64';
1344 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1347 sub print_drivedevice_full
{
1348 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1353 if ($drive->{interface
} eq 'virtio') {
1354 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1355 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1356 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1357 } elsif ($drive->{interface
} eq 'scsi') {
1359 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1360 my $unit = $drive->{index} % $maxdev;
1361 my $devicetype = 'hd';
1363 if (drive_is_cdrom
($drive)) {
1366 if ($drive->{file
} =~ m
|^/|) {
1367 $path = $drive->{file
};
1368 if (my $info = path_is_scsi
($path)) {
1369 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1370 $devicetype = 'block';
1371 } elsif ($info->{type
} == 1) { # tape
1372 $devicetype = 'generic';
1376 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1379 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
1380 my $version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, kvm_user_version
());
1381 if ($path =~ m/^iscsi\:\/\
// &&
1382 !min_version
($version, 4, 1)) {
1383 $devicetype = 'generic';
1387 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1388 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1390 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1393 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1394 $device .= ",rotation_rate=1";
1396 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1398 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1399 my $maxdev = ($drive->{interface
} eq 'sata') ?
$PVE::QemuServer
::Drive
::MAX_SATA_DISKS
: 2;
1400 my $controller = int($drive->{index} / $maxdev);
1401 my $unit = $drive->{index} % $maxdev;
1402 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1404 $device = "ide-$devicetype";
1405 if ($drive->{interface
} eq 'ide') {
1406 $device .= ",bus=ide.$controller,unit=$unit";
1408 $device .= ",bus=ahci$controller.$unit";
1410 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1412 if ($devicetype eq 'hd') {
1413 if (my $model = $drive->{model
}) {
1414 $model = URI
::Escape
::uri_unescape
($model);
1415 $device .= ",model=$model";
1417 if ($drive->{ssd
}) {
1418 $device .= ",rotation_rate=1";
1421 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1422 } elsif ($drive->{interface
} eq 'usb') {
1424 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1426 die "unsupported interface type";
1429 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1431 if (my $serial = $drive->{serial
}) {
1432 $serial = URI
::Escape
::uri_unescape
($serial);
1433 $device .= ",serial=$serial";
1440 sub get_initiator_name
{
1443 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1444 while (defined(my $line = <$fh>)) {
1445 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1454 sub print_drive_commandline_full
{
1455 my ($storecfg, $vmid, $drive) = @_;
1458 my $volid = $drive->{file
};
1461 if (drive_is_cdrom
($drive)) {
1462 $path = get_iso_path
($storecfg, $vmid, $volid);
1464 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1466 $path = PVE
::Storage
::path
($storecfg, $volid);
1467 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1468 $format = qemu_img_format
($scfg, $volname);
1476 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1477 foreach my $o (@qemu_drive_options) {
1478 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1481 # snapshot only accepts on|off
1482 if (defined($drive->{snapshot
})) {
1483 my $v = $drive->{snapshot
} ?
'on' : 'off';
1484 $opts .= ",snapshot=$v";
1487 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1488 my ($dir, $qmpname) = @$type;
1489 if (my $v = $drive->{"mbps$dir"}) {
1490 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1492 if (my $v = $drive->{"mbps${dir}_max"}) {
1493 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1495 if (my $v = $drive->{"bps${dir}_max_length"}) {
1496 $opts .= ",throttling.bps$qmpname-max-length=$v";
1498 if (my $v = $drive->{"iops${dir}"}) {
1499 $opts .= ",throttling.iops$qmpname=$v";
1501 if (my $v = $drive->{"iops${dir}_max"}) {
1502 $opts .= ",throttling.iops$qmpname-max=$v";
1504 if (my $v = $drive->{"iops${dir}_max_length"}) {
1505 $opts .= ",throttling.iops$qmpname-max-length=$v";
1509 $opts .= ",format=$format" if $format && !$drive->{format
};
1511 my $cache_direct = 0;
1513 if (my $cache = $drive->{cache
}) {
1514 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1515 } elsif (!drive_is_cdrom
($drive)) {
1516 $opts .= ",cache=none";
1520 # aio native works only with O_DIRECT
1521 if (!$drive->{aio
}) {
1523 $opts .= ",aio=native";
1525 $opts .= ",aio=threads";
1529 if (!drive_is_cdrom
($drive)) {
1531 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1532 $detectzeroes = 'off';
1533 } elsif ($drive->{discard
}) {
1534 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1536 # This used to be our default with discard not being specified:
1537 $detectzeroes = 'on';
1539 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1542 my $pathinfo = $path ?
"file=$path," : '';
1544 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1547 sub print_netdevice_full
{
1548 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1550 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1552 my $device = $net->{model
};
1553 if ($net->{model
} eq 'virtio') {
1554 $device = 'virtio-net-pci';
1557 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1558 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1559 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1560 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1561 my $vectors = $net->{queues
} * 2 + 2;
1562 $tmpstr .= ",vectors=$vectors,mq=on";
1564 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1566 if ($use_old_bios_files) {
1568 if ($device eq 'virtio-net-pci') {
1569 $romfile = 'pxe-virtio.rom';
1570 } elsif ($device eq 'e1000') {
1571 $romfile = 'pxe-e1000.rom';
1572 } elsif ($device eq 'ne2k') {
1573 $romfile = 'pxe-ne2k_pci.rom';
1574 } elsif ($device eq 'pcnet') {
1575 $romfile = 'pxe-pcnet.rom';
1576 } elsif ($device eq 'rtl8139') {
1577 $romfile = 'pxe-rtl8139.rom';
1579 $tmpstr .= ",romfile=$romfile" if $romfile;
1585 sub print_netdev_full
{
1586 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1589 if ($netid =~ m/^net(\d+)$/) {
1593 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1595 my $ifname = "tap${vmid}i$i";
1597 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1598 die "interface name '$ifname' is too long (max 15 character)\n"
1599 if length($ifname) >= 16;
1601 my $vhostparam = '';
1602 if (is_native
($arch)) {
1603 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1606 my $vmname = $conf->{name
} || "vm$vmid";
1609 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1611 if ($net->{bridge
}) {
1612 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1614 $netdev = "type=user,id=$netid,hostname=$vmname";
1617 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1623 'cirrus' => 'cirrus-vga',
1625 'vmware' => 'vmware-svga',
1626 'virtio' => 'virtio-vga',
1629 sub print_vga_device
{
1630 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
1632 my $type = $vga_map->{$vga->{type
}};
1633 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
1634 $type = 'virtio-gpu';
1636 my $vgamem_mb = $vga->{memory
};
1638 my $max_outputs = '';
1640 $type = $id ?
'qxl' : 'qxl-vga';
1642 if (!$conf->{ostype
} || $conf->{ostype
} =~ m/^(?:l\d\d)|(?:other)$/) {
1643 # set max outputs so linux can have up to 4 qxl displays with one device
1644 if (min_version
($machine_version, 4, 1)) {
1645 $max_outputs = ",max_outputs=4";
1650 die "no devicetype for $vga->{type}\n" if !$type;
1654 if ($vga->{type
} eq 'virtio') {
1655 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
1656 $memory = ",max_hostmem=$bytes";
1658 # from https://www.spice-space.org/multiple-monitors.html
1659 $memory = ",vgamem_mb=$vga->{memory}";
1660 my $ram = $vgamem_mb * 4;
1661 my $vram = $vgamem_mb * 2;
1662 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1664 $memory = ",vgamem_mb=$vga->{memory}";
1666 } elsif ($qxlnum && $id) {
1667 $memory = ",ram_size=67108864,vram_size=33554432";
1670 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
1671 my $vgaid = "vga" . ($id // '');
1674 if ($q35 && $vgaid eq 'vga') {
1675 # the first display uses pcie.0 bus on q35 machines
1676 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
1678 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
1681 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}";
1684 sub parse_number_sets
{
1687 foreach my $part (split(/;/, $set)) {
1688 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1689 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1690 push @$res, [ $1, $2 ];
1692 die "invalid range: $part\n";
1701 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1702 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1703 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1710 return undef if !$value;
1712 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1714 my @idlist = split(/;/, $res->{host
});
1715 delete $res->{host
};
1716 foreach my $id (@idlist) {
1717 my $devs = PVE
::SysFSTools
::lspci
($id);
1718 die "no PCI device found for '$id'\n" if !scalar(@$devs);
1719 push @{$res->{pciid
}}, @$devs;
1724 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1728 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1733 if (!defined($res->{macaddr
})) {
1734 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1735 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1740 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1741 sub parse_ipconfig
{
1744 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1750 if ($res->{gw
} && !$res->{ip
}) {
1751 warn 'gateway specified without specifying an IP address';
1754 if ($res->{gw6
} && !$res->{ip6
}) {
1755 warn 'IPv6 gateway specified without specifying an IPv6 address';
1758 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1759 warn 'gateway specified together with DHCP';
1762 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
1764 warn "IPv6 gateway specified together with $res->{ip6} address";
1768 if (!$res->{ip
} && !$res->{ip6
}) {
1769 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
1778 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1781 sub add_random_macs
{
1782 my ($settings) = @_;
1784 foreach my $opt (keys %$settings) {
1785 next if $opt !~ m/^net(\d+)$/;
1786 my $net = parse_net
($settings->{$opt});
1788 $settings->{$opt} = print_net
($net);
1792 sub vm_is_volid_owner
{
1793 my ($storecfg, $vmid, $volid) = @_;
1795 if ($volid !~ m
|^/|) {
1797 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1798 if ($owner && ($owner == $vmid)) {
1806 sub vmconfig_register_unused_drive
{
1807 my ($storecfg, $vmid, $conf, $drive) = @_;
1809 if (drive_is_cloudinit
($drive)) {
1810 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
1812 } elsif (!drive_is_cdrom
($drive)) {
1813 my $volid = $drive->{file
};
1814 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1815 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1820 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
1824 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1825 format_description
=> 'UUID',
1826 description
=> "Set SMBIOS1 UUID.",
1831 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1832 format_description
=> 'Base64 encoded string',
1833 description
=> "Set SMBIOS1 version.",
1838 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1839 format_description
=> 'Base64 encoded string',
1840 description
=> "Set SMBIOS1 serial number.",
1845 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1846 format_description
=> 'Base64 encoded string',
1847 description
=> "Set SMBIOS1 manufacturer.",
1852 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1853 format_description
=> 'Base64 encoded string',
1854 description
=> "Set SMBIOS1 product ID.",
1859 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1860 format_description
=> 'Base64 encoded string',
1861 description
=> "Set SMBIOS1 SKU string.",
1866 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
1867 format_description
=> 'Base64 encoded string',
1868 description
=> "Set SMBIOS1 family string.",
1873 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
1881 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
1888 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
1891 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
1893 sub parse_watchdog
{
1896 return undef if !$value;
1898 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
1903 sub parse_guest_agent
{
1906 return {} if !defined($value->{agent
});
1908 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
1911 # if the agent is disabled ignore the other potentially set properties
1912 return {} if !$res->{enabled
};
1919 return {} if !$value;
1920 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
1928 return undef if !$value;
1930 my $res = eval { PVE
::JSONSchema
::parse_property_string
($rng_fmt, $value) };
1935 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1936 sub verify_usb_device
{
1937 my ($value, $noerr) = @_;
1939 return $value if parse_usb_device
($value);
1941 return undef if $noerr;
1943 die "unable to parse usb device\n";
1946 # add JSON properties for create and set function
1947 sub json_config_properties
{
1950 foreach my $opt (keys %$confdesc) {
1951 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
1952 $prop->{$opt} = $confdesc->{$opt};
1958 # return copy of $confdesc_cloudinit to generate documentation
1959 sub cloudinit_config_properties
{
1961 return dclone
($confdesc_cloudinit);
1965 my ($key, $value) = @_;
1967 die "unknown setting '$key'\n" if !$confdesc->{$key};
1969 my $type = $confdesc->{$key}->{type
};
1971 if (!defined($value)) {
1972 die "got undefined value\n";
1975 if ($value =~ m/[\n\r]/) {
1976 die "property contains a line feed\n";
1979 if ($type eq 'boolean') {
1980 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1981 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1982 die "type check ('boolean') failed - got '$value'\n";
1983 } elsif ($type eq 'integer') {
1984 return int($1) if $value =~ m/^(\d+)$/;
1985 die "type check ('integer') failed - got '$value'\n";
1986 } elsif ($type eq 'number') {
1987 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
1988 die "type check ('number') failed - got '$value'\n";
1989 } elsif ($type eq 'string') {
1990 if (my $fmt = $confdesc->{$key}->{format
}) {
1991 PVE
::JSONSchema
::check_format
($fmt, $value);
1994 $value =~ s/^\"(.*)\"$/$1/;
1997 die "internal error"
2002 my ($storecfg, $vmid, $skiplock, $replacement_conf) = @_;
2004 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2006 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2008 if ($conf->{template
}) {
2009 # check if any base image is still used by a linked clone
2010 foreach_drive
($conf, sub {
2011 my ($ds, $drive) = @_;
2012 return if drive_is_cdrom
($drive);
2014 my $volid = $drive->{file
};
2015 return if !$volid || $volid =~ m
|^/|;
2017 die "base volume '$volid' is still in use by linked cloned\n"
2018 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2023 # only remove disks owned by this VM
2024 foreach_drive
($conf, sub {
2025 my ($ds, $drive) = @_;
2026 return if drive_is_cdrom
($drive, 1);
2028 my $volid = $drive->{file
};
2029 return if !$volid || $volid =~ m
|^/|;
2031 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2032 return if !$path || !$owner || ($owner != $vmid);
2034 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2035 warn "Could not remove disk '$volid', check manually: $@" if $@;
2038 # also remove unused disk
2039 my $vmdisks = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2040 PVE
::Storage
::foreach_volid
($vmdisks, sub {
2041 my ($volid, $sid, $volname, $d) = @_;
2042 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid) };
2046 if (defined $replacement_conf) {
2047 PVE
::QemuConfig-
>write_config($vmid, $replacement_conf);
2049 PVE
::QemuConfig-
>destroy_config($vmid);
2053 sub parse_vm_config
{
2054 my ($filename, $raw) = @_;
2056 return undef if !defined($raw);
2059 digest
=> Digest
::SHA
::sha1_hex
($raw),
2064 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2065 || die "got strange filename '$filename'";
2073 my @lines = split(/\n/, $raw);
2074 foreach my $line (@lines) {
2075 next if $line =~ m/^\s*$/;
2077 if ($line =~ m/^\[PENDING\]\s*$/i) {
2078 $section = 'pending';
2079 if (defined($descr)) {
2081 $conf->{description
} = $descr;
2084 $conf = $res->{$section} = {};
2087 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2089 if (defined($descr)) {
2091 $conf->{description
} = $descr;
2094 $conf = $res->{snapshots
}->{$section} = {};
2098 if ($line =~ m/^\#(.*)\s*$/) {
2099 $descr = '' if !defined($descr);
2100 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2104 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2105 $descr = '' if !defined($descr);
2106 $descr .= PVE
::Tools
::decode_text
($2);
2107 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2108 $conf->{snapstate
} = $1;
2109 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2112 $conf->{$key} = $value;
2113 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2115 if ($section eq 'pending') {
2116 $conf->{delete} = $value; # we parse this later
2118 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2120 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2123 eval { $value = check_type
($key, $value); };
2125 warn "vm $vmid - unable to parse value of '$key' - $@";
2127 $key = 'ide2' if $key eq 'cdrom';
2128 my $fmt = $confdesc->{$key}->{format
};
2129 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2130 my $v = parse_drive
($key, $value);
2131 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2132 $v->{file
} = $volid;
2133 $value = print_drive
($v);
2135 warn "vm $vmid - unable to parse value of '$key'\n";
2140 $conf->{$key} = $value;
2145 if (defined($descr)) {
2147 $conf->{description
} = $descr;
2149 delete $res->{snapstate
}; # just to be sure
2154 sub write_vm_config
{
2155 my ($filename, $conf) = @_;
2157 delete $conf->{snapstate
}; # just to be sure
2159 if ($conf->{cdrom
}) {
2160 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2161 $conf->{ide2
} = $conf->{cdrom
};
2162 delete $conf->{cdrom
};
2165 # we do not use 'smp' any longer
2166 if ($conf->{sockets
}) {
2167 delete $conf->{smp
};
2168 } elsif ($conf->{smp
}) {
2169 $conf->{sockets
} = $conf->{smp
};
2170 delete $conf->{cores
};
2171 delete $conf->{smp
};
2174 my $used_volids = {};
2176 my $cleanup_config = sub {
2177 my ($cref, $pending, $snapname) = @_;
2179 foreach my $key (keys %$cref) {
2180 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2181 $key eq 'snapstate' || $key eq 'pending';
2182 my $value = $cref->{$key};
2183 if ($key eq 'delete') {
2184 die "propertry 'delete' is only allowed in [PENDING]\n"
2186 # fixme: check syntax?
2189 eval { $value = check_type
($key, $value); };
2190 die "unable to parse value of '$key' - $@" if $@;
2192 $cref->{$key} = $value;
2194 if (!$snapname && is_valid_drivename
($key)) {
2195 my $drive = parse_drive
($key, $value);
2196 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2201 &$cleanup_config($conf);
2203 &$cleanup_config($conf->{pending
}, 1);
2205 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2206 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
2207 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2210 # remove 'unusedX' settings if we re-add a volume
2211 foreach my $key (keys %$conf) {
2212 my $value = $conf->{$key};
2213 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2214 delete $conf->{$key};
2218 my $generate_raw_config = sub {
2219 my ($conf, $pending) = @_;
2223 # add description as comment to top of file
2224 if (defined(my $descr = $conf->{description
})) {
2226 foreach my $cl (split(/\n/, $descr)) {
2227 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2230 $raw .= "#\n" if $pending;
2234 foreach my $key (sort keys %$conf) {
2235 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2236 $raw .= "$key: $conf->{$key}\n";
2241 my $raw = &$generate_raw_config($conf);
2243 if (scalar(keys %{$conf->{pending
}})){
2244 $raw .= "\n[PENDING]\n";
2245 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2248 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2249 $raw .= "\n[$snapname]\n";
2250 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2260 # we use static defaults from our JSON schema configuration
2261 foreach my $key (keys %$confdesc) {
2262 if (defined(my $default = $confdesc->{$key}->{default})) {
2263 $res->{$key} = $default;
2271 my $vmlist = PVE
::Cluster
::get_vmlist
();
2273 return $res if !$vmlist || !$vmlist->{ids
};
2274 my $ids = $vmlist->{ids
};
2275 my $nodename = nodename
();
2277 foreach my $vmid (keys %$ids) {
2278 my $d = $ids->{$vmid};
2279 next if !$d->{node
} || $d->{node
} ne $nodename;
2280 next if !$d->{type
} || $d->{type
} ne 'qemu';
2281 $res->{$vmid}->{exists} = 1;
2286 # test if VM uses local resources (to prevent migration)
2287 sub check_local_resources
{
2288 my ($conf, $noerr) = @_;
2292 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2293 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2295 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2297 foreach my $k (keys %$conf) {
2298 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
2299 # sockets are safe: they will recreated be on the target side post-migrate
2300 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2301 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2304 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2309 # check if used storages are available on all nodes (use by migrate)
2310 sub check_storage_availability
{
2311 my ($storecfg, $conf, $node) = @_;
2313 foreach_drive
($conf, sub {
2314 my ($ds, $drive) = @_;
2316 my $volid = $drive->{file
};
2319 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2322 # check if storage is available on both nodes
2323 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2324 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2328 # list nodes where all VM images are available (used by has_feature API)
2330 my ($conf, $storecfg) = @_;
2332 my $nodelist = PVE
::Cluster
::get_nodelist
();
2333 my $nodehash = { map { $_ => 1 } @$nodelist };
2334 my $nodename = nodename
();
2336 foreach_drive
($conf, sub {
2337 my ($ds, $drive) = @_;
2339 my $volid = $drive->{file
};
2342 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2344 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2345 if ($scfg->{disable
}) {
2347 } elsif (my $avail = $scfg->{nodes
}) {
2348 foreach my $node (keys %$nodehash) {
2349 delete $nodehash->{$node} if !$avail->{$node};
2351 } elsif (!$scfg->{shared
}) {
2352 foreach my $node (keys %$nodehash) {
2353 delete $nodehash->{$node} if $node ne $nodename
2362 sub check_local_storage_availability
{
2363 my ($conf, $storecfg) = @_;
2365 my $nodelist = PVE
::Cluster
::get_nodelist
();
2366 my $nodehash = { map { $_ => {} } @$nodelist };
2368 foreach_drive
($conf, sub {
2369 my ($ds, $drive) = @_;
2371 my $volid = $drive->{file
};
2374 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2376 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2378 if ($scfg->{disable
}) {
2379 foreach my $node (keys %$nodehash) {
2380 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2382 } elsif (my $avail = $scfg->{nodes
}) {
2383 foreach my $node (keys %$nodehash) {
2384 if (!$avail->{$node}) {
2385 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2392 foreach my $node (values %$nodehash) {
2393 if (my $unavail = $node->{unavailable_storages
}) {
2394 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2401 # Compat only, use assert_config_exists_on_node and vm_running_locally where possible
2403 my ($vmid, $nocheck, $node) = @_;
2405 PVE
::QemuConfig
::assert_config_exists_on_node
($vmid, $node) if !$nocheck;
2406 return PVE
::QemuServer
::Helpers
::vm_running_locally
($vmid);
2411 my $vzlist = config_list
();
2413 my $fd = IO
::Dir-
>new($PVE::QemuServer
::Helpers
::var_run_tmpdir
) || return $vzlist;
2415 while (defined(my $de = $fd->read)) {
2416 next if $de !~ m/^(\d+)\.pid$/;
2418 next if !defined($vzlist->{$vmid});
2419 if (my $pid = check_running
($vmid)) {
2420 $vzlist->{$vmid}->{pid
} = $pid;
2427 our $vmstatus_return_properties = {
2428 vmid
=> get_standard_option
('pve-vmid'),
2430 description
=> "Qemu process status.",
2432 enum
=> ['stopped', 'running'],
2435 description
=> "Maximum memory in bytes.",
2438 renderer
=> 'bytes',
2441 description
=> "Root disk size in bytes.",
2444 renderer
=> 'bytes',
2447 description
=> "VM name.",
2452 description
=> "Qemu QMP agent status.",
2457 description
=> "PID of running qemu process.",
2462 description
=> "Uptime.",
2465 renderer
=> 'duration',
2468 description
=> "Maximum usable CPUs.",
2473 description
=> "The current config lock, if any.",
2478 description
=> "The current configured tags, if any",
2484 my $last_proc_pid_stat;
2486 # get VM status information
2487 # This must be fast and should not block ($full == false)
2488 # We only query KVM using QMP if $full == true (this can be slow)
2490 my ($opt_vmid, $full) = @_;
2494 my $storecfg = PVE
::Storage
::config
();
2496 my $list = vzlist
();
2497 my $defaults = load_defaults
();
2499 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2501 my $cpucount = $cpuinfo->{cpus
} || 1;
2503 foreach my $vmid (keys %$list) {
2504 next if $opt_vmid && ($vmid ne $opt_vmid);
2506 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2508 my $d = { vmid
=> $vmid };
2509 $d->{pid
} = $list->{$vmid}->{pid
};
2511 # fixme: better status?
2512 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2514 my $size = PVE
::QemuServer
::Drive
::bootdisk_size
($storecfg, $conf);
2515 if (defined($size)) {
2516 $d->{disk
} = 0; # no info available
2517 $d->{maxdisk
} = $size;
2523 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2524 * ($conf->{cores
} || $defaults->{cores
});
2525 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2526 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2528 $d->{name
} = $conf->{name
} || "VM $vmid";
2529 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2530 : $defaults->{memory
}*(1024*1024);
2532 if ($conf->{balloon
}) {
2533 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2534 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2535 : $defaults->{shares
};
2546 $d->{diskwrite
} = 0;
2548 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2550 $d->{serial
} = 1 if conf_has_serial
($conf);
2551 $d->{lock} = $conf->{lock} if $conf->{lock};
2552 $d->{tags
} = $conf->{tags
} if defined($conf->{tags
});
2557 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2558 foreach my $dev (keys %$netdev) {
2559 next if $dev !~ m/^tap([1-9]\d*)i/;
2561 my $d = $res->{$vmid};
2564 $d->{netout
} += $netdev->{$dev}->{receive
};
2565 $d->{netin
} += $netdev->{$dev}->{transmit
};
2568 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2569 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2574 my $ctime = gettimeofday
;
2576 foreach my $vmid (keys %$list) {
2578 my $d = $res->{$vmid};
2579 my $pid = $d->{pid
};
2582 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2583 next if !$pstat; # not running
2585 my $used = $pstat->{utime} + $pstat->{stime
};
2587 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2589 if ($pstat->{vsize
}) {
2590 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2593 my $old = $last_proc_pid_stat->{$pid};
2595 $last_proc_pid_stat->{$pid} = {
2603 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2605 if ($dtime > 1000) {
2606 my $dutime = $used - $old->{used
};
2608 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2609 $last_proc_pid_stat->{$pid} = {
2615 $d->{cpu
} = $old->{cpu
};
2619 return $res if !$full;
2621 my $qmpclient = PVE
::QMPClient-
>new();
2623 my $ballooncb = sub {
2624 my ($vmid, $resp) = @_;
2626 my $info = $resp->{'return'};
2627 return if !$info->{max_mem
};
2629 my $d = $res->{$vmid};
2631 # use memory assigned to VM
2632 $d->{maxmem
} = $info->{max_mem
};
2633 $d->{balloon
} = $info->{actual
};
2635 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2636 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2637 $d->{freemem
} = $info->{free_mem
};
2640 $d->{ballooninfo
} = $info;
2643 my $blockstatscb = sub {
2644 my ($vmid, $resp) = @_;
2645 my $data = $resp->{'return'} || [];
2646 my $totalrdbytes = 0;
2647 my $totalwrbytes = 0;
2649 for my $blockstat (@$data) {
2650 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2651 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2653 $blockstat->{device
} =~ s/drive-//;
2654 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2656 $res->{$vmid}->{diskread
} = $totalrdbytes;
2657 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2660 my $statuscb = sub {
2661 my ($vmid, $resp) = @_;
2663 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2664 # this fails if ballon driver is not loaded, so this must be
2665 # the last commnand (following command are aborted if this fails).
2666 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2668 my $status = 'unknown';
2669 if (!defined($status = $resp->{'return'}->{status
})) {
2670 warn "unable to get VM status\n";
2674 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2677 foreach my $vmid (keys %$list) {
2678 next if $opt_vmid && ($vmid ne $opt_vmid);
2679 next if !$res->{$vmid}->{pid
}; # not running
2680 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2683 $qmpclient->queue_execute(undef, 2);
2685 foreach my $vmid (keys %$list) {
2686 next if $opt_vmid && ($vmid ne $opt_vmid);
2687 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2693 sub conf_has_serial
{
2696 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2697 if ($conf->{"serial$i"}) {
2705 sub conf_has_audio
{
2706 my ($conf, $id) = @_;
2709 my $audio = $conf->{"audio$id"};
2710 return undef if !defined($audio);
2712 my $audioproperties = PVE
::JSONSchema
::parse_property_string
($audio_fmt, $audio);
2713 my $audiodriver = $audioproperties->{driver
} // 'spice';
2716 dev
=> $audioproperties->{device
},
2717 dev_id
=> "audiodev$id",
2718 backend
=> $audiodriver,
2719 backend_id
=> "$audiodriver-backend${id}",
2723 sub vga_conf_has_spice
{
2726 my $vgaconf = parse_vga
($vga);
2727 my $vgatype = $vgaconf->{type
};
2728 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
2735 return get_host_arch
() eq $arch;
2740 return $conf->{arch
} // get_host_arch
();
2743 my $default_machines = {
2748 sub get_vm_machine
{
2749 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
2751 my $machine = $forcemachine || $conf->{machine
};
2753 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
2755 $machine ||= $default_machines->{$arch};
2756 if ($add_pve_version) {
2757 $kvmversion //= kvm_user_version
();
2758 my $pvever = PVE
::QemuServer
::Machine
::get_pve_version
($kvmversion);
2759 $machine .= "+pve$pvever";
2763 if ($add_pve_version && $machine !~ m/\+pve\d+$/) {
2764 # for version-pinned machines that do not include a pve-version (e.g.
2765 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
2766 $machine .= '+pve0';
2772 sub get_ovmf_files
($) {
2775 my $ovmf = $OVMF->{$arch}
2776 or die "no OVMF images known for architecture '$arch'\n";
2782 aarch64
=> '/usr/bin/qemu-system-aarch64',
2783 x86_64
=> '/usr/bin/qemu-system-x86_64',
2785 sub get_command_for_arch
($) {
2787 return '/usr/bin/kvm' if is_native
($arch);
2789 my $cmd = $Arch2Qemu->{$arch}
2790 or die "don't know how to emulate architecture '$arch'\n";
2794 # To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
2795 # to use in a QEMU command line (-cpu element), first array_intersect the result
2796 # of query_supported_ with query_understood_. This is necessary because:
2798 # a) query_understood_ returns flags the host cannot use and
2799 # b) query_supported_ (rather the QMP call) doesn't actually return CPU
2800 # flags, but CPU settings - with most of them being flags. Those settings
2801 # (and some flags, curiously) cannot be specified as a "-cpu" argument.
2803 # query_supported_ needs to start up to 2 temporary VMs and is therefore rather
2804 # expensive. If you need the value returned from this, you can get it much
2805 # cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
2806 # $accel being 'kvm' or 'tcg'.
2808 # pvestatd calls this function on startup and whenever the QEMU/KVM version
2809 # changes, automatically populating pmxcfs.
2811 # Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
2812 # since kvm and tcg machines support different flags
2814 sub query_supported_cpu_flags
{
2817 $arch //= get_host_arch
();
2818 my $default_machine = $default_machines->{$arch};
2822 # FIXME: Once this is merged, the code below should work for ARM as well:
2823 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
2824 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
2827 my $kvm_supported = defined(kvm_version
());
2828 my $qemu_cmd = get_command_for_arch
($arch);
2830 my $pidfile = PVE
::QemuServer
::Helpers
::pidfile_name
($fakevmid);
2832 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
2833 my $query_supported_run_qemu = sub {
2839 '-machine', $default_machine,
2841 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server,nowait",
2842 '-mon', 'chardev=qmp,mode=control',
2843 '-pidfile', $pidfile,
2848 push @$cmd, '-accel', 'tcg';
2851 my $rc = run_command
($cmd, noerr
=> 1, quiet
=> 0);
2852 die "QEMU flag querying VM exited with code " . $rc if $rc;
2855 my $cmd_result = mon_cmd
(
2857 'query-cpu-model-expansion',
2859 model
=> { name
=> 'host' }
2862 my $props = $cmd_result->{model
}->{props
};
2863 foreach my $prop (keys %$props) {
2864 next if $props->{$prop} ne '1';
2865 # QEMU returns some flags multiple times, with '_', '.' or '-'
2866 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
2867 # We only keep those with underscores, to match /proc/cpuinfo
2868 $prop =~ s/\.|-/_/g;
2869 $flags->{$prop} = 1;
2874 # force stop with 10 sec timeout and 'nocheck'
2875 # always stop, even if QMP failed
2876 vm_stop
(undef, $fakevmid, 1, 1, 10, 0, 1);
2880 return [ sort keys %$flags ];
2883 # We need to query QEMU twice, since KVM and TCG have different supported flags
2884 PVE
::QemuConfig-
>lock_config($fakevmid, sub {
2885 $flags->{tcg
} = eval { $query_supported_run_qemu->(0) };
2886 warn "warning: failed querying supported tcg flags: $@\n" if $@;
2888 if ($kvm_supported) {
2889 $flags->{kvm
} = eval { $query_supported_run_qemu->(1) };
2890 warn "warning: failed querying supported kvm flags: $@\n" if $@;
2897 # Understood CPU flags are written to a file at 'pve-qemu' compile time
2898 my $understood_cpu_flag_dir = "/usr/share/kvm";
2899 sub query_understood_cpu_flags
{
2900 my $arch = get_host_arch
();
2901 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
2903 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
2906 my $raw = file_get_contents
($filepath);
2907 $raw =~ s/^\s+|\s+$//g;
2908 my @flags = split(/\s+/, $raw);
2913 sub config_to_command
{
2914 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2917 my $globalFlags = [];
2918 my $machineFlags = [];
2923 my $ostype = $conf->{ostype
};
2924 my $winversion = windows_version
($ostype);
2925 my $kvm = $conf->{kvm
};
2926 my $nodename = nodename
();
2928 my $arch = get_vm_arch
($conf);
2929 my $kvm_binary = get_command_for_arch
($arch);
2930 my $kvmver = kvm_user_version
($kvm_binary);
2932 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
2933 $kvmver //= "undefined";
2934 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
2937 my $add_pve_version = min_version
($kvmver, 4, 1);
2939 my $machine_type = get_vm_machine
($conf, $forcemachine, $arch, $add_pve_version);
2940 my $machine_version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, $kvmver);
2941 $kvm //= 1 if is_native
($arch);
2943 $machine_version =~ m/(\d+)\.(\d+)/;
2944 my ($machine_major, $machine_minor) = ($1, $2);
2945 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type', please upgrade node '$nodename'\n"
2946 if !PVE
::QemuServer
::min_version
($kvmver, $machine_major, $machine_minor);
2948 if (!PVE
::QemuServer
::Machine
::can_run_pve_machine_version
($machine_version, $kvmver)) {
2949 my $max_pve_version = PVE
::QemuServer
::Machine
::get_pve_version
($machine_version);
2950 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is pve$max_pve_version)"
2951 . " is too old to run machine type '$machine_type', please upgrade node '$nodename'\n";
2954 # if a specific +pve version is required for a feature, use $version_guard
2955 # instead of min_version to allow machines to be run with the minimum
2957 my $required_pve_version = 0;
2958 my $version_guard = sub {
2959 my ($major, $minor, $pve) = @_;
2960 return 0 if !min_version
($machine_version, $major, $minor, $pve);
2961 my $max_pve = PVE
::QemuServer
::Machine
::get_pve_version
("$major.$minor");
2962 return 1 if min_version
($machine_version, $major, $minor, $max_pve+1);
2963 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
2968 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
2969 if !defined kvm_version
();
2972 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
2973 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2974 my $use_old_bios_files = undef;
2975 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2977 my $cpuunits = defined($conf->{cpuunits
}) ?
2978 $conf->{cpuunits
} : $defaults->{cpuunits
};
2980 push @$cmd, $kvm_binary;
2982 push @$cmd, '-id', $vmid;
2984 my $vmname = $conf->{name
} || "vm$vmid";
2986 push @$cmd, '-name', $vmname;
2990 my $qmpsocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid);
2991 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2992 push @$cmd, '-mon', "chardev=qmp,mode=control";
2994 if (min_version
($machine_version, 2, 12)) {
2995 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
2996 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
2999 push @$cmd, '-pidfile' , PVE
::QemuServer
::Helpers
::pidfile_name
($vmid);
3001 push @$cmd, '-daemonize';
3003 if ($conf->{smbios1
}) {
3004 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3005 if ($smbios_conf->{base64
}) {
3006 # Do not pass base64 flag to qemu
3007 delete $smbios_conf->{base64
};
3008 my $smbios_string = "";
3009 foreach my $key (keys %$smbios_conf) {
3011 if ($key eq "uuid") {
3012 $value = $smbios_conf->{uuid
}
3014 $value = decode_base64
($smbios_conf->{$key});
3016 # qemu accepts any binary data, only commas need escaping by double comma
3018 $smbios_string .= "," . $key . "=" . $value if $value;
3020 push @$cmd, '-smbios', "type=1" . $smbios_string;
3022 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3026 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3027 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3028 die "uefi base image not found\n" if ! -f
$ovmf_code;
3032 if (my $efidisk = $conf->{efidisk0
}) {
3033 my $d = parse_drive
('efidisk0', $efidisk);
3034 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3035 $format = $d->{format
};
3037 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3038 if (!defined($format)) {
3039 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3040 $format = qemu_img_format
($scfg, $volname);
3044 die "efidisk format must be specified\n"
3045 if !defined($format);
3048 warn "no efidisk configured! Using temporary efivars disk.\n";
3049 $path = "/tmp/$vmid-ovmf.fd";
3050 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3056 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3057 $size_str = ",size=" . (-s
$ovmf_vars);
3060 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3061 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0$size_str,file=$path";
3066 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3067 if (min_version
($machine_version, 4, 0)) {
3068 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3070 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3074 if ($conf->{vmgenid
}) {
3075 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3078 # add usb controllers
3079 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3080 push @$devices, @usbcontrollers if @usbcontrollers;
3081 my $vga = parse_vga
($conf->{vga
});
3083 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3084 $vga->{type
} = 'qxl' if $qxlnum;
3086 if (!$vga->{type
}) {
3087 if ($arch eq 'aarch64') {
3088 $vga->{type
} = 'virtio';
3089 } elsif (min_version
($machine_version, 2, 9)) {
3090 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3092 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3096 # enable absolute mouse coordinates (needed by vnc)
3098 if (defined($conf->{tablet
})) {
3099 $tablet = $conf->{tablet
};
3101 $tablet = $defaults->{tablet
};
3102 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3103 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3107 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3108 my $kbd = print_keyboarddevice_full
($conf, $arch);
3109 push @$devices, '-device', $kbd if defined($kbd);
3113 my $gpu_passthrough;
3116 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3117 my $id = "hostpci$i";
3118 my $d = parse_hostpci
($conf->{$id});
3121 if (my $pcie = $d->{pcie
}) {
3122 die "q35 machine model is not enabled" if !$q35;
3123 # win7 wants to have the pcie devices directly on the pcie bus
3124 # instead of in the root port
3125 if ($winversion == 7) {
3126 $pciaddr = print_pcie_addr
("${id}bus0");
3128 # add more root ports if needed, 4 are present by default
3129 # by pve-q35 cfgs, rest added here on demand.
3131 push @$devices, '-device', print_pcie_root_port
($i);
3133 $pciaddr = print_pcie_addr
($id);
3136 $pciaddr = print_pci_addr
($id, $bridges, $arch, $machine_type);
3140 if ($d->{'x-vga'}) {
3141 $xvga = ',x-vga=on' if !($conf->{bios
} && $conf->{bios
} eq 'ovmf');
3143 $vga->{type
} = 'none' if !defined($conf->{vga
});
3144 $gpu_passthrough = 1;
3147 my $pcidevices = $d->{pciid
};
3148 my $multifunction = 1 if @$pcidevices > 1;
3151 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3152 my $pci_id = $pcidevices->[0]->{id
};
3153 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3154 $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid";
3155 } elsif ($d->{mdev
}) {
3156 warn "ignoring mediated device '$id' with multifunction device\n";
3160 foreach my $pcidevice (@$pcidevices) {
3161 my $devicestr = "vfio-pci";
3164 $devicestr .= ",sysfsdev=$sysfspath";
3166 $devicestr .= ",host=$pcidevice->{id}";
3169 my $mf_addr = $multifunction ?
".$j" : '';
3170 $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
3173 $devicestr .= ',rombar=0' if defined($d->{rombar
}) && !$d->{rombar
};
3174 $devicestr .= "$xvga";
3175 $devicestr .= ",multifunction=on" if $multifunction;
3176 $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile
};
3179 push @$devices, '-device', $devicestr;
3185 my $usb_dev_features = {};
3186 $usb_dev_features->{spice_usb3
} = 1 if min_version
($machine_version, 4, 0);
3188 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES, $usb_dev_features);
3189 push @$devices, @usbdevices if @usbdevices;
3191 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3192 if (my $path = $conf->{"serial$i"}) {
3193 if ($path eq 'socket') {
3194 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3195 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3196 # On aarch64, serial0 is the UART device. Qemu only allows
3197 # connecting UART devices via the '-serial' command line, as
3198 # the device has a fixed slot on the hardware...
3199 if ($arch eq 'aarch64' && $i == 0) {
3200 push @$devices, '-serial', "chardev:serial$i";
3202 push @$devices, '-device', "isa-serial,chardev=serial$i";
3205 die "no such serial device\n" if ! -c
$path;
3206 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3207 push @$devices, '-device', "isa-serial,chardev=serial$i";
3213 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3214 if (my $path = $conf->{"parallel$i"}) {
3215 die "no such parallel device\n" if ! -c
$path;
3216 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3217 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3218 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3222 if (my $audio = conf_has_audio
($conf)) {
3224 my $audiopciaddr = print_pci_addr
("audio0", $bridges, $arch, $machine_type);
3226 my $id = $audio->{dev_id
};
3227 if ($audio->{dev
} eq 'AC97') {
3228 push @$devices, '-device', "AC97,id=${id}${audiopciaddr}";
3229 } elsif ($audio->{dev
} =~ /intel\-hda$/) {
3230 push @$devices, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3231 push @$devices, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0";
3232 push @$devices, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1";
3234 die "unkown audio device '$audio->{dev}', implement me!";
3237 push @$devices, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3241 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3242 $sockets = $conf->{sockets
} if $conf->{sockets
};
3244 my $cores = $conf->{cores
} || 1;
3246 my $maxcpus = $sockets * $cores;
3248 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3250 my $allowed_vcpus = $cpuinfo->{cpus
};
3252 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3253 if ($allowed_vcpus < $maxcpus);
3255 if($hotplug_features->{cpu
} && min_version
($machine_version, 2, 7)) {
3257 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3258 for (my $i = 2; $i <= $vcpus; $i++) {
3259 my $cpustr = print_cpu_device
($conf,$i);
3260 push @$cmd, '-device', $cpustr;
3265 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3267 push @$cmd, '-nodefaults';
3269 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3271 my $bootindex_hash = {};
3273 foreach my $o (split(//, $bootorder)) {
3274 $bootindex_hash->{$o} = $i*100;
3278 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3280 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3282 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3284 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3285 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
3286 my $socket = PVE
::QemuServer
::Helpers
::vnc_socket
($vmid);
3287 push @$cmd, '-vnc', "unix:$socket,password";
3289 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3290 push @$cmd, '-nographic';
3294 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3296 my $useLocaltime = $conf->{localtime};
3298 if ($winversion >= 5) { # windows
3299 $useLocaltime = 1 if !defined($conf->{localtime});
3301 # use time drift fix when acpi is enabled
3302 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3303 $tdf = 1 if !defined($conf->{tdf
});
3307 if ($winversion >= 6) {
3308 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3309 push @$cmd, '-no-hpet';
3312 push @$rtcFlags, 'driftfix=slew' if $tdf;
3314 if (($conf->{startdate
}) && ($conf->{startdate
} ne 'now')) {
3315 push @$rtcFlags, "base=$conf->{startdate}";
3316 } elsif ($useLocaltime) {
3317 push @$rtcFlags, 'base=localtime';
3320 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
3322 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3324 push @$cmd, '-S' if $conf->{freeze
};
3326 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3328 my $guest_agent = parse_guest_agent
($conf);
3330 if ($guest_agent->{enabled
}) {
3331 my $qgasocket = PVE
::QemuServer
::Helpers
::qmp_socket
($vmid, 1);
3332 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3334 if (!$guest_agent->{type
} || $guest_agent->{type
} eq 'virtio') {
3335 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3336 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3337 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3338 } elsif ($guest_agent->{type
} eq 'isa') {
3339 push @$devices, '-device', "isa-serial,chardev=qga0";
3343 my $rng = parse_rng
($conf->{rng0
}) if $conf->{rng0
};
3344 if ($rng && &$version_guard(4, 1, 2)) {
3345 my $max_bytes = $rng->{max_bytes
} // $rng_fmt->{max_bytes
}->{default};
3346 my $period = $rng->{period
} // $rng_fmt->{period
}->{default};
3348 my $limiter_str = "";
3350 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3353 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
3354 die "cannot create VirtIO RNG device: source file '$rng->{source}' doesn't exist\n"
3355 if ! -e
$rng->{source
};
3357 my $rng_addr = print_pci_addr
("rng0", $bridges, $arch, $machine_type);
3359 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3360 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3368 for(my $i = 1; $i < $qxlnum; $i++){
3369 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
3372 # assume other OS works like Linux
3373 my ($ram, $vram) = ("134217728", "67108864");
3374 if ($vga->{memory
}) {
3375 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3376 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3378 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3379 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3383 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3385 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3386 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3387 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3389 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3390 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3391 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3393 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3394 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3396 my $spice_enhancement = PVE
::JSONSchema
::parse_property_string
($spice_enhancements_fmt, $conf->{spice_enhancements
} // '');
3397 if ($spice_enhancement->{foldersharing
}) {
3398 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3399 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3402 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3403 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming
};
3404 push @$devices, '-spice', "$spice_opts";
3407 # enable balloon by default, unless explicitly disabled
3408 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3409 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3410 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3413 if ($conf->{watchdog
}) {
3414 my $wdopts = parse_watchdog
($conf->{watchdog
});
3415 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3416 my $watchdog = $wdopts->{model
} || 'i6300esb';
3417 push @$devices, '-device', "$watchdog$pciaddr";
3418 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3422 my $scsicontroller = {};
3423 my $ahcicontroller = {};
3424 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3426 # Add iscsi initiator name if available
3427 if (my $initiator = get_initiator_name
()) {
3428 push @$devices, '-iscsi', "initiator-name=$initiator";
3431 foreach_drive
($conf, sub {
3432 my ($ds, $drive) = @_;
3434 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3435 push @$vollist, $drive->{file
};
3438 # ignore efidisk here, already added in bios/fw handling code above
3439 return if $drive->{interface
} eq 'efidisk';
3441 $use_virtio = 1 if $ds =~ m/^virtio/;
3443 if (drive_is_cdrom
($drive)) {
3444 if ($bootindex_hash->{d
}) {
3445 $drive->{bootindex
} = $bootindex_hash->{d
};
3446 $bootindex_hash->{d
} += 1;
3449 if ($bootindex_hash->{c
}) {
3450 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3451 $bootindex_hash->{c
} += 1;
3455 if($drive->{interface
} eq 'virtio'){
3456 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3459 if ($drive->{interface
} eq 'scsi') {
3461 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3463 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3464 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3466 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3467 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3470 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3471 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3472 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3473 } elsif ($drive->{iothread
}) {
3474 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3478 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3479 $queues = ",num_queues=$drive->{queues}";
3482 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3483 $scsicontroller->{$controller}=1;
3486 if ($drive->{interface
} eq 'sata') {
3487 my $controller = int($drive->{index} / $PVE::QemuServer
::Drive
::MAX_SATA_DISKS
);
3488 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3489 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3490 $ahcicontroller->{$controller}=1;
3493 my $drive_cmd = print_drive_commandline_full
($storecfg, $vmid, $drive);
3494 push @$devices, '-drive',$drive_cmd;
3495 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3498 for (my $i = 0; $i < $MAX_NETS; $i++) {
3499 next if !$conf->{"net$i"};
3500 my $d = parse_net
($conf->{"net$i"});
3503 $use_virtio = 1 if $d->{model
} eq 'virtio';
3505 if ($bootindex_hash->{n
}) {
3506 $d->{bootindex
} = $bootindex_hash->{n
};
3507 $bootindex_hash->{n
} += 1;
3510 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3511 push @$devices, '-netdev', $netdevfull;
3513 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3514 push @$devices, '-device', $netdevicefull;
3517 if ($conf->{ivshmem
}) {
3518 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3522 $bus = print_pcie_addr
("ivshmem");
3524 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3527 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3528 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3530 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3531 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3534 # pci.4 is nested in pci.1
3535 $bridges->{1} = 1 if $bridges->{4};
3539 if (min_version
($machine_version, 2, 3)) {
3544 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3548 for my $k (sort {$b cmp $a} keys %$bridges) {
3549 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
3550 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3551 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3553 # add after -readconfig pve-q35.cfg
3554 splice @$devices, 2, 0, '-device', $devstr;
3556 unshift @$devices, '-device', $devstr if $k > 0;
3561 push @$machineFlags, 'accel=tcg';
3564 my $machine_type_min = $machine_type;
3565 if ($add_pve_version) {
3566 $machine_type_min =~ s/\+pve\d+$//;
3567 $machine_type_min .= "+pve$required_pve_version";
3569 push @$machineFlags, "type=${machine_type_min}";
3571 push @$cmd, @$devices;
3572 push @$cmd, '-rtc', join(',', @$rtcFlags)
3573 if scalar(@$rtcFlags);
3574 push @$cmd, '-machine', join(',', @$machineFlags)
3575 if scalar(@$machineFlags);
3576 push @$cmd, '-global', join(',', @$globalFlags)
3577 if scalar(@$globalFlags);
3579 if (my $vmstate = $conf->{vmstate
}) {
3580 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
3581 push @$vollist, $vmstate;
3582 push @$cmd, '-loadstate', $statepath;
3583 print "activating and using '$vmstate' as vmstate\n";
3587 if ($conf->{args
}) {
3588 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3592 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3598 my $res = mon_cmd
($vmid, 'query-spice');
3600 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3603 sub vm_devices_list
{
3606 my $res = mon_cmd
($vmid, 'query-pci');
3607 my $devices_to_check = [];
3609 foreach my $pcibus (@$res) {
3610 push @$devices_to_check, @{$pcibus->{devices
}},
3613 while (@$devices_to_check) {
3615 for my $d (@$devices_to_check) {
3616 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3617 next if !$d->{'pci_bridge'};
3619 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3620 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3622 $devices_to_check = $to_check;
3625 my $resblock = mon_cmd
($vmid, 'query-block');
3626 foreach my $block (@$resblock) {
3627 if($block->{device
} =~ m/^drive-(\S+)/){
3632 my $resmice = mon_cmd
($vmid, 'query-mice');
3633 foreach my $mice (@$resmice) {
3634 if ($mice->{name
} eq 'QEMU HID Tablet') {
3635 $devices->{tablet
} = 1;
3640 # for usb devices there is no query-usb
3641 # but we can iterate over the entries in
3642 # qom-list path=/machine/peripheral
3643 my $resperipheral = mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3644 foreach my $per (@$resperipheral) {
3645 if ($per->{name
} =~ m/^usb\d+$/) {
3646 $devices->{$per->{name
}} = 1;
3654 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3656 my $q35 = PVE
::QemuServer
::Machine
::machine_type_is_q35
($conf);
3658 my $devices_list = vm_devices_list
($vmid);
3659 return 1 if defined($devices_list->{$deviceid});
3661 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3663 if ($deviceid eq 'tablet') {
3665 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
3667 } elsif ($deviceid eq 'keyboard') {
3669 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
3671 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3673 die "usb hotplug currently not reliable\n";
3674 # since we can't reliably hot unplug all added usb devices
3675 # and usb passthrough disables live migration
3676 # we disable usb hotplugging for now
3677 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3679 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3681 qemu_iothread_add
($vmid, $deviceid, $device);
3683 qemu_driveadd
($storecfg, $vmid, $device);
3684 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3686 qemu_deviceadd
($vmid, $devicefull);
3687 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3689 eval { qemu_drivedel
($vmid, $deviceid); };
3694 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3697 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3698 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3699 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3701 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3703 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3704 qemu_iothread_add
($vmid, $deviceid, $device);
3705 $devicefull .= ",iothread=iothread-$deviceid";
3708 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3709 $devicefull .= ",num_queues=$device->{queues}";
3712 qemu_deviceadd
($vmid, $devicefull);
3713 qemu_deviceaddverify
($vmid, $deviceid);
3715 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3717 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
3718 qemu_driveadd
($storecfg, $vmid, $device);
3720 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
3721 eval { qemu_deviceadd
($vmid, $devicefull); };
3723 eval { qemu_drivedel
($vmid, $deviceid); };
3728 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3730 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
3732 my $machine_type = PVE
::QemuServer
::Machine
::qemu_machine_pxe
($vmid, $conf);
3733 my $use_old_bios_files = undef;
3734 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3736 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
3737 qemu_deviceadd
($vmid, $netdevicefull);
3739 qemu_deviceaddverify
($vmid, $deviceid);
3740 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
3743 eval { qemu_netdevdel
($vmid, $deviceid); };
3748 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3751 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
3752 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3754 qemu_deviceadd
($vmid, $devicefull);
3755 qemu_deviceaddverify
($vmid, $deviceid);
3758 die "can't hotplug device '$deviceid'\n";
3764 # fixme: this should raise exceptions on error!
3765 sub vm_deviceunplug
{
3766 my ($vmid, $conf, $deviceid) = @_;
3768 my $devices_list = vm_devices_list
($vmid);
3769 return 1 if !defined($devices_list->{$deviceid});
3771 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3773 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3775 qemu_devicedel
($vmid, $deviceid);
3777 } elsif ($deviceid =~ m/^usb\d+$/) {
3779 die "usb hotplug currently not reliable\n";
3780 # when unplugging usb devices this way,
3781 # there may be remaining usb controllers/hubs
3782 # so we disable it for now
3783 qemu_devicedel
($vmid, $deviceid);
3784 qemu_devicedelverify
($vmid, $deviceid);
3786 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3788 qemu_devicedel
($vmid, $deviceid);
3789 qemu_devicedelverify
($vmid, $deviceid);
3790 qemu_drivedel
($vmid, $deviceid);
3791 qemu_iothread_del
($conf, $vmid, $deviceid);
3793 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3795 qemu_devicedel
($vmid, $deviceid);
3796 qemu_devicedelverify
($vmid, $deviceid);
3797 qemu_iothread_del
($conf, $vmid, $deviceid);
3799 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3801 qemu_devicedel
($vmid, $deviceid);
3802 qemu_drivedel
($vmid, $deviceid);
3803 qemu_deletescsihw
($conf, $vmid, $deviceid);
3805 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3807 qemu_devicedel
($vmid, $deviceid);
3808 qemu_devicedelverify
($vmid, $deviceid);
3809 qemu_netdevdel
($vmid, $deviceid);
3812 die "can't unplug device '$deviceid'\n";
3818 sub qemu_deviceadd
{
3819 my ($vmid, $devicefull) = @_;
3821 $devicefull = "driver=".$devicefull;
3822 my %options = split(/[=,]/, $devicefull);
3824 mon_cmd
($vmid, "device_add" , %options);
3827 sub qemu_devicedel
{
3828 my ($vmid, $deviceid) = @_;
3830 my $ret = mon_cmd
($vmid, "device_del", id
=> $deviceid);
3833 sub qemu_iothread_add
{
3834 my($vmid, $deviceid, $device) = @_;
3836 if ($device->{iothread
}) {
3837 my $iothreads = vm_iothreads_list
($vmid);
3838 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3842 sub qemu_iothread_del
{
3843 my($conf, $vmid, $deviceid) = @_;
3845 my $confid = $deviceid;
3846 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
3847 $confid = 'scsi' . $1;
3849 my $device = parse_drive
($confid, $conf->{$confid});
3850 if ($device->{iothread
}) {
3851 my $iothreads = vm_iothreads_list
($vmid);
3852 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3856 sub qemu_objectadd
{
3857 my($vmid, $objectid, $qomtype) = @_;
3859 mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3864 sub qemu_objectdel
{
3865 my($vmid, $objectid) = @_;
3867 mon_cmd
($vmid, "object-del", id
=> $objectid);
3873 my ($storecfg, $vmid, $device) = @_;
3875 my $drive = print_drive_commandline_full
($storecfg, $vmid, $device);
3876 $drive =~ s/\\/\\\\/g;
3877 my $ret = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "drive_add auto \"$drive\"");
3879 # If the command succeeds qemu prints: "OK
"
3880 return 1 if $ret =~ m/OK/s;
3882 die "adding drive failed
: $ret\n";
3886 my($vmid, $deviceid) = @_;
3888 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-
$deviceid");
3891 return 1 if $ret eq "";
3893 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3894 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3896 die "deleting drive
$deviceid failed
: $ret\n";
3899 sub qemu_deviceaddverify {
3900 my ($vmid, $deviceid) = @_;
3902 for (my $i = 0; $i <= 5; $i++) {
3903 my $devices_list = vm_devices_list($vmid);
3904 return 1 if defined($devices_list->{$deviceid});
3908 die "error on hotplug device
'$deviceid'\n";
3912 sub qemu_devicedelverify {
3913 my ($vmid, $deviceid) = @_;
3915 # need to verify that the device is correctly removed as device_del
3916 # is async and empty return is not reliable
3918 for (my $i = 0; $i <= 5; $i++) {
3919 my $devices_list = vm_devices_list($vmid);
3920 return 1 if !defined($devices_list->{$deviceid});
3924 die "error on hot-unplugging device
'$deviceid'\n";
3927 sub qemu_findorcreatescsihw {
3928 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
3930 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3932 my $scsihwid="$controller_prefix$controller";
3933 my $devices_list = vm_devices_list($vmid);
3935 if(!defined($devices_list->{$scsihwid})) {
3936 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
3942 sub qemu_deletescsihw {
3943 my ($conf, $vmid, $opt) = @_;
3945 my $device = parse_drive($opt, $conf->{$opt});
3947 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3948 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3952 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3954 my $devices_list = vm_devices_list($vmid);
3955 foreach my $opt (keys %{$devices_list}) {
3956 if (is_valid_drivename($opt)) {
3957 my $drive = parse_drive($opt, $conf->{$opt});
3958 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3964 my $scsihwid="scsihw
$controller";
3966 vm_deviceunplug($vmid, $conf, $scsihwid);
3971 sub qemu_add_pci_bridge {
3972 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
3978 print_pci_addr($device, $bridges, $arch, $machine_type);
3980 while (my ($k, $v) = each %$bridges) {
3983 return 1 if !defined($bridgeid) || $bridgeid < 1;
3985 my $bridge = "pci
.$bridgeid";
3986 my $devices_list = vm_devices_list($vmid);
3988 if (!defined($devices_list->{$bridge})) {
3989 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
3995 sub qemu_set_link_status {
3996 my ($vmid, $device, $up) = @_;
3998 mon_cmd($vmid, "set_link
", name => $device,
3999 up => $up ? JSON::true : JSON::false);
4002 sub qemu_netdevadd {
4003 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4005 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4006 my %options = split(/[=,]/, $netdev);
4008 mon_cmd($vmid, "netdev_add
", %options);
4012 sub qemu_netdevdel {
4013 my ($vmid, $deviceid) = @_;
4015 mon_cmd($vmid, "netdev_del
", id => $deviceid);
4018 sub qemu_usb_hotplug {
4019 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4023 # remove the old one first
4024 vm_deviceunplug($vmid, $conf, $deviceid);
4026 # check if xhci controller is necessary and available
4027 if ($device->{usb3}) {
4029 my $devicelist = vm_devices_list($vmid);
4031 if (!$devicelist->{xhci}) {
4032 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4033 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4036 my $d = parse_usb_device($device->{host});
4037 $d->{usb3} = $device->{usb3};
4040 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4043 sub qemu_cpu_hotplug {
4044 my ($vmid, $conf, $vcpus) = @_;
4046 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
4049 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4050 $sockets = $conf->{sockets} if $conf->{sockets};
4051 my $cores = $conf->{cores} || 1;
4052 my $maxcpus = $sockets * $cores;
4054 $vcpus = $maxcpus if !$vcpus;
4056 die "you can
't add more vcpus than maxcpus\n"
4057 if $vcpus > $maxcpus;
4059 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4061 if ($vcpus < $currentvcpus) {
4063 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4065 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4066 qemu_devicedel($vmid, "cpu$i");
4068 my $currentrunningvcpus = undef;
4070 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4071 last if scalar(@{$currentrunningvcpus}) == $i-1;
4072 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4076 #update conf after each succesfull cpu unplug
4077 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4078 PVE::QemuConfig->write_config($vmid, $conf);
4081 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4087 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4088 die "vcpus in running vm does not match its configuration\n"
4089 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4091 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
4093 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4094 my $cpustr = print_cpu_device($conf, $i);
4095 qemu_deviceadd($vmid, $cpustr);
4098 my $currentrunningvcpus = undef;
4100 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
4101 last if scalar(@{$currentrunningvcpus}) == $i;
4102 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4106 #update conf after each succesfull cpu hotplug
4107 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4108 PVE::QemuConfig->write_config($vmid, $conf);
4112 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4113 mon_cmd($vmid, "cpu-add", id => int($i));
4118 sub qemu_block_set_io_throttle {
4119 my ($vmid, $deviceid,
4120 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4121 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4122 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4123 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4125 return if !check_running($vmid) ;
4127 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4129 bps_rd => int($bps_rd),
4130 bps_wr => int($bps_wr),
4132 iops_rd => int($iops_rd),
4133 iops_wr => int($iops_wr),
4134 bps_max => int($bps_max),
4135 bps_rd_max => int($bps_rd_max),
4136 bps_wr_max => int($bps_wr_max),
4137 iops_max => int($iops_max),
4138 iops_rd_max => int($iops_rd_max),
4139 iops_wr_max => int($iops_wr_max),
4140 bps_max_length => int($bps_max_length),
4141 bps_rd_max_length => int($bps_rd_max_length),
4142 bps_wr_max_length => int($bps_wr_max_length),
4143 iops_max_length => int($iops_max_length),
4144 iops_rd_max_length => int($iops_rd_max_length),
4145 iops_wr_max_length => int($iops_wr_max_length),
4150 # old code, only used to shutdown old VM after update
4152 my ($fh, $timeout) = @_;
4154 my $sel = new IO::Select;
4161 while (scalar (@ready = $sel->can_read($timeout))) {
4163 if ($count = $fh->sysread($buf, 8192)) {
4164 if ($buf =~ /^(.*)\(qemu\) $/s) {
4171 if (!defined($count)) {
4178 die "monitor read timeout\n" if !scalar(@ready);
4183 sub qemu_block_resize {
4184 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4186 my $running = check_running($vmid);
4188 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4190 return if !$running;
4192 my $padding = (1024 - $size % 1024) % 1024;
4193 $size = $size + $padding;
4195 mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4199 sub qemu_volume_snapshot {
4200 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4202 my $running = check_running($vmid);
4204 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4205 mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4207 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4211 sub qemu_volume_snapshot_delete {
4212 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4214 my $running = check_running($vmid);
4219 my $conf = PVE::QemuConfig->load_config($vmid);
4220 foreach_drive($conf, sub {
4221 my ($ds, $drive) = @_;
4222 $running = 1 if $drive->{file} eq $volid;
4226 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4227 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4229 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4233 sub set_migration_caps {
4239 "auto-converge" => 1,
4241 "x-rdma-pin-all" => 0,
4246 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
4248 for my $supported_capability (@$supported_capabilities) {
4250 capability => $supported_capability->{capability},
4251 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4255 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4258 my $fast_plug_option = {
4266 'vmstatestorage
' => 1,
4271 # hotplug changes in [PENDING]
4272 # $selection hash can be used to only apply specified options, for
4273 # example: { cores => 1 } (only apply changed 'cores
')
4274 # $errors ref is used to return error messages
4275 sub vmconfig_hotplug_pending {
4276 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4278 my $defaults = load_defaults();
4279 my $arch = get_vm_arch($conf);
4280 my $machine_type = get_vm_machine($conf, undef, $arch);
4282 # commit values which do not have any impact on running VM first
4283 # Note: those option cannot raise errors, we we do not care about
4284 # $selection and always apply them.
4286 my $add_error = sub {
4287 my ($opt, $msg) = @_;
4288 $errors->{$opt} = "hotplug problem - $msg";
4292 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4293 if ($fast_plug_option->{$opt}) {
4294 $conf->{$opt} = $conf->{pending}->{$opt};
4295 delete $conf->{pending}->{$opt};
4301 PVE::QemuConfig->write_config($vmid, $conf);
4304 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4306 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4307 foreach my $opt (sort keys %$pending_delete_hash) {
4308 next if $selection && !$selection->{$opt};
4309 my $force = $pending_delete_hash->{$opt}->{force};
4311 if ($opt eq 'hotplug
') {
4312 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4313 } elsif ($opt eq 'tablet
') {
4314 die "skip\n" if !$hotplug_features->{usb};
4315 if ($defaults->{tablet}) {
4316 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4317 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4318 if $arch eq 'aarch64
';
4320 vm_deviceunplug($vmid, $conf, 'tablet
');
4321 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4323 } elsif ($opt =~ m/^usb\d+/) {
4325 # since we cannot reliably hot unplug usb devices
4326 # we are disabling it
4327 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4328 vm_deviceunplug($vmid, $conf, $opt);
4329 } elsif ($opt eq 'vcpus
') {
4330 die "skip\n" if !$hotplug_features->{cpu};
4331 qemu_cpu_hotplug($vmid, $conf, undef);
4332 } elsif ($opt eq 'balloon
') {
4333 # enable balloon device is not hotpluggable
4334 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4335 # here we reset the ballooning value to memory
4336 my $balloon = $conf->{memory} || $defaults->{memory};
4337 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4338 } elsif ($fast_plug_option->{$opt}) {
4340 } elsif ($opt =~ m/^net(\d+)$/) {
4341 die "skip\n" if !$hotplug_features->{network};
4342 vm_deviceunplug($vmid, $conf, $opt);
4343 } elsif (is_valid_drivename($opt)) {
4344 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4345 vm_deviceunplug($vmid, $conf, $opt);
4346 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4347 } elsif ($opt =~ m/^memory$/) {
4348 die "skip\n" if !$hotplug_features->{memory};
4349 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4350 } elsif ($opt eq 'cpuunits
') {
4351 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4352 } elsif ($opt eq 'cpulimit
') {
4353 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4359 &$add_error($opt, $err) if $err ne "skip\n";
4361 delete $conf->{$opt};
4362 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4366 my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
4367 $apply_pending_cloudinit = sub {
4368 return if $apply_pending_cloudinit_done; # once is enough
4369 $apply_pending_cloudinit_done = 1; # once is enough
4371 my ($key, $value) = @_;
4373 my @cloudinit_opts = keys %$confdesc_cloudinit;
4374 foreach my $opt (keys %{$conf->{pending}}) {
4375 next if !grep { $_ eq $opt } @cloudinit_opts;
4376 $conf->{$opt} = delete $conf->{pending}->{$opt};
4379 my $new_conf = { %$conf };
4380 $new_conf->{$key} = $value;
4381 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4384 foreach my $opt (keys %{$conf->{pending}}) {
4385 next if $selection && !$selection->{$opt};
4386 my $value = $conf->{pending}->{$opt};
4388 if ($opt eq 'hotplug
') {
4389 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4390 } elsif ($opt eq 'tablet
') {
4391 die "skip\n" if !$hotplug_features->{usb};
4393 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4394 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4395 if $arch eq 'aarch64
';
4396 } elsif ($value == 0) {
4397 vm_deviceunplug($vmid, $conf, 'tablet
');
4398 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4400 } elsif ($opt =~ m/^usb\d+$/) {
4402 # since we cannot reliably hot unplug usb devices
4403 # we are disabling it
4404 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4405 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4406 die "skip\n" if !$d;
4407 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4408 } elsif ($opt eq 'vcpus
') {
4409 die "skip\n" if !$hotplug_features->{cpu};
4410 qemu_cpu_hotplug($vmid, $conf, $value);
4411 } elsif ($opt eq 'balloon
') {
4412 # enable/disable balloning device is not hotpluggable
4413 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4414 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4415 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4417 # allow manual ballooning if shares is set to zero
4418 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4419 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4420 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4422 } elsif ($opt =~ m/^net(\d+)$/) {
4423 # some changes can be done without hotplug
4424 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4425 $vmid, $opt, $value, $arch, $machine_type);
4426 } elsif (is_valid_drivename($opt)) {
4427 die "skip\n" if $opt eq 'efidisk0
';
4428 # some changes can be done without hotplug
4429 my $drive = parse_drive($opt, $value);
4430 if (drive_is_cloudinit($drive)) {
4431 &$apply_pending_cloudinit($opt, $value);
4433 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4434 $vmid, $opt, $value, $arch, $machine_type);
4435 } elsif ($opt =~ m/^memory$/) { #dimms
4436 die "skip\n" if !$hotplug_features->{memory};
4437 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4438 } elsif ($opt eq 'cpuunits
') {
4439 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4440 } elsif ($opt eq 'cpulimit
') {
4441 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4442 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4444 die "skip\n"; # skip non-hot-pluggable options
4448 &$add_error($opt, $err) if $err ne "skip\n";
4450 $conf->{$opt} = $value;
4451 delete $conf->{pending}->{$opt};
4455 PVE::QemuConfig->write_config($vmid, $conf);
4458 sub try_deallocate_drive {
4459 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4461 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4462 my $volid = $drive->{file};
4463 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4464 my $sid = PVE::Storage::parse_volume_id($volid);
4465 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4467 # check if the disk is really unused
4468 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4469 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
4470 PVE::Storage::vdisk_free($storecfg, $volid);
4473 # If vm is not owner of this disk remove from config
4481 sub vmconfig_delete_or_detach_drive {
4482 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4484 my $drive = parse_drive($opt, $conf->{$opt});
4486 my $rpcenv = PVE::RPCEnvironment::get();
4487 my $authuser = $rpcenv->get_user();
4490 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4491 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4493 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4499 sub vmconfig_apply_pending {
4500 my ($vmid, $conf, $storecfg, $errors) = @_;
4502 my $add_apply_error = sub {
4503 my ($opt, $msg) = @_;
4504 my $err_msg = "unable to apply pending change $opt : $msg";
4505 $errors->{$opt} = $err_msg;
4511 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
4512 foreach my $opt (sort keys %$pending_delete_hash) {
4513 my $force = $pending_delete_hash->{$opt}->{force};
4515 if ($opt =~ m/^unused/) {
4516 die "internal error";
4517 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4518 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4522 $add_apply_error->($opt, $err);
4524 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
4525 delete $conf->{$opt};
4529 PVE::QemuConfig->cleanup_pending($conf);
4531 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4532 next if $opt eq 'delete'; # just to be sure
4534 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
4535 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4539 $add_apply_error->($opt, $err);
4541 $conf->{$opt} = delete $conf->{pending}->{$opt};
4545 # write all changes at once to avoid unnecessary i/o
4546 PVE::QemuConfig->write_config($vmid, $conf);
4549 sub vmconfig_update_net {
4550 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4552 my $newnet = parse_net($value);
4554 if ($conf->{$opt}) {
4555 my $oldnet = parse_net($conf->{$opt});
4557 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4558 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4559 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4560 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4562 # for non online change, we try to hot-unplug
4563 die "skip\n" if !$hotplug;
4564 vm_deviceunplug($vmid, $conf, $opt);
4567 die "internal error" if $opt !~ m/net(\d+)/;
4568 my $iface = "tap${vmid}i$1";
4570 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4571 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4572 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4573 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4574 PVE::Network::tap_unplug($iface);
4577 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4579 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4581 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4582 # Rate can be applied on its own but any change above needs to
4583 # include the rate in tap_plug since OVS resets everything.
4584 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4587 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4588 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4596 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4602 sub vmconfig_update_disk {
4603 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4605 my $drive = parse_drive($opt, $value);
4607 if ($conf->{$opt}) {
4609 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4611 my $media = $drive->{media} || 'disk
';
4612 my $oldmedia = $old_drive->{media} || 'disk
';
4613 die "unable to change media type\n" if $media ne $oldmedia;
4615 if (!drive_is_cdrom($old_drive)) {
4617 if ($drive->{file} ne $old_drive->{file}) {
4619 die "skip\n" if !$hotplug;
4621 # unplug and register as unused
4622 vm_deviceunplug($vmid, $conf, $opt);
4623 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4626 # update existing disk
4628 # skip non hotpluggable value
4629 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4630 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4631 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4632 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
4633 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
4638 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4639 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4640 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4641 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4642 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4643 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4644 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4645 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4646 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4647 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4648 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4649 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4650 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4651 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4652 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4653 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4654 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4655 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4657 qemu_block_set_io_throttle($vmid,"drive-$opt",
4658 ($drive->{mbps} || 0)*1024*1024,
4659 ($drive->{mbps_rd} || 0)*1024*1024,
4660 ($drive->{mbps_wr} || 0)*1024*1024,
4661 $drive->{iops} || 0,
4662 $drive->{iops_rd} || 0,
4663 $drive->{iops_wr} || 0,
4664 ($drive->{mbps_max} || 0)*1024*1024,
4665 ($drive->{mbps_rd_max} || 0)*1024*1024,
4666 ($drive->{mbps_wr_max} || 0)*1024*1024,
4667 $drive->{iops_max} || 0,
4668 $drive->{iops_rd_max} || 0,
4669 $drive->{iops_wr_max} || 0,
4670 $drive->{bps_max_length} || 1,
4671 $drive->{bps_rd_max_length} || 1,
4672 $drive->{bps_wr_max_length} || 1,
4673 $drive->{iops_max_length} || 1,
4674 $drive->{iops_rd_max_length} || 1,
4675 $drive->{iops_wr_max_length} || 1);
4684 if ($drive->{file} eq 'none
') {
4685 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4686 if (drive_is_cloudinit($old_drive)) {
4687 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4690 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4692 # force eject if locked
4693 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
4696 mon_cmd($vmid, "blockdev-change-medium",
4697 id => "$opt", filename => "$path");
4706 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4708 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4709 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
4712 # called in locked context by incoming migration
4713 sub vm_migrate_alloc_nbd_disks {
4714 my ($storecfg, $vmid, $conf, $targetstorage, $replicated_volumes) = @_;
4716 my $local_volumes = {};
4717 foreach_drive($conf, sub {
4718 my ($ds, $drive) = @_;
4720 return if drive_is_cdrom($drive);
4722 my $volid = $drive->{file};
4726 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4728 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4729 return if $scfg->{shared};
4730 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4736 foreach my $opt (sort keys %$local_volumes) {
4737 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4738 if ($replicated_volumes->{$volid}) {
4739 # re-use existing, replicated volume with bitmap on source side
4740 $nbd->{$opt} = $conf->{${opt}};
4741 print "re-using replicated volume: $opt - $volid\n";
4744 my $drive = parse_drive($opt, $conf->{$opt});
4746 # If a remote storage is specified and the format of the original
4747 # volume is not available there, fall back to the default format.
4748 # Otherwise use the same format as the original.
4749 if ($targetstorage && $targetstorage ne "1") {
4750 $storeid = $targetstorage;
4751 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4752 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4753 my $fileFormat = qemu_img_format($scfg, $volname);
4754 $format = (grep {$fileFormat eq $_} @{$validFormats}) ? $fileFormat : $defFormat;
4756 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4757 $format = qemu_img_format($scfg, $volname);
4760 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4761 my $newdrive = $drive;
4762 $newdrive->{format} = $format;
4763 $newdrive->{file} = $newvolid;
4764 my $drivestr = print_drive($newdrive);
4765 $nbd->{$opt} = $drivestr;
4766 #pass drive to conf for command line
4767 $conf->{$opt} = $drivestr;
4773 # see vm_start_nolock for parameters, additionally:
4775 # targetstorage = storageid/'1' - target storage for disks migrated over NBD
4777 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
4779 PVE::QemuConfig->lock_config($vmid, sub {
4780 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
4782 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4784 $params->{resume} = PVE::QemuConfig->has_lock($conf, 'suspended
');
4786 PVE::QemuConfig->check_lock($conf)
4787 if !($params->{skiplock} || $params->{resume});
4789 die "VM $vmid already running\n" if check_running($vmid, undef, $migrate_opts->{migratedfrom});
4791 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $conf, $migrate_opts->{targetstorage}, $migrate_opts->{replicated_volumes})
4792 if $migrate_opts->{targetstorage};
4794 vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
4800 # statefile => 'tcp
', 'unix
' for migration or path/volid for RAM state
4801 # skiplock => 0/1, skip checking for config lock
4802 # forcemachine => to force Qemu machine (rollback/migration)
4803 # timeout => in seconds
4804 # paused => start VM in paused state (backup)
4805 # resume => resume from hibernation
4807 # nbd => newly allocated volumes for NBD exports (vm_migrate_alloc_nbd_disks)
4808 # migratedfrom => source node
4809 # spice_ticket => used for spice migration, passed via tunnel/stdin
4810 # network => CIDR of migration network
4811 # type => secure/insecure - tunnel over encrypted connection or plain-text
4812 # nbd_proto_version => int, 0 for TCP, 1 for UNIX
4813 # replicated_volumes = which volids should be re-used with bitmaps for nbd migration
4814 sub vm_start_nolock {
4815 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
4817 my $statefile = $params->{statefile};
4818 my $resume = $params->{resume};
4820 my $migratedfrom = $migrate_opts->{migratedfrom};
4821 my $migration_type = $migrate_opts->{type};
4823 # clean up leftover reboot request files
4824 eval { clear_reboot_request($vmid); };
4827 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4828 vmconfig_apply_pending($vmid, $conf, $storecfg);
4829 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4832 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4834 my $defaults = load_defaults();
4836 # set environment variable useful inside network script
4837 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4839 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
4841 my $forcemachine = $params->{forcemachine};
4843 # enforce machine type on suspended vm to ensure HW compatibility
4844 $forcemachine = $conf->{runningmachine};
4845 print "Resuming suspended VM\n";
4848 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4851 my $get_migration_ip = sub {
4852 my ($nodename) = @_;
4854 return $migration_ip if defined($migration_ip);
4856 my $cidr = $migrate_opts->{network};
4858 if (!defined($cidr)) {
4859 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4860 $cidr = $dc_conf->{migration}->{network};
4863 if (defined($cidr)) {
4864 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
4866 die "could not get IP: no address configured on local " .
4867 "node for network '$cidr'\n" if scalar(@$ips) == 0;
4869 die "could not get IP: multiple addresses configured on local " .
4870 "node for network '$cidr'\n" if scalar(@$ips) > 1;
4872 $migration_ip = @$ips[0];
4875 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
4876 if !defined($migration_ip);
4878 return $migration_ip;
4883 if ($statefile eq 'tcp
') {
4884 my $localip = "localhost";
4885 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4886 my $nodename = nodename();
4888 if (!defined($migration_type)) {
4889 if (defined($datacenterconf->{migration}->{type})) {
4890 $migration_type = $datacenterconf->{migration}->{type};
4892 $migration_type = 'secure
';
4896 if ($migration_type eq 'insecure
') {
4897 $localip = $get_migration_ip->($nodename);
4898 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4901 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4902 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4903 $migrate_uri = "tcp:${localip}:${migrate_port}";
4904 push @$cmd, '-incoming
', $migrate_uri;
4907 } elsif ($statefile eq 'unix
') {
4908 # should be default for secure migrations as a ssh TCP forward
4909 # tunnel is not deterministic reliable ready and fails regurarly
4910 # to set up in time, so use UNIX socket forwards
4911 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4912 unlink $socket_addr;
4914 $migrate_uri = "unix:$socket_addr";
4916 push @$cmd, '-incoming
', $migrate_uri;
4919 } elsif (-e $statefile) {
4920 push @$cmd, '-loadstate
', $statefile;
4922 my $statepath = PVE::Storage::path($storecfg, $statefile);
4923 push @$vollist, $statefile;
4924 push @$cmd, '-loadstate
', $statepath;
4926 } elsif ($params->{paused}) {
4931 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4932 my $d = parse_hostpci($conf->{"hostpci$i"});
4934 my $pcidevices = $d->{pciid};
4935 foreach my $pcidevice (@$pcidevices) {
4936 my $pciid = $pcidevice->{id};
4938 my $info = PVE::SysFSTools::pci_device_info("$pciid");
4939 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
4940 die "no pci device info for device '$pciid'\n" if !$info;
4943 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
4944 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
4946 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
4947 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
4948 die "can
't reset pci device '$pciid'\n"
4949 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
4954 PVE::Storage::activate_volumes($storecfg, $vollist);
4957 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4958 outfunc => sub {}, errfunc => sub {});
4960 # Issues with the above 'stop
' not being fully completed are extremely rare, a very low
4961 # timeout should be more than enough here...
4962 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
4964 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4965 : $defaults->{cpuunits};
4967 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
4969 timeout => $statefile ? undef : $start_timeout,
4974 # when migrating, prefix QEMU output so other side can pick up any
4975 # errors that might occur and show the user
4976 if ($migratedfrom) {
4977 $run_params{quiet} = 1;
4978 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
4982 Slice => 'qemu
.slice
',
4984 CPUShares => $cpuunits
4987 if (my $cpulimit = $conf->{cpulimit}) {
4988 $properties{CPUQuota} = int($cpulimit * 100);
4990 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4992 my $run_qemu = sub {
4993 PVE::Tools::run_fork sub {
4994 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4996 my $exitcode = run_command($cmd, %run_params);
4997 die "QEMU exited with code $exitcode\n" if $exitcode;
5001 if ($conf->{hugepages}) {
5004 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5005 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5007 PVE::QemuServer::Memory::hugepages_mount();
5008 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5010 eval { $run_qemu->() };
5012 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5016 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5018 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5021 eval { $run_qemu->() };
5025 # deactivate volumes if start fails
5026 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5027 die "start failed: $err";
5030 print "migration listens on $migrate_uri\n" if $migrate_uri;
5032 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5033 eval { mon_cmd($vmid, "cont"); };
5037 #start nbd server for storage migration
5038 if (my $nbd = $migrate_opts->{nbd}) {
5039 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
5041 my $migrate_storage_uri;
5042 # nbd_protocol_version > 0 for unix socket support
5043 if ($nbd_protocol_version > 0 && $migration_type eq 'secure
') {
5044 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5045 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix
', data => { path => $socket_path } } );
5046 $migrate_storage_uri = "nbd:unix:$socket_path";
5048 my $nodename = nodename();
5049 my $localip = $get_migration_ip->($nodename);
5050 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5051 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5053 mon_cmd($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
5054 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5055 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
5058 foreach my $opt (sort keys %$nbd) {
5059 my $drivestr = $nbd->{$opt};
5060 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5061 print "storage migration listens on $migrate_storage_uri:exportname=drive-$opt volume:$drivestr\n";
5065 if ($migratedfrom) {
5067 set_migration_caps($vmid);
5072 print "spice listens on port $spice_port\n";
5073 if ($migrate_opts->{spice_ticket}) {
5074 mon_cmd($vmid, "set_password", protocol => 'spice
', password => $migrate_opts->{spice_ticket});
5075 mon_cmd($vmid, "expire_password", protocol => 'spice
', time => "+30");
5080 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5081 if !$statefile && $conf->{balloon};
5083 foreach my $opt (keys %$conf) {
5084 next if $opt !~ m/^net\d+$/;
5085 my $nicconf = parse_net($conf->{$opt});
5086 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5090 mon_cmd($vmid, 'qom-set
',
5091 path => "machine/peripheral/balloon0",
5092 property => "guest-stats-polling-interval",
5093 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5096 print "Resumed VM, removing state\n";
5097 if (my $vmstate = $conf->{vmstate}) {
5098 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5099 PVE::Storage::vdisk_free($storecfg, $vmstate);
5101 delete $conf->@{qw(lock vmstate runningmachine)};
5102 PVE
::QemuConfig-
>write_config($vmid, $conf);
5105 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5108 sub vm_commandline
{
5109 my ($storecfg, $vmid, $snapname) = @_;
5111 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5115 my $snapshot = $conf->{snapshots
}->{$snapname};
5116 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5118 # check for a 'runningmachine' in snapshot
5119 $forcemachine = $snapshot->{runningmachine
} if $snapshot->{runningmachine
};
5121 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5126 my $defaults = load_defaults
();
5128 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults, $forcemachine);
5130 return PVE
::Tools
::cmd2string
($cmd);
5134 my ($vmid, $skiplock) = @_;
5136 PVE
::QemuConfig-
>lock_config($vmid, sub {
5138 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5140 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5142 mon_cmd
($vmid, "system_reset");
5146 sub get_vm_volumes
{
5150 foreach_volid
($conf, sub {
5151 my ($volid, $attr) = @_;
5153 return if $volid =~ m
|^/|;
5155 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5158 push @$vollist, $volid;
5164 sub vm_stop_cleanup
{
5165 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5170 my $vollist = get_vm_volumes
($conf);
5171 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5174 foreach my $ext (qw(mon qmp pid vnc qga)) {
5175 unlink "/var/run/qemu-server/${vmid}.$ext";
5178 if ($conf->{ivshmem
}) {
5179 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5180 # just delete it for now, VMs which have this already open do not
5181 # are affected, but new VMs will get a separated one. If this
5182 # becomes an issue we either add some sort of ref-counting or just
5183 # add a "don't delete on stop" flag to the ivshmem format.
5184 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5187 foreach my $key (keys %$conf) {
5188 next if $key !~ m/^hostpci(\d+)$/;
5189 my $hostpciindex = $1;
5190 my $d = parse_hostpci
($conf->{$key});
5191 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5193 foreach my $pci (@{$d->{pciid
}}) {
5194 my $pciid = $pci->{id
};
5195 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5199 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5201 warn $@ if $@; # avoid errors - just warn
5204 # call only in locked context
5206 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
5208 my $pid = check_running
($vmid, $nocheck);
5213 $conf = PVE
::QemuConfig-
>load_config($vmid);
5214 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5215 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5216 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5217 $timeout = $opts->{down
} if $opts->{down
};
5219 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5224 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5225 mon_cmd
($vmid, "guest-shutdown", timeout
=> $timeout);
5227 mon_cmd
($vmid, "system_powerdown");
5230 mon_cmd
($vmid, "quit");
5236 $timeout = 60 if !defined($timeout);
5239 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5244 if ($count >= $timeout) {
5246 warn "VM still running - terminating now with SIGTERM\n";
5249 die "VM quit/powerdown failed - got timeout\n";
5252 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5257 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5260 die "VM quit/powerdown failed\n";
5268 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5273 if ($count >= $timeout) {
5274 warn "VM still running - terminating now with SIGKILL\n";
5279 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5282 # Note: use $nocheck to skip tests if VM configuration file exists.
5283 # We need that when migration VMs to other nodes (files already moved)
5284 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5286 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5288 $force = 1 if !defined($force) && !$shutdown;
5291 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5292 kill 15, $pid if $pid;
5293 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5294 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5298 PVE
::QemuConfig-
>lock_config($vmid, sub {
5299 _do_vm_stop
($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
5304 my ($vmid, $timeout) = @_;
5306 PVE
::QemuConfig-
>lock_config($vmid, sub {
5309 # only reboot if running, as qmeventd starts it again on a stop event
5310 return if !check_running
($vmid);
5312 create_reboot_request
($vmid);
5314 my $storecfg = PVE
::Storage
::config
();
5315 _do_vm_stop
($storecfg, $vmid, undef, undef, $timeout, 1);
5319 # avoid that the next normal shutdown will be confused for a reboot
5320 clear_reboot_request
($vmid);
5326 # note: if using the statestorage parameter, the caller has to check privileges
5328 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5335 PVE
::QemuConfig-
>lock_config($vmid, sub {
5337 $conf = PVE
::QemuConfig-
>load_config($vmid);
5339 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5340 PVE
::QemuConfig-
>check_lock($conf)
5341 if !($skiplock || $is_backing_up);
5343 die "cannot suspend to disk during backup\n"
5344 if $is_backing_up && $includestate;
5346 if ($includestate) {
5347 $conf->{lock} = 'suspending';
5348 my $date = strftime
("%Y-%m-%d", localtime(time()));
5349 $storecfg = PVE
::Storage
::config
();
5350 if (!$statestorage) {
5351 $statestorage = find_vmstate_storage
($conf, $storecfg);
5352 # check permissions for the storage
5353 my $rpcenv = PVE
::RPCEnvironment
::get
();
5354 if ($rpcenv->{type
} ne 'cli') {
5355 my $authuser = $rpcenv->get_user();
5356 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
5361 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5362 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5363 PVE
::QemuConfig-
>write_config($vmid, $conf);
5365 mon_cmd
($vmid, "stop");
5369 if ($includestate) {
5371 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5374 mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5376 my $state = mon_cmd
($vmid, "query-savevm");
5377 if (!$state->{status
}) {
5378 die "savevm not active\n";
5379 } elsif ($state->{status
} eq 'active') {
5382 } elsif ($state->{status
} eq 'completed') {
5383 print "State saved, quitting\n";
5385 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5386 die "query-savevm failed with error '$state->{error}'\n"
5388 die "query-savevm returned status '$state->{status}'\n";
5394 PVE
::QemuConfig-
>lock_config($vmid, sub {
5395 $conf = PVE
::QemuConfig-
>load_config($vmid);
5397 # cleanup, but leave suspending lock, to indicate something went wrong
5399 mon_cmd
($vmid, "savevm-end");
5400 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5401 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5402 delete $conf->@{qw(vmstate runningmachine)};
5403 PVE
::QemuConfig-
>write_config($vmid, $conf);
5409 die "lock changed unexpectedly\n"
5410 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5412 mon_cmd
($vmid, "quit");
5413 $conf->{lock} = 'suspended';
5414 PVE
::QemuConfig-
>write_config($vmid, $conf);
5420 my ($vmid, $skiplock, $nocheck) = @_;
5422 PVE
::QemuConfig-
>lock_config($vmid, sub {
5423 my $res = mon_cmd
($vmid, 'query-status');
5424 my $resume_cmd = 'cont';
5426 if ($res->{status
} && $res->{status
} eq 'suspended') {
5427 $resume_cmd = 'system_wakeup';
5432 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5434 PVE
::QemuConfig-
>check_lock($conf)
5435 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5438 mon_cmd
($vmid, $resume_cmd);
5443 my ($vmid, $skiplock, $key) = @_;
5445 PVE
::QemuConfig-
>lock_config($vmid, sub {
5447 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5449 # there is no qmp command, so we use the human monitor command
5450 my $res = PVE
::QemuServer
::Monitor
::hmp_cmd
($vmid, "sendkey $key");
5451 die $res if $res ne '';
5455 # vzdump restore implementaion
5457 sub tar_archive_read_firstfile
{
5458 my $archive = shift;
5460 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5462 # try to detect archive type first
5463 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5464 die "unable to open file '$archive'\n";
5465 my $firstfile = <$fh>;
5469 die "ERROR: archive contaions no data\n" if !$firstfile;
5475 sub tar_restore_cleanup
{
5476 my ($storecfg, $statfile) = @_;
5478 print STDERR
"starting cleanup\n";
5480 if (my $fd = IO
::File-
>new($statfile, "r")) {
5481 while (defined(my $line = <$fd>)) {
5482 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5485 if ($volid =~ m
|^/|) {
5486 unlink $volid || die 'unlink failed\n';
5488 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5490 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5492 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5494 print STDERR
"unable to parse line in statfile - $line";
5501 sub restore_file_archive
{
5502 my ($archive, $vmid, $user, $opts) = @_;
5504 my $format = $opts->{format
};
5507 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5508 $format = 'tar' if !$format;
5510 } elsif ($archive =~ m/\.tar$/) {
5511 $format = 'tar' if !$format;
5512 } elsif ($archive =~ m/.tar.lzo$/) {
5513 $format = 'tar' if !$format;
5515 } elsif ($archive =~ m/\.vma$/) {
5516 $format = 'vma' if !$format;
5517 } elsif ($archive =~ m/\.vma\.gz$/) {
5518 $format = 'vma' if !$format;
5520 } elsif ($archive =~ m/\.vma\.lzo$/) {
5521 $format = 'vma' if !$format;
5524 $format = 'vma' if !$format; # default
5527 # try to detect archive format
5528 if ($format eq 'tar') {
5529 return restore_tar_archive
($archive, $vmid, $user, $opts);
5531 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5535 # hepler to remove disks that will not be used after restore
5536 my $restore_cleanup_oldconf = sub {
5537 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
5539 foreach_drive
($oldconf, sub {
5540 my ($ds, $drive) = @_;
5542 return if drive_is_cdrom
($drive, 1);
5544 my $volid = $drive->{file
};
5545 return if !$volid || $volid =~ m
|^/|;
5547 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
5548 return if !$path || !$owner || ($owner != $vmid);
5550 # Note: only delete disk we want to restore
5551 # other volumes will become unused
5552 if ($virtdev_hash->{$ds}) {
5553 eval { PVE
::Storage
::vdisk_free
($storecfg, $volid); };
5560 # delete vmstate files, after the restore we have no snapshots anymore
5561 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5562 my $snap = $oldconf->{snapshots
}->{$snapname};
5563 if ($snap->{vmstate
}) {
5564 eval { PVE
::Storage
::vdisk_free
($storecfg, $snap->{vmstate
}); };
5572 # Helper to parse vzdump backup device hints
5574 # $rpcenv: Environment, used to ckeck storage permissions
5575 # $user: User ID, to check storage permissions
5576 # $storecfg: Storage configuration
5577 # $fh: the file handle for reading the configuration
5578 # $devinfo: should contain device sizes for all backu-up'ed devices
5579 # $options: backup options (pool, default storage)
5581 # Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
5582 my $parse_backup_hints = sub {
5583 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
5585 my $virtdev_hash = {};
5587 while (defined(my $line = <$fh>)) {
5588 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5589 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5590 die "archive does not contain data for drive '$virtdev'\n"
5591 if !$devinfo->{$devname};
5593 if (defined($options->{storage
})) {
5594 $storeid = $options->{storage
} || 'local';
5595 } elsif (!$storeid) {
5598 $format = 'raw' if !$format;
5599 $devinfo->{$devname}->{devname
} = $devname;
5600 $devinfo->{$devname}->{virtdev
} = $virtdev;
5601 $devinfo->{$devname}->{format
} = $format;
5602 $devinfo->{$devname}->{storeid
} = $storeid;
5604 # check permission on storage
5605 my $pool = $options->{pool
}; # todo: do we need that?
5606 if ($user ne 'root@pam') {
5607 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5610 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5611 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
5613 my $drive = parse_drive
($virtdev, $2);
5614 if (drive_is_cloudinit
($drive)) {
5615 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5616 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5617 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
5619 $virtdev_hash->{$virtdev} = {
5621 storeid
=> $options->{storage
} // $storeid,
5622 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
5629 return $virtdev_hash;
5632 # Helper to allocate and activate all volumes required for a restore
5634 # $storecfg: Storage configuration
5635 # $virtdev_hash: as returned by parse_backup_hints()
5637 # Returns: { $virtdev => $volid }
5638 my $restore_allocate_devices = sub {
5639 my ($storecfg, $virtdev_hash, $vmid) = @_;
5642 foreach my $virtdev (sort keys %$virtdev_hash) {
5643 my $d = $virtdev_hash->{$virtdev};
5644 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5645 my $storeid = $d->{storeid
};
5646 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5648 # test if requested format is supported
5649 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5650 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5651 $d->{format
} = $defFormat if !$supported;
5654 if ($d->{is_cloudinit
}) {
5655 $name = "vm-$vmid-cloudinit";
5656 $name .= ".$d->{format}" if $d->{format
} ne 'raw';
5659 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
5661 print STDERR
"new volume ID is '$volid'\n";
5662 $d->{volid
} = $volid;
5664 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
5666 $map->{$virtdev} = $volid;
5672 my $restore_update_config_line = sub {
5673 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5675 return if $line =~ m/^\#qmdump\#/;
5676 return if $line =~ m/^\#vzdump\#/;
5677 return if $line =~ m/^lock:/;
5678 return if $line =~ m/^unused\d+:/;
5679 return if $line =~ m/^parent:/;
5681 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5682 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5683 # try to convert old 1.X settings
5684 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5685 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5686 my ($model, $macaddr) = split(/\=/, $devconfig);
5687 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5690 bridge
=> "vmbr$ind",
5691 macaddr
=> $macaddr,
5693 my $netstr = print_net
($net);
5695 print $outfd "net$cookie->{netcount}: $netstr\n";
5696 $cookie->{netcount
}++;
5698 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5699 my ($id, $netstr) = ($1, $2);
5700 my $net = parse_net
($netstr);
5701 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5702 $netstr = print_net
($net);
5703 print $outfd "$id: $netstr\n";
5704 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5707 my $di = parse_drive
($virtdev, $value);
5708 if (defined($di->{backup
}) && !$di->{backup
}) {
5709 print $outfd "#$line";
5710 } elsif ($map->{$virtdev}) {
5711 delete $di->{format
}; # format can change on restore
5712 $di->{file
} = $map->{$virtdev};
5713 $value = print_drive
($di);
5714 print $outfd "$virtdev: $value\n";
5718 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5720 if ($vmgenid ne '0') {
5721 # always generate a new vmgenid if there was a valid one setup
5722 $vmgenid = generate_uuid
();
5724 print $outfd "vmgenid: $vmgenid\n";
5725 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5726 my ($uuid, $uuid_str);
5727 UUID
::generate
($uuid);
5728 UUID
::unparse
($uuid, $uuid_str);
5729 my $smbios1 = parse_smbios1
($2);
5730 $smbios1->{uuid
} = $uuid_str;
5731 print $outfd $1.print_smbios1
($smbios1)."\n";
5737 my $restore_deactivate_volumes = sub {
5738 my ($storecfg, $devinfo) = @_;
5741 foreach my $devname (keys %$devinfo) {
5742 my $volid = $devinfo->{$devname}->{volid
};
5743 push @$vollist, $volid if $volid;
5746 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5749 my $restore_destroy_volumes = sub {
5750 my ($storecfg, $devinfo) = @_;
5752 foreach my $devname (keys %$devinfo) {
5753 my $volid = $devinfo->{$devname}->{volid
};
5756 if ($volid =~ m
|^/|) {
5757 unlink $volid || die 'unlink failed\n';
5759 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5761 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5763 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5768 my ($cfg, $vmid) = @_;
5770 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5772 my $volid_hash = {};
5773 foreach my $storeid (keys %$info) {
5774 foreach my $item (@{$info->{$storeid}}) {
5775 next if !($item->{volid
} && $item->{size
});
5776 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5777 $volid_hash->{$item->{volid
}} = $item;
5784 sub update_disk_config
{
5785 my ($vmid, $conf, $volid_hash) = @_;
5788 my $prefix = "VM $vmid:";
5790 # used and unused disks
5791 my $referenced = {};
5793 # Note: it is allowed to define multiple storages with same path (alias), so
5794 # we need to check both 'volid' and real 'path' (two different volid can point
5795 # to the same path).
5797 my $referencedpath = {};
5800 PVE
::QemuConfig-
>foreach_volume($conf, sub {
5801 my ($opt, $drive) = @_;
5803 my $volid = $drive->{file
};
5806 # mark volid as "in-use" for next step
5807 $referenced->{$volid} = 1;
5808 if ($volid_hash->{$volid} &&
5809 (my $path = $volid_hash->{$volid}->{path
})) {
5810 $referencedpath->{$path} = 1;
5813 return if drive_is_cdrom
($drive);
5814 return if !$volid_hash->{$volid};
5816 my ($updated, $old_size, $new_size) = PVE
::QemuServer
::Drive
::update_disksize
($drive, $volid_hash);
5817 if (defined($updated)) {
5819 $conf->{$opt} = print_drive
($updated);
5820 print "$prefix size of disk '$volid' ($opt) updated from $old_size to $new_size\n";
5824 # remove 'unusedX' entry if volume is used
5825 PVE
::QemuConfig-
>foreach_unused_volume($conf, sub {
5826 my ($opt, $drive) = @_;
5828 my $volid = $drive->{file
};
5831 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5832 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5833 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5835 delete $conf->{$opt};
5838 $referenced->{$volid} = 1;
5839 $referencedpath->{$path} = 1 if $path;
5842 foreach my $volid (sort keys %$volid_hash) {
5843 next if $volid =~ m/vm-$vmid-state-/;
5844 next if $referenced->{$volid};
5845 my $path = $volid_hash->{$volid}->{path
};
5846 next if !$path; # just to be sure
5847 next if $referencedpath->{$path};
5849 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5850 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
5851 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5858 my ($vmid, $nolock, $dryrun) = @_;
5860 my $cfg = PVE
::Storage
::config
();
5862 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5863 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5864 foreach my $stor (keys %{$cfg->{ids
}}) {
5865 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5868 print "rescan volumes...\n";
5869 my $volid_hash = scan_volids
($cfg, $vmid);
5871 my $updatefn = sub {
5874 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5876 PVE
::QemuConfig-
>check_lock($conf);
5879 foreach my $volid (keys %$volid_hash) {
5880 my $info = $volid_hash->{$volid};
5881 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5884 my $changes = update_disk_config
($vmid, $conf, $vm_volids);
5886 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5889 if (defined($vmid)) {
5893 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5896 my $vmlist = config_list
();
5897 foreach my $vmid (keys %$vmlist) {
5901 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5907 sub restore_proxmox_backup_archive
{
5908 my ($archive, $vmid, $user, $options) = @_;
5910 my $storecfg = PVE
::Storage
::config
();
5912 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($archive);
5913 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5915 my $server = $scfg->{server
};
5916 my $datastore = $scfg->{datastore
};
5917 my $username = $scfg->{username
} // 'root@pam';
5918 my $fingerprint = $scfg->{fingerprint
};
5920 my $repo = "$username\@$server:$datastore";
5921 my $password = PVE
::Storage
::PBSPlugin
::pbs_get_password
($scfg, $storeid);
5922 local $ENV{PBS_PASSWORD
} = $password;
5923 local $ENV{PBS_FINGERPRINT
} = $fingerprint if defined($fingerprint);
5925 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
5926 PVE
::Storage
::parse_volname
($storecfg, $archive);
5928 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
5930 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
5932 my $tmpdir = "/var/tmp/vzdumptmp$$";
5936 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5937 my $tmpfn = "$conffile.$$.tmp";
5938 # disable interrupts (always do cleanups)
5942 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
5944 # Note: $oldconf is undef if VM does not exists
5945 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5946 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5948 my $rpcenv = PVE
::RPCEnvironment
::get
();
5957 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5959 my $cfgfn = "$tmpdir/qemu-server.conf";
5960 my $firewall_config_fn = "$tmpdir/fw.conf";
5961 my $index_fn = "$tmpdir/index.json";
5963 my $cmd = "restore";
5965 my $param = [$pbs_backup_name, "index.json", $index_fn];
5966 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
5967 my $index = PVE
::Tools
::file_get_contents
($index_fn);
5968 $index = decode_json
($index);
5970 # print Dumper($index);
5971 foreach my $info (@{$index->{files
}}) {
5972 if ($info->{filename
} =~ m/^(drive-\S+).img.fidx$/) {
5974 if ($info->{size
} =~ m/^(\d+)$/) { # untaint size
5975 $devinfo->{$devname}->{size
} = $1;
5977 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
5982 my $is_qemu_server_backup = scalar(grep { $_->{filename
} eq 'qemu-server.conf.blob' } @{$index->{files
}});
5983 if (!$is_qemu_server_backup) {
5984 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
5986 my $has_firewall_config = scalar(grep { $_->{filename
} eq 'fw.conf.blob' } @{$index->{files
}});
5988 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
5989 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
5991 if ($has_firewall_config) {
5992 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
5993 PVE
::Storage
::PBSPlugin
::run_raw_client_cmd
($scfg, $storeid, $cmd, $param);
5995 my $pve_firewall_dir = '/etc/pve/firewall';
5996 mkdir $pve_firewall_dir; # make sure the dir exists
5997 PVE
::Tools
::file_copy
($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6000 my $fh = IO
::File-
>new($cfgfn, "r") ||
6001 "unable to read qemu-server.conf - $!\n";
6003 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
6005 # fixme: rate limit?
6007 # create empty/temp config
6008 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\nlock: create");
6010 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6013 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6015 foreach my $virtdev (sort keys %$virtdev_hash) {
6016 my $d = $virtdev_hash->{$virtdev};
6017 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6019 my $volid = $d->{volid
};
6021 my $path = PVE
::Storage
::path
($storecfg, $volid);
6023 my $pbs_restore_cmd = [
6024 '/usr/bin/pbs-restore',
6025 '--repository', $repo,
6027 "$d->{devname}.img.fidx",
6032 if (PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $volid)) {
6033 push @$pbs_restore_cmd, '--skip-zero';
6036 my $dbg_cmdstring = PVE
::Tools
::cmd2string
($pbs_restore_cmd);
6037 print "restore proxmox backup image: $dbg_cmdstring\n";
6038 run_command
($pbs_restore_cmd);
6041 $fh->seek(0, 0) || die "seek failed - $!\n";
6043 my $outfd = new IO
::File
($tmpfn, "w") ||
6044 die "unable to write config for VM $vmid\n";
6046 my $cookie = { netcount
=> 0 };
6047 while (defined(my $line = <$fh>)) {
6048 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $options->{unique
});
6056 $restore_deactivate_volumes->($storecfg, $devinfo);
6062 $restore_destroy_volumes->($storecfg, $devinfo);
6066 rename($tmpfn, $conffile) ||
6067 die "unable to commit configuration file '$conffile'\n";
6069 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6071 eval { rescan
($vmid, 1); };
6075 sub restore_vma_archive
{
6076 my ($archive, $vmid, $user, $opts, $comp) = @_;
6078 my $readfrom = $archive;
6080 my $cfg = PVE
::Storage
::config
();
6082 my $bwlimit = $opts->{bwlimit
};
6084 my $dbg_cmdstring = '';
6085 my $add_pipe = sub {
6087 push @$commands, $cmd;
6088 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6089 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6094 if ($archive eq '-') {
6097 # If we use a backup from a PVE defined storage we also consider that
6098 # storage's rate limit:
6099 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6100 if (defined($volid)) {
6101 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6102 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6104 print STDERR
"applying read rate limit: $readlimit\n";
6105 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6106 $add_pipe->($cstream);
6113 if ($comp eq 'gzip') {
6114 $cmd = ['zcat', $readfrom];
6115 } elsif ($comp eq 'lzop') {
6116 $cmd = ['lzop', '-d', '-c', $readfrom];
6118 die "unknown compression method '$comp'\n";
6123 my $tmpdir = "/var/tmp/vzdumptmp$$";
6126 # disable interrupts (always do cleanups)
6130 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6132 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6133 POSIX
::mkfifo
($mapfifo, 0600);
6136 my $openfifo = sub {
6137 open($fifofh, '>', $mapfifo) || die $!;
6140 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6147 my $rpcenv = PVE
::RPCEnvironment
::get
();
6149 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6150 my $tmpfn = "$conffile.$$.tmp";
6152 # Note: $oldconf is undef if VM does not exist
6153 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6154 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6158 my $print_devmap = sub {
6159 my $cfgfn = "$tmpdir/qemu-server.conf";
6161 # we can read the config - that is already extracted
6162 my $fh = IO
::File-
>new($cfgfn, "r") ||
6163 "unable to read qemu-server.conf - $!\n";
6165 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6167 my $pve_firewall_dir = '/etc/pve/firewall';
6168 mkdir $pve_firewall_dir; # make sure the dir exists
6169 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6172 my $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
6174 foreach my $key (keys %storage_limits) {
6175 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6177 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6178 $storage_limits{$key} = $limit * 1024;
6181 foreach my $devname (keys %$devinfo) {
6182 die "found no device mapping information for device '$devname'\n"
6183 if !$devinfo->{$devname}->{virtdev
};
6186 # create empty/temp config
6188 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6189 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
6193 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
6195 # print restore information to $fifofh
6196 foreach my $virtdev (sort keys %$virtdev_hash) {
6197 my $d = $virtdev_hash->{$virtdev};
6198 next if $d->{is_cloudinit
}; # no need to restore cloudinit
6200 my $storeid = $d->{storeid
};
6201 my $volid = $d->{volid
};
6204 if (my $limit = $storage_limits{$storeid}) {
6205 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6208 my $write_zeros = 1;
6209 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6213 my $path = PVE
::Storage
::path
($cfg, $volid);
6215 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6217 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6220 $fh->seek(0, 0) || die "seek failed - $!\n";
6222 my $outfd = new IO
::File
($tmpfn, "w") ||
6223 die "unable to write config for VM $vmid\n";
6225 my $cookie = { netcount
=> 0 };
6226 while (defined(my $line = <$fh>)) {
6227 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6240 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6241 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6243 $oldtimeout = alarm($timeout);
6250 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6251 my ($dev_id, $size, $devname) = ($1, $2, $3);
6252 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6253 } elsif ($line =~ m/^CTIME: /) {
6254 # we correctly received the vma config, so we can disable
6255 # the timeout now for disk allocation (set to 10 minutes, so
6256 # that we always timeout if something goes wrong)
6259 print $fifofh "done\n";
6260 my $tmp = $oldtimeout || 0;
6261 $oldtimeout = undef;
6267 print "restore vma archive: $dbg_cmdstring\n";
6268 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6272 alarm($oldtimeout) if $oldtimeout;
6274 $restore_deactivate_volumes->($cfg, $devinfo);
6281 $restore_destroy_volumes->($cfg, $devinfo);
6285 rename($tmpfn, $conffile) ||
6286 die "unable to commit configuration file '$conffile'\n";
6288 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6290 eval { rescan
($vmid, 1); };
6294 sub restore_tar_archive
{
6295 my ($archive, $vmid, $user, $opts) = @_;
6297 if ($archive ne '-') {
6298 my $firstfile = tar_archive_read_firstfile
($archive);
6299 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6300 if $firstfile ne 'qemu-server.conf';
6303 my $storecfg = PVE
::Storage
::config
();
6305 # avoid zombie disks when restoring over an existing VM -> cleanup first
6306 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6307 # skiplock=1 because qmrestore has set the 'create' lock itself already
6308 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6309 destroy_vm
($storecfg, $vmid, 1, { lock => 'restore' }) if -f
$vmcfgfn;
6311 my $tocmd = "/usr/lib/qemu-server/qmextract";
6313 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6314 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6315 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6316 $tocmd .= ' --info' if $opts->{info
};
6318 # tar option "xf" does not autodetect compression when read from STDIN,
6319 # so we pipe to zcat
6320 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6321 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6323 my $tmpdir = "/var/tmp/vzdumptmp$$";
6326 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6327 local $ENV{VZDUMP_VMID
} = $vmid;
6328 local $ENV{VZDUMP_USER
} = $user;
6330 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6331 my $tmpfn = "$conffile.$$.tmp";
6333 # disable interrupts (always do cleanups)
6337 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6345 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6347 if ($archive eq '-') {
6348 print "extracting archive from STDIN\n";
6349 run_command
($cmd, input
=> "<&STDIN");
6351 print "extracting archive '$archive'\n";
6355 return if $opts->{info
};
6359 my $statfile = "$tmpdir/qmrestore.stat";
6360 if (my $fd = IO
::File-
>new($statfile, "r")) {
6361 while (defined (my $line = <$fd>)) {
6362 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6363 $map->{$1} = $2 if $1;
6365 print STDERR
"unable to parse line in statfile - $line\n";
6371 my $confsrc = "$tmpdir/qemu-server.conf";
6373 my $srcfd = new IO
::File
($confsrc, "r") ||
6374 die "unable to open file '$confsrc'\n";
6376 my $outfd = new IO
::File
($tmpfn, "w") ||
6377 die "unable to write config for VM $vmid\n";
6379 my $cookie = { netcount
=> 0 };
6380 while (defined (my $line = <$srcfd>)) {
6381 $restore_update_config_line->($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6389 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6395 rename $tmpfn, $conffile ||
6396 die "unable to commit configuration file '$conffile'\n";
6398 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6400 eval { rescan
($vmid, 1); };
6404 sub foreach_storage_used_by_vm
{
6405 my ($conf, $func) = @_;
6409 foreach_drive
($conf, sub {
6410 my ($ds, $drive) = @_;
6411 return if drive_is_cdrom
($drive);
6413 my $volid = $drive->{file
};
6415 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6416 $sidhash->{$sid} = $sid if $sid;
6419 foreach my $sid (sort keys %$sidhash) {
6424 my $qemu_snap_storage = {
6427 sub do_snapshots_with_qemu
{
6428 my ($storecfg, $volid) = @_;
6430 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6431 my $scfg = $storecfg->{ids
}->{$storage_name};
6433 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6437 if ($volid =~ m/\.(qcow2|qed)$/){
6444 sub qga_check_running
{
6445 my ($vmid, $nowarn) = @_;
6447 eval { mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6449 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6455 sub template_create
{
6456 my ($vmid, $conf, $disk) = @_;
6458 my $storecfg = PVE
::Storage
::config
();
6460 foreach_drive
($conf, sub {
6461 my ($ds, $drive) = @_;
6463 return if drive_is_cdrom
($drive);
6464 return if $disk && $ds ne $disk;
6466 my $volid = $drive->{file
};
6467 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6469 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6470 $drive->{file
} = $voliddst;
6471 $conf->{$ds} = print_drive
($drive);
6472 PVE
::QemuConfig-
>write_config($vmid, $conf);
6476 sub convert_iscsi_path
{
6479 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6484 my $initiator_name = get_initiator_name
();
6486 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6487 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6490 die "cannot convert iscsi path '$path', unkown format\n";
6493 sub qemu_img_convert
{
6494 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6496 my $storecfg = PVE
::Storage
::config
();
6497 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6498 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6500 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6504 my $src_is_iscsi = 0;
6508 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6509 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6510 $src_format = qemu_img_format
($src_scfg, $src_volname);
6511 $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6512 $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6513 $cachemode = 'none' if $src_scfg->{type
} eq 'zfspool';
6514 } elsif (-f
$src_volid) {
6515 $src_path = $src_volid;
6516 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6521 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
6523 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6524 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6525 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6526 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6529 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6530 push @$cmd, '-l', "snapshot.name=$snapname"
6531 if $snapname && $src_format && $src_format eq "qcow2";
6532 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6533 push @$cmd, '-T', $cachemode if defined($cachemode);
6535 if ($src_is_iscsi) {
6536 push @$cmd, '--image-opts';
6537 $src_path = convert_iscsi_path
($src_path);
6538 } elsif ($src_format) {
6539 push @$cmd, '-f', $src_format;
6542 if ($dst_is_iscsi) {
6543 push @$cmd, '--target-image-opts';
6544 $dst_path = convert_iscsi_path
($dst_path);
6546 push @$cmd, '-O', $dst_format;
6549 push @$cmd, $src_path;
6551 if (!$dst_is_iscsi && $is_zero_initialized) {
6552 push @$cmd, "zeroinit:$dst_path";
6554 push @$cmd, $dst_path;
6559 if($line =~ m/\((\S+)\/100\
%\)/){
6561 my $transferred = int($size * $percent / 100);
6562 my $remaining = $size - $transferred;
6564 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6569 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6571 die "copy failed: $err" if $err;
6574 sub qemu_img_format
{
6575 my ($scfg, $volname) = @_;
6577 if ($scfg->{path
} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
6584 sub qemu_drive_mirror
{
6585 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
6587 $jobs = {} if !$jobs;
6591 $jobs->{"drive-$drive"} = {};
6593 if ($dst_volid =~ /^nbd:/) {
6594 $qemu_target = $dst_volid;
6597 my $storecfg = PVE
::Storage
::config
();
6598 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6600 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6602 $format = qemu_img_format
($dst_scfg, $dst_volname);
6604 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6606 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6609 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6610 $opts->{format
} = $format if $format;
6612 if (defined($src_bitmap)) {
6613 $opts->{sync
} = 'incremental';
6614 $opts->{bitmap
} = $src_bitmap;
6615 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
6618 if (defined($bwlimit)) {
6619 $opts->{speed
} = $bwlimit * 1024;
6620 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
6622 print "drive mirror is starting for drive-$drive\n";
6625 # if a job already runs for this device we get an error, catch it for cleanup
6626 eval { mon_cmd
($vmid, "drive-mirror", %$opts); };
6628 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6630 die "mirroring error: $err\n";
6633 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $completion, $qga);
6636 # $completion can be either
6637 # 'complete': wait until all jobs are ready, block-job-complete them (default)
6638 # 'cancel': wait until all jobs are ready, block-job-cancel them
6639 # 'skip': wait until all jobs are ready, return with block jobs in ready state
6640 sub qemu_drive_mirror_monitor
{
6641 my ($vmid, $vmiddst, $jobs, $completion, $qga) = @_;
6643 $completion //= 'complete';
6646 my $err_complete = 0;
6649 die "storage migration timed out\n" if $err_complete > 300;
6651 my $stats = mon_cmd
($vmid, "query-block-jobs");
6653 my $running_mirror_jobs = {};
6654 foreach my $stat (@$stats) {
6655 next if $stat->{type
} ne 'mirror';
6656 $running_mirror_jobs->{$stat->{device
}} = $stat;
6659 my $readycounter = 0;
6661 foreach my $job (keys %$jobs) {
6663 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6664 print "$job : finished\n";
6665 delete $jobs->{$job};
6669 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6671 my $busy = $running_mirror_jobs->{$job}->{busy
};
6672 my $ready = $running_mirror_jobs->{$job}->{ready
};
6673 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6674 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6675 my $remaining = $total - $transferred;
6676 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6678 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6681 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6684 last if scalar(keys %$jobs) == 0;
6686 if ($readycounter == scalar(keys %$jobs)) {
6687 print "all mirroring jobs are ready \n";
6688 last if $completion eq 'skip'; #do the complete later
6690 if ($vmiddst && $vmiddst != $vmid) {
6691 my $agent_running = $qga && qga_check_running
($vmid);
6692 if ($agent_running) {
6693 print "freeze filesystem\n";
6694 eval { mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6696 print "suspend vm\n";
6697 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6700 # if we clone a disk for a new target vm, we don't switch the disk
6701 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6703 if ($agent_running) {
6704 print "unfreeze filesystem\n";
6705 eval { mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6707 print "resume vm\n";
6708 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6714 foreach my $job (keys %$jobs) {
6715 # try to switch the disk if source and destination are on the same guest
6716 print "$job: Completing block job...\n";
6719 if ($completion eq 'complete') {
6720 $op = 'block-job-complete';
6721 } elsif ($completion eq 'cancel') {
6722 $op = 'block-job-cancel';
6724 die "invalid completion value: $completion\n";
6726 eval { mon_cmd
($vmid, $op, device
=> $job) };
6727 if ($@ =~ m/cannot be completed/) {
6728 print "$job: Block job cannot be completed, try again.\n";
6731 print "$job: Completed successfully.\n";
6732 $jobs->{$job}->{complete
} = 1;
6743 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6744 die "mirroring error: $err";
6749 sub qemu_blockjobs_cancel
{
6750 my ($vmid, $jobs) = @_;
6752 foreach my $job (keys %$jobs) {
6753 print "$job: Cancelling block job\n";
6754 eval { mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6755 $jobs->{$job}->{cancel
} = 1;
6759 my $stats = mon_cmd
($vmid, "query-block-jobs");
6761 my $running_jobs = {};
6762 foreach my $stat (@$stats) {
6763 $running_jobs->{$stat->{device
}} = $stat;
6766 foreach my $job (keys %$jobs) {
6768 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6769 print "$job: Done.\n";
6770 delete $jobs->{$job};
6774 last if scalar(keys %$jobs) == 0;
6781 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6782 $newvmid, $storage, $format, $full, $newvollist, $jobs, $completion, $qga, $bwlimit, $conf) = @_;
6787 print "create linked clone of drive $drivename ($drive->{file})\n";
6788 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6789 push @$newvollist, $newvolid;
6792 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6793 $storeid = $storage if $storage;
6795 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6796 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6798 print "create full clone of drive $drivename ($drive->{file})\n";
6800 if (drive_is_cloudinit
($drive)) {
6801 $name = "vm-$newvmid-cloudinit";
6802 $name .= ".$dst_format" if $dst_format ne 'raw';
6804 $size = PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
;
6805 } elsif ($drivename eq 'efidisk0') {
6806 $size = get_efivars_size
($conf);
6808 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6809 push @$newvollist, $newvolid;
6811 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6813 if (drive_is_cloudinit
($drive)) {
6817 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6818 if (!$running || $snapname) {
6819 # TODO: handle bwlimits
6820 if ($drivename eq 'efidisk0') {
6821 # the relevant data on the efidisk may be smaller than the source
6822 # e.g. on RBD/ZFS, so we use dd to copy only the amount
6823 # that is given by the OVMF_VARS.fd
6824 my $src_path = PVE
::Storage
::path
($storecfg, $drive->{file
});
6825 my $dst_path = PVE
::Storage
::path
($storecfg, $newvolid);
6826 run_command
(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
6828 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6832 my $kvmver = get_running_qemu_version
($vmid);
6833 if (!min_version
($kvmver, 2, 7)) {
6834 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6835 if $drive->{iothread
};
6838 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $completion, $qga, $bwlimit);
6843 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6846 $disk->{format
} = undef;
6847 $disk->{file
} = $newvolid;
6848 $disk->{size
} = $size;
6853 sub get_running_qemu_version
{
6855 my $res = mon_cmd
($vmid, "query-version");
6856 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6859 sub qemu_use_old_bios_files
{
6860 my ($machine_type) = @_;
6862 return if !$machine_type;
6864 my $use_old_bios_files = undef;
6866 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6868 $use_old_bios_files = 1;
6870 my $version = PVE
::QemuServer
::Machine
::extract_version
($machine_type, kvm_user_version
());
6871 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6872 # load new efi bios files on migration. So this hack is required to allow
6873 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6874 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6875 $use_old_bios_files = !min_version
($version, 2, 4);
6878 return ($use_old_bios_files, $machine_type);
6881 sub get_efivars_size
{
6883 my $arch = get_vm_arch
($conf);
6884 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6885 die "uefi vars image '$ovmf_vars' not found\n" if ! -f
$ovmf_vars;
6886 return -s
$ovmf_vars;
6889 sub update_efidisk_size
{
6892 return if !defined($conf->{efidisk0
});
6894 my $disk = PVE
::QemuServer
::parse_drive
('efidisk0', $conf->{efidisk0
});
6895 $disk->{size
} = get_efivars_size
($conf);
6896 $conf->{efidisk0
} = print_drive
($disk);
6901 sub create_efidisk
($$$$$) {
6902 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6904 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6905 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6907 my $vars_size_b = -s
$ovmf_vars;
6908 my $vars_size = PVE
::Tools
::convert_size
($vars_size_b, 'b' => 'kb');
6909 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6910 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6912 qemu_img_convert
($ovmf_vars, $volid, $vars_size_b, undef, 0);
6913 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $volid, 3);
6915 return ($volid, $size/1024);
6918 sub vm_iothreads_list
{
6921 my $res = mon_cmd
($vmid, 'query-iothreads');
6924 foreach my $iothread (@$res) {
6925 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6932 my ($conf, $drive) = @_;
6936 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6938 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6944 my $controller = int($drive->{index} / $maxdev);
6945 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6947 return ($maxdev, $controller, $controller_prefix);
6950 sub windows_version
{
6953 return 0 if !$ostype;
6957 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6959 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6961 } elsif ($ostype =~ m/^win(\d+)$/) {
6968 sub resolve_dst_disk_format
{
6969 my ($storecfg, $storeid, $src_volname, $format) = @_;
6970 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6973 # if no target format is specified, use the source disk format as hint
6975 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6976 $format = qemu_img_format
($scfg, $src_volname);
6982 # test if requested format is supported - else use default
6983 my $supported = grep { $_ eq $format } @$validFormats;
6984 $format = $defFormat if !$supported;
6988 # NOTE: if this logic changes, please update docs & possibly gui logic
6989 sub find_vmstate_storage
{
6990 my ($conf, $storecfg) = @_;
6992 # first, return storage from conf if set
6993 return $conf->{vmstatestorage
} if $conf->{vmstatestorage
};
6995 my ($target, $shared, $local);
6997 foreach_storage_used_by_vm
($conf, sub {
6999 my $scfg = PVE
::Storage
::storage_config
($storecfg, $sid);
7000 my $dst = $scfg->{shared
} ? \
$shared : \
$local;
7001 $$dst = $sid if !$$dst || $scfg->{path
}; # prefer file based storage
7004 # second, use shared storage where VM has at least one disk
7005 # third, use local storage where VM has at least one disk
7006 # fall back to local storage
7007 $target = $shared // $local // 'local';
7013 my ($uuid, $uuid_str);
7014 UUID
::generate
($uuid);
7015 UUID
::unparse
($uuid, $uuid_str);
7019 sub generate_smbios1_uuid
{
7020 return "uuid=".generate_uuid
();
7026 mon_cmd
($vmid, 'nbd-server-stop');
7029 sub create_reboot_request
{
7031 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7032 or die "failed to create reboot trigger file: $!\n";
7036 sub clear_reboot_request
{
7038 my $path = "/run/qemu-server/$vmid.reboot";
7041 $res = unlink($path);
7042 die "could not remove reboot request for $vmid: $!"
7043 if !$res && $! != POSIX
::ENOENT
;
7048 # bash completion helper
7050 sub complete_backup_archives
{
7051 my ($cmdname, $pname, $cvalue) = @_;
7053 my $cfg = PVE
::Storage
::config
();
7057 if ($cvalue =~ m/^([^:]+):/) {
7061 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7064 foreach my $id (keys %$data) {
7065 foreach my $item (@{$data->{$id}}) {
7066 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7067 push @$res, $item->{volid
} if defined($item->{volid
});
7074 my $complete_vmid_full = sub {
7077 my $idlist = vmstatus
();
7081 foreach my $id (keys %$idlist) {
7082 my $d = $idlist->{$id};
7083 if (defined($running)) {
7084 next if $d->{template
};
7085 next if $running && $d->{status
} ne 'running';
7086 next if !$running && $d->{status
} eq 'running';
7095 return &$complete_vmid_full();
7098 sub complete_vmid_stopped
{
7099 return &$complete_vmid_full(0);
7102 sub complete_vmid_running
{
7103 return &$complete_vmid_full(1);
7106 sub complete_storage
{
7108 my $cfg = PVE
::Storage
::config
();
7109 my $ids = $cfg->{ids
};
7112 foreach my $sid (keys %$ids) {
7113 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7114 next if !$ids->{$sid}->{content
}->{images
};
7121 sub complete_migration_storage
{
7122 my ($cmd, $param, $current_value, $all_args) = @_;
7124 my $targetnode = @$all_args[1];
7126 my $cfg = PVE
::Storage
::config
();
7127 my $ids = $cfg->{ids
};
7130 foreach my $sid (keys %$ids) {
7131 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, $targetnode, 1);
7132 next if !$ids->{$sid}->{content
}->{images
};