1 package PVE
::QemuServer
;
23 use Storable
qw(dclone);
25 use PVE
::Exception
qw(raise raise_param_exc);
27 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
28 use PVE
::JSONSchema
qw(get_standard_option);
29 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
34 use PVE
::RPCEnvironment
;
35 use PVE
::GuestHelpers
;
36 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
37 use PVE
::QemuServer
::Memory
;
38 use PVE
::QemuServer
::USB
qw(parse_usb_device);
39 use PVE
::QemuServer
::Cloudinit
;
42 use Time
::HiRes
qw(gettimeofday);
43 use File
::Copy
qw(copy);
46 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
49 "$EDK2_FW_BASE/OVMF_CODE.fd",
50 "$EDK2_FW_BASE/OVMF_VARS.fd"
53 "$EDK2_FW_BASE/AAVMF_CODE.fd",
54 "$EDK2_FW_BASE/AAVMF_VARS.fd"
58 my $qemu_snap_storage = { rbd
=> 1 };
60 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
62 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
64 # Note about locking: we use flock on the config file protect
65 # against concurent actions.
66 # Aditionaly, we have a 'lock' setting in the config file. This
67 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
68 # allowed when such lock is set. But you can ignore this kind of
69 # lock with the --skiplock flag.
71 cfs_register_file
('/qemu-server/',
75 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
76 description
=> "Some command save/restore state from this location.",
82 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
84 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
85 description
=> "The drive's backing file's data format.",
89 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
90 description
=> "Specifies the Qemu machine type.",
92 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
97 #no warnings 'redefine';
100 my ($controller, $vmid, $option, $value) = @_;
102 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
103 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
107 my $nodename = PVE
::INotify
::nodename
();
109 mkdir "/etc/pve/nodes/$nodename";
110 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
113 my $var_run_tmpdir = "/var/run/qemu-server";
114 mkdir $var_run_tmpdir;
116 my $lock_dir = "/var/lock/qemu-server";
119 my $cpu_vendor_list = {
121 486 => 'GenuineIntel',
122 pentium
=> 'GenuineIntel',
123 pentium2
=> 'GenuineIntel',
124 pentium3
=> 'GenuineIntel',
125 coreduo
=> 'GenuineIntel',
126 core2duo
=> 'GenuineIntel',
127 Conroe
=> 'GenuineIntel',
128 Penryn
=> 'GenuineIntel',
129 Nehalem
=> 'GenuineIntel',
130 'Nehalem-IBRS' => 'GenuineIntel',
131 Westmere
=> 'GenuineIntel',
132 'Westmere-IBRS' => 'GenuineIntel',
133 SandyBridge
=> 'GenuineIntel',
134 'SandyBridge-IBRS' => 'GenuineIntel',
135 IvyBridge
=> 'GenuineIntel',
136 'IvyBridge-IBRS' => 'GenuineIntel',
137 Haswell
=> 'GenuineIntel',
138 'Haswell-IBRS' => 'GenuineIntel',
139 'Haswell-noTSX' => 'GenuineIntel',
140 'Haswell-noTSX-IBRS' => 'GenuineIntel',
141 Broadwell
=> 'GenuineIntel',
142 'Broadwell-IBRS' => 'GenuineIntel',
143 'Broadwell-noTSX' => 'GenuineIntel',
144 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
145 'Skylake-Client' => 'GenuineIntel',
146 'Skylake-Client-IBRS' => 'GenuineIntel',
147 'Skylake-Server' => 'GenuineIntel',
148 'Skylake-Server-IBRS' => 'GenuineIntel',
151 athlon
=> 'AuthenticAMD',
152 phenom
=> 'AuthenticAMD',
153 Opteron_G1
=> 'AuthenticAMD',
154 Opteron_G2
=> 'AuthenticAMD',
155 Opteron_G3
=> 'AuthenticAMD',
156 Opteron_G4
=> 'AuthenticAMD',
157 Opteron_G5
=> 'AuthenticAMD',
158 EPYC
=> 'AuthenticAMD',
159 'EPYC-IBPB' => 'AuthenticAMD',
161 # generic types, use vendor from host node
170 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb|md-clear)/;
174 description
=> "Emulated CPU type.",
176 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
181 description
=> "Do not identify as a KVM virtual machine.",
188 pattern
=> qr/[a-zA-Z0-9]{1,12}/,
189 format_description
=> 'vendor-id',
190 description
=> 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
194 description
=> "List of additional CPU flags separated by ';'."
195 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
196 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb', 'md-clear'.",
197 format_description
=> '+FLAG[;-FLAG...]',
199 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
208 enum
=> [qw(i6300esb ib700)],
209 description
=> "Watchdog type to emulate.",
210 default => 'i6300esb',
215 enum
=> [qw(reset shutdown poweroff pause debug none)],
216 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
220 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
224 description
=> "Enable/disable Qemu GuestAgent.",
229 fstrim_cloned_disks
=> {
230 description
=> "Run fstrim after cloning/moving a disk.",
239 description
=> "Select the VGA type.",
244 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
247 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
259 description
=> "The size of the file in MB.",
263 pattern
=> '[a-zA-Z0-9\-]+',
265 format_description
=> 'string',
266 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
274 description
=> "Specifies whether a VM will be started during system bootup.",
280 description
=> "Automatic restart after crash (currently ignored).",
285 type
=> 'string', format
=> 'pve-hotplug-features',
286 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'.",
287 default => 'network,disk,usb',
292 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
298 description
=> "Lock/unlock the VM.",
299 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
304 description
=> "Limit of CPU usage.",
305 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.",
313 description
=> "CPU weight for a VM.",
314 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.",
322 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
329 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
335 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.",
343 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
344 "It should not be necessary to set it.",
345 enum
=> PVE
::Tools
::kvmkeymaplist
(),
350 type
=> 'string', format
=> 'dns-name',
351 description
=> "Set a name for the VM. Only used on the configuration web interface.",
356 description
=> "SCSI controller model",
357 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
363 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
368 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
369 description
=> "Specify guest operating system.",
370 verbose_description
=> <<EODESC,
371 Specify guest operating system. This is used to enable special
372 optimization/features for specific operating systems:
375 other;; unspecified OS
376 wxp;; Microsoft Windows XP
377 w2k;; Microsoft Windows 2000
378 w2k3;; Microsoft Windows 2003
379 w2k8;; Microsoft Windows 2008
380 wvista;; Microsoft Windows Vista
381 win7;; Microsoft Windows 7
382 win8;; Microsoft Windows 8/2012/2012r2
383 win10;; Microsoft Windows 10/2016
384 l24;; Linux 2.4 Kernel
385 l26;; Linux 2.6/3.X Kernel
386 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
392 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
393 pattern
=> '[acdn]{1,4}',
398 type
=> 'string', format
=> 'pve-qm-bootdisk',
399 description
=> "Enable booting from specified disk.",
400 pattern
=> '(ide|sata|scsi|virtio)\d+',
405 description
=> "The number of CPUs. Please use option -sockets instead.",
412 description
=> "The number of CPU sockets.",
419 description
=> "The number of cores per socket.",
426 description
=> "Enable/disable NUMA.",
432 description
=> "Enable/disable hugepages memory.",
433 enum
=> [qw(any 2 1024)],
438 description
=> "Number of hotplugged vcpus.",
445 description
=> "Enable/disable ACPI.",
450 description
=> "Enable/disable Qemu GuestAgent and its properties.",
452 format
=> $agent_fmt,
457 description
=> "Enable/disable KVM hardware virtualization.",
463 description
=> "Enable/disable time drift fix.",
469 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
474 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
478 type
=> 'string', format
=> $vga_fmt,
479 description
=> "Configure the VGA hardware.",
480 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
481 "high resolution modes (>= 1280x1024x16) you may need to increase " .
482 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
483 "is 'std' for all OS types besides some Windows versions (XP and " .
484 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
485 "display server. For win* OS you can select how many independent " .
486 "displays you want, Linux guests can add displays them self.\n".
487 "You can also run without any graphic card, using a serial device as terminal.",
491 type
=> 'string', format
=> 'pve-qm-watchdog',
492 description
=> "Create a virtual hardware watchdog device.",
493 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
494 " (by a guest action), the watchdog must be periodically polled " .
495 "by an agent inside the guest or else the watchdog will reset " .
496 "the guest (or execute the respective action specified)",
501 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
502 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'.",
503 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
506 startup
=> get_standard_option
('pve-startup-order'),
510 description
=> "Enable/disable Template.",
516 description
=> "Arbitrary arguments passed to kvm.",
517 verbose_description
=> <<EODESCR,
518 Arbitrary arguments passed to kvm, for example:
520 args: -no-reboot -no-hpet
522 NOTE: this option is for experts only.
529 description
=> "Enable/disable the USB tablet device.",
530 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
531 "usually needed to allow absolute mouse positioning with VNC. " .
532 "Else the mouse runs out of sync with normal VNC clients. " .
533 "If you're running lots of console-only guests on one host, " .
534 "you may consider disabling this to save some context switches. " .
535 "This is turned off by default if you use spice (-vga=qxl).",
540 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
544 migrate_downtime
=> {
547 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
553 type
=> 'string', format
=> 'pve-qm-ide',
554 typetext
=> '<volume>',
555 description
=> "This is an alias for option -ide2",
559 description
=> "Emulated CPU type.",
563 parent
=> get_standard_option
('pve-snapshot-name', {
565 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
569 description
=> "Timestamp for snapshots.",
575 type
=> 'string', format
=> 'pve-volume-id',
576 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
578 vmstatestorage
=> get_standard_option
('pve-storage-id', {
579 description
=> "Default storage for VM state volumes/files.",
582 runningmachine
=> get_standard_option
('pve-qemu-machine', {
583 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
585 machine
=> get_standard_option
('pve-qemu-machine'),
587 description
=> "Virtual processor architecture. Defaults to the host.",
590 enum
=> [qw(x86_64 aarch64)],
593 description
=> "Specify SMBIOS type 1 fields.",
594 type
=> 'string', format
=> 'pve-qm-smbios1',
601 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
607 enum
=> [ qw(seabios ovmf) ],
608 description
=> "Select BIOS implementation.",
609 default => 'seabios',
613 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
614 format_description
=> 'UUID',
615 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
616 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
617 " 128-bit integer value identifier to the guest OS. This allows to".
618 " notify the guest operating system when the virtual machine is".
619 " executed with a different configuration (e.g. snapshot execution".
620 " or creation from a template). The guest operating system notices".
621 " the change, and is then able to react as appropriate by marking".
622 " its copies of distributed databases as dirty, re-initializing its".
623 " random number generator, etc.\n".
624 "Note that auto-creation only works when done throug API/CLI create".
625 " or update methods, but not when manually editing the config file.",
626 default => "1 (autogenerated)",
631 format
=> 'pve-volume-id',
633 description
=> "Script that will be executed during various steps in the vms lifetime.",
637 format
=> $ivshmem_fmt,
638 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
647 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.',
648 format
=> 'pve-volume-id',
649 format_description
=> 'volume',
654 description
=> 'Specify a custom file containing all network data passed to the VM via cloud-init.',
655 format
=> 'pve-volume-id',
656 format_description
=> 'volume',
661 description
=> 'Specify a custom file containing all user data passed to the VM via cloud-init.',
662 format
=> 'pve-volume-id',
663 format_description
=> 'volume',
666 PVE
::JSONSchema
::register_format
('pve-qm-cicustom', $cicustom_fmt);
668 my $confdesc_cloudinit = {
672 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.',
673 enum
=> ['configdrive2', 'nocloud'],
678 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
683 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.',
688 description
=> 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
689 format
=> 'pve-qm-cicustom',
694 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.",
698 type
=> 'string', format
=> 'address-list',
699 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.",
704 format
=> 'urlencoded',
705 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
709 # what about other qemu settings ?
711 #machine => 'string',
724 ##soundhw => 'string',
726 while (my ($k, $v) = each %$confdesc) {
727 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
730 my $MAX_IDE_DISKS = 4;
731 my $MAX_SCSI_DISKS = 14;
732 my $MAX_VIRTIO_DISKS = 16;
733 my $MAX_SATA_DISKS = 6;
734 my $MAX_USB_DEVICES = 5;
736 my $MAX_UNUSED_DISKS = 256;
737 my $MAX_HOSTPCI_DEVICES = 4;
738 my $MAX_SERIAL_PORTS = 4;
739 my $MAX_PARALLEL_PORTS = 3;
745 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
746 description
=> "CPUs accessing this NUMA node.",
747 format_description
=> "id[-id];...",
751 description
=> "Amount of memory this NUMA node provides.",
756 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
757 description
=> "Host NUMA nodes to use.",
758 format_description
=> "id[-id];...",
763 enum
=> [qw(preferred bind interleave)],
764 description
=> "NUMA allocation policy.",
768 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
771 type
=> 'string', format
=> $numa_fmt,
772 description
=> "NUMA topology.",
774 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
776 for (my $i = 0; $i < $MAX_NUMA; $i++) {
777 $confdesc->{"numa$i"} = $numadesc;
780 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
781 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
782 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
783 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
785 my $net_fmt_bridge_descr = <<__EOD__;
786 Bridge to attach the network device to. The Proxmox VE standard bridge
789 If you do not specify a bridge, we create a kvm user (NATed) network
790 device, which provides DHCP and DNS services. The following addresses
797 The DHCP server assign addresses to the guest starting from 10.0.2.15.
801 macaddr
=> get_standard_option
('mac-addr', {
802 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
806 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'.",
807 enum
=> $nic_model_list,
810 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
813 description
=> $net_fmt_bridge_descr,
814 format_description
=> 'bridge',
819 minimum
=> 0, maximum
=> 16,
820 description
=> 'Number of packet queues to be used on the device.',
826 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
831 minimum
=> 1, maximum
=> 4094,
832 description
=> 'VLAN tag to apply to packets on this interface.',
837 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
838 description
=> 'VLAN trunks to pass through this interface.',
839 format_description
=> 'vlanid[;vlanid...]',
844 description
=> 'Whether this interface should be protected by the firewall.',
849 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
856 type
=> 'string', format
=> $net_fmt,
857 description
=> "Specify network devices.",
860 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
865 format
=> 'pve-ipv4-config',
866 format_description
=> 'IPv4Format/CIDR',
867 description
=> 'IPv4 address in CIDR format.',
874 format_description
=> 'GatewayIPv4',
875 description
=> 'Default gateway for IPv4 traffic.',
881 format
=> 'pve-ipv6-config',
882 format_description
=> 'IPv6Format/CIDR',
883 description
=> 'IPv6 address in CIDR format.',
890 format_description
=> 'GatewayIPv6',
891 description
=> 'Default gateway for IPv6 traffic.',
896 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
899 type
=> 'string', format
=> 'pve-qm-ipconfig',
900 description
=> <<'EODESCR',
901 cloud-init: Specify IP addresses and gateways for the corresponding interface.
903 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
905 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
906 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
908 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
911 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
913 for (my $i = 0; $i < $MAX_NETS; $i++) {
914 $confdesc->{"net$i"} = $netdesc;
915 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
918 foreach my $key (keys %$confdesc_cloudinit) {
919 $confdesc->{$key} = $confdesc_cloudinit->{$key};
922 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
923 sub verify_volume_id_or_qm_path
{
924 my ($volid, $noerr) = @_;
926 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
930 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
931 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
933 return undef if $noerr;
941 my %drivedesc_base = (
942 volume
=> { alias
=> 'file' },
945 format
=> 'pve-volume-id-or-qm-path',
947 format_description
=> 'volume',
948 description
=> "The drive's backing volume.",
952 enum
=> [qw(cdrom disk)],
953 description
=> "The drive's media type.",
959 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
964 description
=> "Force the drive's physical geometry to have a specific head count.",
969 description
=> "Force the drive's physical geometry to have a specific sector count.",
974 enum
=> [qw(none lba auto)],
975 description
=> "Force disk geometry bios translation mode.",
980 description
=> "Controls qemu's snapshot mode feature."
981 . " If activated, changes made to the disk are temporary and will"
982 . " be discarded when the VM is shutdown.",
987 enum
=> [qw(none writethrough writeback unsafe directsync)],
988 description
=> "The drive's cache mode",
991 format
=> get_standard_option
('pve-qm-image-format'),
994 format
=> 'disk-size',
995 format_description
=> 'DiskSize',
996 description
=> "Disk size. This is purely informational and has no effect.",
1001 description
=> "Whether the drive should be included when making backups.",
1006 description
=> 'Whether the drive should considered for replication jobs.',
1012 enum
=> [qw(ignore report stop)],
1013 description
=> 'Read error action.',
1018 enum
=> [qw(enospc ignore report stop)],
1019 description
=> 'Write error action.',
1024 enum
=> [qw(native threads)],
1025 description
=> 'AIO type to use.',
1030 enum
=> [qw(ignore on)],
1031 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
1036 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
1041 format
=> 'urlencoded',
1042 format_description
=> 'serial',
1043 maxLength
=> 20*3, # *3 since it's %xx url enoded
1044 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
1049 description
=> 'Mark this locally-managed volume as available on all nodes',
1050 verbose_description
=> "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
1056 my %iothread_fmt = ( iothread
=> {
1058 description
=> "Whether to use iothreads for this drive",
1065 format
=> 'urlencoded',
1066 format_description
=> 'model',
1067 maxLength
=> 40*3, # *3 since it's %xx url enoded
1068 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1076 description
=> "Number of queues.",
1082 my %scsiblock_fmt = (
1085 description
=> "whether to use scsi-block for full passthrough of host block device\n\nWARNING: can lead to I/O errors in combination with low memory or high memory fragmentation on host",
1094 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1102 pattern
=> qr/^(0x)[0-9a-fA-F]{16}/,
1103 format_description
=> 'wwn',
1104 description
=> "The drive's worldwide name, encoded as 16 bytes hex string, prefixed by '0x'.",
1109 my $add_throttle_desc = sub {
1110 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1113 format_description
=> $unit,
1114 description
=> "Maximum $what in $longunit.",
1117 $d->{minimum
} = $minimum if defined($minimum);
1118 $drivedesc_base{$key} = $d;
1120 # throughput: (leaky bucket)
1121 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1122 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1123 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1124 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1125 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1126 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1127 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1128 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1129 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1131 # pools: (pool of IO before throttling starts taking effect)
1132 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1133 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1134 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1135 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1136 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1137 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1140 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1141 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1142 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1143 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1144 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1145 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1148 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1149 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1150 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1151 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1159 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1163 type
=> 'string', format
=> $ide_fmt,
1164 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1166 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1178 type
=> 'string', format
=> $scsi_fmt,
1179 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1181 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1190 type
=> 'string', format
=> $sata_fmt,
1191 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1193 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1201 type
=> 'string', format
=> $virtio_fmt,
1202 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1204 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1206 my $alldrive_fmt = {
1217 volume
=> { alias
=> 'file' },
1220 format
=> 'pve-volume-id-or-qm-path',
1222 format_description
=> 'volume',
1223 description
=> "The drive's backing volume.",
1225 format
=> get_standard_option
('pve-qm-image-format'),
1228 format
=> 'disk-size',
1229 format_description
=> 'DiskSize',
1230 description
=> "Disk size. This is purely informational and has no effect.",
1235 my $efidisk_desc = {
1237 type
=> 'string', format
=> $efidisk_fmt,
1238 description
=> "Configure a Disk for storing EFI vars",
1241 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1246 type
=> 'string', format
=> 'pve-qm-usb-device',
1247 format_description
=> 'HOSTUSBDEVICE|spice',
1248 description
=> <<EODESCR,
1249 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1251 'bus-port(.port)*' (decimal numbers) or
1252 'vendor_id:product_id' (hexadeciaml numbers) or
1255 You can use the 'lsusb -t' command to list existing usb devices.
1257 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1259 The value 'spice' can be used to add a usb redirection devices for spice.
1265 description
=> "Specifies whether if given host option is a USB3 device or port (this does currently not work reliably with spice redirection and is then ignored).",
1272 type
=> 'string', format
=> $usb_fmt,
1273 description
=> "Configure an USB device (n is 0 to 4).",
1275 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1277 my $PCIRE = qr/[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1282 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1283 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1284 description
=> <<EODESCR,
1285 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1286 of PCI virtual functions of the host. HOSTPCIID syntax is:
1288 'bus:dev.func' (hexadecimal numbers)
1290 You can us the 'lspci' command to list existing PCI devices.
1295 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1301 pattern
=> '[^,;]+',
1302 format_description
=> 'string',
1303 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1308 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1314 description
=> "Enable vfio-vga device support.",
1320 format_description
=> 'string',
1321 pattern
=> '[^/\.:]+',
1323 description
=> <<EODESCR
1324 The type of mediated device to use.
1325 An instance of this type will be created on startup of the VM and
1326 will be cleaned up when the VM stops.
1330 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1334 type
=> 'string', format
=> 'pve-qm-hostpci',
1335 description
=> "Map host PCI devices into guest.",
1336 verbose_description
=> <<EODESCR,
1337 Map host PCI devices into guest.
1339 NOTE: This option allows direct access to host hardware. So it is no longer
1340 possible to migrate such machines - use with special care.
1342 CAUTION: Experimental! User reported problems with this option.
1345 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1350 pattern
=> '(/dev/.+|socket)',
1351 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1352 verbose_description
=> <<EODESCR,
1353 Create a serial device inside the VM (n is 0 to 3), and pass through a
1354 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1355 host side (use 'qm terminal' to open a terminal connection).
1357 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1359 CAUTION: Experimental! User reported problems with this option.
1366 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1367 description
=> "Map host parallel devices (n is 0 to 2).",
1368 verbose_description
=> <<EODESCR,
1369 Map host parallel devices (n is 0 to 2).
1371 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1373 CAUTION: Experimental! User reported problems with this option.
1377 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1378 $confdesc->{"parallel$i"} = $paralleldesc;
1381 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1382 $confdesc->{"serial$i"} = $serialdesc;
1385 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1386 $confdesc->{"hostpci$i"} = $hostpcidesc;
1389 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1390 $drivename_hash->{"ide$i"} = 1;
1391 $confdesc->{"ide$i"} = $idedesc;
1394 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1395 $drivename_hash->{"sata$i"} = 1;
1396 $confdesc->{"sata$i"} = $satadesc;
1399 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1400 $drivename_hash->{"scsi$i"} = 1;
1401 $confdesc->{"scsi$i"} = $scsidesc ;
1404 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1405 $drivename_hash->{"virtio$i"} = 1;
1406 $confdesc->{"virtio$i"} = $virtiodesc;
1409 $drivename_hash->{efidisk0
} = 1;
1410 $confdesc->{efidisk0
} = $efidisk_desc;
1412 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1413 $confdesc->{"usb$i"} = $usbdesc;
1418 type
=> 'string', format
=> 'pve-volume-id',
1419 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1422 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1423 $confdesc->{"unused$i"} = $unuseddesc;
1426 my $kvm_api_version = 0;
1429 return $kvm_api_version if $kvm_api_version;
1431 open my $fh, '<', '/dev/kvm'
1434 # 0xae00 => KVM_GET_API_VERSION
1435 $kvm_api_version = ioctl($fh, 0xae00, 0);
1437 return $kvm_api_version;
1440 my $kvm_user_version;
1442 sub kvm_user_version
{
1444 return $kvm_user_version if $kvm_user_version;
1446 $kvm_user_version = 'unknown';
1450 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1451 $kvm_user_version = $2;
1455 eval { run_command
("kvm -version", outfunc
=> $code); };
1458 return $kvm_user_version;
1462 sub kernel_has_vhost_net
{
1463 return -c
'/dev/vhost-net';
1466 sub valid_drive_names
{
1467 # order is important - used to autoselect boot disk
1468 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1469 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1470 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1471 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1475 sub is_valid_drivename
{
1478 return defined($drivename_hash->{$dev});
1483 return defined($confdesc->{$key});
1487 return $nic_model_list;
1490 sub os_list_description
{
1494 wxp
=> 'Windows XP',
1495 w2k
=> 'Windows 2000',
1496 w2k3
=>, 'Windows 2003',
1497 w2k8
=> 'Windows 2008',
1498 wvista
=> 'Windows Vista',
1499 win7
=> 'Windows 7',
1500 win8
=> 'Windows 8/2012',
1501 win10
=> 'Windows 10/2016',
1509 sub get_cdrom_path
{
1511 return $cdrom_path if $cdrom_path;
1513 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1514 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1515 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1519 my ($storecfg, $vmid, $cdrom) = @_;
1521 if ($cdrom eq 'cdrom') {
1522 return get_cdrom_path
();
1523 } elsif ($cdrom eq 'none') {
1525 } elsif ($cdrom =~ m
|^/|) {
1528 return PVE
::Storage
::path
($storecfg, $cdrom);
1532 # try to convert old style file names to volume IDs
1533 sub filename_to_volume_id
{
1534 my ($vmid, $file, $media) = @_;
1536 if (!($file eq 'none' || $file eq 'cdrom' ||
1537 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1539 return undef if $file =~ m
|/|;
1541 if ($media && $media eq 'cdrom') {
1542 $file = "local:iso/$file";
1544 $file = "local:$vmid/$file";
1551 sub verify_media_type
{
1552 my ($opt, $vtype, $media) = @_;
1557 if ($media eq 'disk') {
1559 } elsif ($media eq 'cdrom') {
1562 die "internal error";
1565 return if ($vtype eq $etype);
1567 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1570 sub cleanup_drive_path
{
1571 my ($opt, $storecfg, $drive) = @_;
1573 # try to convert filesystem paths to volume IDs
1575 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1576 ($drive->{file
} !~ m
|^/dev/.+|) &&
1577 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1578 ($drive->{file
} !~ m/^\d+$/)) {
1579 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1580 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1581 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1582 verify_media_type
($opt, $vtype, $drive->{media
});
1583 $drive->{file
} = $volid;
1586 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1589 sub parse_hotplug_features
{
1594 return $res if $data eq '0';
1596 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1598 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1599 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1602 die "invalid hotplug feature '$feature'\n";
1608 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1609 sub pve_verify_hotplug_features
{
1610 my ($value, $noerr) = @_;
1612 return $value if parse_hotplug_features
($value);
1614 return undef if $noerr;
1616 die "unable to parse hotplug option\n";
1619 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1620 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1621 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1622 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1623 # [,iothread=on][,serial=serial][,model=model]
1626 my ($key, $data) = @_;
1628 my ($interface, $index);
1630 if ($key =~ m/^([^\d]+)(\d+)$/) {
1637 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1638 : $confdesc->{$key}->{format
};
1640 warn "invalid drive key: $key\n";
1643 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1644 return undef if !$res;
1645 $res->{interface
} = $interface;
1646 $res->{index} = $index;
1649 foreach my $opt (qw(bps bps_rd bps_wr)) {
1650 if (my $bps = defined(delete $res->{$opt})) {
1651 if (defined($res->{"m$opt"})) {
1652 warn "both $opt and m$opt specified\n";
1656 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1660 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1661 for my $requirement (
1662 [mbps_max
=> 'mbps'],
1663 [mbps_rd_max
=> 'mbps_rd'],
1664 [mbps_wr_max
=> 'mbps_wr'],
1665 [miops_max
=> 'miops'],
1666 [miops_rd_max
=> 'miops_rd'],
1667 [miops_wr_max
=> 'miops_wr'],
1668 [bps_max_length
=> 'mbps_max'],
1669 [bps_rd_max_length
=> 'mbps_rd_max'],
1670 [bps_wr_max_length
=> 'mbps_wr_max'],
1671 [iops_max_length
=> 'iops_max'],
1672 [iops_rd_max_length
=> 'iops_rd_max'],
1673 [iops_wr_max_length
=> 'iops_wr_max']) {
1674 my ($option, $requires) = @$requirement;
1675 if ($res->{$option} && !$res->{$requires}) {
1676 warn "$option requires $requires\n";
1681 return undef if $error;
1683 return undef if $res->{mbps_rd
} && $res->{mbps
};
1684 return undef if $res->{mbps_wr
} && $res->{mbps
};
1685 return undef if $res->{iops_rd
} && $res->{iops
};
1686 return undef if $res->{iops_wr
} && $res->{iops
};
1688 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1689 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1690 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1691 return undef if $res->{interface
} eq 'virtio';
1694 if (my $size = $res->{size
}) {
1695 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1702 my ($vmid, $drive) = @_;
1703 my $data = { %$drive };
1704 delete $data->{$_} for qw(index interface);
1705 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1709 my($fh, $noerr) = @_;
1712 my $SG_GET_VERSION_NUM = 0x2282;
1714 my $versionbuf = "\x00" x
8;
1715 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1717 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1720 my $version = unpack("I", $versionbuf);
1721 if ($version < 30000) {
1722 die "scsi generic interface too old\n" if !$noerr;
1726 my $buf = "\x00" x
36;
1727 my $sensebuf = "\x00" x
8;
1728 my $cmd = pack("C x3 C x1", 0x12, 36);
1730 # see /usr/include/scsi/sg.h
1731 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";
1733 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1734 length($sensebuf), 0, length($buf), $buf,
1735 $cmd, $sensebuf, 6000);
1737 $ret = ioctl($fh, $SG_IO, $packet);
1739 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1743 my @res = unpack($sg_io_hdr_t, $packet);
1744 if ($res[17] || $res[18]) {
1745 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1750 (my $byte0, my $byte1, $res->{vendor
},
1751 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1753 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1754 $res->{type
} = $byte0 & 31;
1762 my $fh = IO
::File-
>new("+<$path") || return undef;
1763 my $res = scsi_inquiry
($fh, 1);
1769 sub machine_type_is_q35
{
1772 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1775 sub print_tabletdevice_full
{
1776 my ($conf, $arch) = @_;
1778 my $q35 = machine_type_is_q35
($conf);
1780 # we use uhci for old VMs because tablet driver was buggy in older qemu
1782 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1788 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1791 sub print_keyboarddevice_full
{
1792 my ($conf, $arch, $machine) = @_;
1794 return undef if $arch ne 'aarch64';
1796 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1799 sub print_drivedevice_full
{
1800 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1805 if ($drive->{interface
} eq 'virtio') {
1806 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1807 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1808 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1809 } elsif ($drive->{interface
} eq 'scsi') {
1811 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1812 my $unit = $drive->{index} % $maxdev;
1813 my $devicetype = 'hd';
1815 if (drive_is_cdrom
($drive)) {
1818 if ($drive->{file
} =~ m
|^/|) {
1819 $path = $drive->{file
};
1820 if (my $info = path_is_scsi
($path)) {
1821 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1822 $devicetype = 'block';
1823 } elsif ($info->{type
} == 1) { # tape
1824 $devicetype = 'generic';
1828 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1831 if($path =~ m/^iscsi\:\/\
//){
1832 $devicetype = 'generic';
1836 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1837 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1839 $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}";
1842 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1843 $device .= ",rotation_rate=1";
1845 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1847 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1848 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1849 my $controller = int($drive->{index} / $maxdev);
1850 my $unit = $drive->{index} % $maxdev;
1851 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1853 $device = "ide-$devicetype";
1854 if ($drive->{interface
} eq 'ide') {
1855 $device .= ",bus=ide.$controller,unit=$unit";
1857 $device .= ",bus=ahci$controller.$unit";
1859 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1861 if ($devicetype eq 'hd') {
1862 if (my $model = $drive->{model
}) {
1863 $model = URI
::Escape
::uri_unescape
($model);
1864 $device .= ",model=$model";
1866 if ($drive->{ssd
}) {
1867 $device .= ",rotation_rate=1";
1870 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1871 } elsif ($drive->{interface
} eq 'usb') {
1873 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1875 die "unsupported interface type";
1878 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1880 if (my $serial = $drive->{serial
}) {
1881 $serial = URI
::Escape
::uri_unescape
($serial);
1882 $device .= ",serial=$serial";
1889 sub get_initiator_name
{
1892 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1893 while (defined(my $line = <$fh>)) {
1894 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1903 sub print_drive_full
{
1904 my ($storecfg, $vmid, $drive) = @_;
1907 my $volid = $drive->{file
};
1910 if (drive_is_cdrom
($drive)) {
1911 $path = get_iso_path
($storecfg, $vmid, $volid);
1913 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1915 $path = PVE
::Storage
::path
($storecfg, $volid);
1916 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1917 $format = qemu_img_format
($scfg, $volname);
1925 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1926 foreach my $o (@qemu_drive_options) {
1927 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1930 # snapshot only accepts on|off
1931 if (defined($drive->{snapshot
})) {
1932 my $v = $drive->{snapshot
} ?
'on' : 'off';
1933 $opts .= ",snapshot=$v";
1936 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1937 my ($dir, $qmpname) = @$type;
1938 if (my $v = $drive->{"mbps$dir"}) {
1939 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1941 if (my $v = $drive->{"mbps${dir}_max"}) {
1942 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1944 if (my $v = $drive->{"bps${dir}_max_length"}) {
1945 $opts .= ",throttling.bps$qmpname-max-length=$v";
1947 if (my $v = $drive->{"iops${dir}"}) {
1948 $opts .= ",throttling.iops$qmpname=$v";
1950 if (my $v = $drive->{"iops${dir}_max"}) {
1951 $opts .= ",throttling.iops$qmpname-max=$v";
1953 if (my $v = $drive->{"iops${dir}_max_length"}) {
1954 $opts .= ",throttling.iops$qmpname-max-length=$v";
1958 $opts .= ",format=$format" if $format && !$drive->{format
};
1960 my $cache_direct = 0;
1962 if (my $cache = $drive->{cache
}) {
1963 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1964 } elsif (!drive_is_cdrom
($drive)) {
1965 $opts .= ",cache=none";
1969 # aio native works only with O_DIRECT
1970 if (!$drive->{aio
}) {
1972 $opts .= ",aio=native";
1974 $opts .= ",aio=threads";
1978 if (!drive_is_cdrom
($drive)) {
1980 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1981 $detectzeroes = 'off';
1982 } elsif ($drive->{discard
}) {
1983 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1985 # This used to be our default with discard not being specified:
1986 $detectzeroes = 'on';
1988 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1991 my $pathinfo = $path ?
"file=$path," : '';
1993 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1996 sub print_netdevice_full
{
1997 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1999 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
2001 my $device = $net->{model
};
2002 if ($net->{model
} eq 'virtio') {
2003 $device = 'virtio-net-pci';
2006 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
2007 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
2008 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
2009 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
2010 my $vectors = $net->{queues
} * 2 + 2;
2011 $tmpstr .= ",vectors=$vectors,mq=on";
2013 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
2015 if ($use_old_bios_files) {
2017 if ($device eq 'virtio-net-pci') {
2018 $romfile = 'pxe-virtio.rom';
2019 } elsif ($device eq 'e1000') {
2020 $romfile = 'pxe-e1000.rom';
2021 } elsif ($device eq 'ne2k') {
2022 $romfile = 'pxe-ne2k_pci.rom';
2023 } elsif ($device eq 'pcnet') {
2024 $romfile = 'pxe-pcnet.rom';
2025 } elsif ($device eq 'rtl8139') {
2026 $romfile = 'pxe-rtl8139.rom';
2028 $tmpstr .= ",romfile=$romfile" if $romfile;
2034 sub print_netdev_full
{
2035 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
2038 if ($netid =~ m/^net(\d+)$/) {
2042 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
2044 my $ifname = "tap${vmid}i$i";
2046 # kvm uses TUNSETIFF ioctl, and that limits ifname length
2047 die "interface name '$ifname' is too long (max 15 character)\n"
2048 if length($ifname) >= 16;
2050 my $vhostparam = '';
2051 if (is_native
($arch)) {
2052 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
2055 my $vmname = $conf->{name
} || "vm$vmid";
2058 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
2060 if ($net->{bridge
}) {
2061 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
2063 $netdev = "type=user,id=$netid,hostname=$vmname";
2066 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
2072 sub print_cpu_device
{
2073 my ($conf, $id) = @_;
2075 my $kvm = $conf->{kvm
} // 1;
2076 my $cpu = $kvm ?
"kvm64" : "qemu64";
2077 if (my $cputype = $conf->{cpu
}) {
2078 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
2079 or die "Cannot parse cpu description: $cputype\n";
2080 $cpu = $cpuconf->{cputype
};
2083 my $cores = $conf->{cores
} || 1;
2085 my $current_core = ($id - 1) % $cores;
2086 my $current_socket = int(($id - 1 - $current_core)/$cores);
2088 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2092 'cirrus' => 'cirrus-vga',
2094 'vmware' => 'vmware-svga',
2095 'virtio' => 'virtio-vga',
2098 sub print_vga_device
{
2099 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2101 my $type = $vga_map->{$vga->{type
}};
2102 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
2103 $type = 'virtio-gpu';
2105 my $vgamem_mb = $vga->{memory
};
2107 $type = $id ?
'qxl' : 'qxl-vga';
2109 die "no devicetype for $vga->{type}\n" if !$type;
2113 if ($vga->{type
} eq 'virtio') {
2114 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2115 $memory = ",max_hostmem=$bytes";
2117 # from https://www.spice-space.org/multiple-monitors.html
2118 $memory = ",vgamem_mb=$vga->{memory}";
2119 my $ram = $vgamem_mb * 4;
2120 my $vram = $vgamem_mb * 2;
2121 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2123 $memory = ",vgamem_mb=$vga->{memory}";
2125 } elsif ($qxlnum && $id) {
2126 $memory = ",ram_size=67108864,vram_size=33554432";
2129 my $q35 = machine_type_is_q35
($conf);
2130 my $vgaid = "vga" . ($id // '');
2133 if ($q35 && $vgaid eq 'vga') {
2134 # the first display uses pcie.0 bus on q35 machines
2135 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2137 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2140 return "$type,id=${vgaid}${memory}${pciaddr}";
2143 sub drive_is_cloudinit
{
2145 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2148 sub drive_is_cdrom
{
2149 my ($drive, $exclude_cloudinit) = @_;
2151 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2153 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2157 sub parse_number_sets
{
2160 foreach my $part (split(/;/, $set)) {
2161 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2162 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2163 push @$res, [ $1, $2 ];
2165 die "invalid range: $part\n";
2174 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2175 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2176 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2183 return undef if !$value;
2185 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2187 my @idlist = split(/;/, $res->{host
});
2188 delete $res->{host
};
2189 foreach my $id (@idlist) {
2190 if ($id =~ m/\./) { # full id 00:00.1
2191 push @{$res->{pciid
}}, {
2194 } else { # partial id 00:00
2195 $res->{pciid
} = PVE
::SysFSTools
::lspci
($id);
2201 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2205 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2210 if (!defined($res->{macaddr
})) {
2211 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2212 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2217 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2218 sub parse_ipconfig
{
2221 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2227 if ($res->{gw
} && !$res->{ip
}) {
2228 warn 'gateway specified without specifying an IP address';
2231 if ($res->{gw6
} && !$res->{ip6
}) {
2232 warn 'IPv6 gateway specified without specifying an IPv6 address';
2235 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2236 warn 'gateway specified together with DHCP';
2239 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2241 warn "IPv6 gateway specified together with $res->{ip6} address";
2245 if (!$res->{ip
} && !$res->{ip6
}) {
2246 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2255 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2258 sub add_random_macs
{
2259 my ($settings) = @_;
2261 foreach my $opt (keys %$settings) {
2262 next if $opt !~ m/^net(\d+)$/;
2263 my $net = parse_net
($settings->{$opt});
2265 $settings->{$opt} = print_net
($net);
2269 sub vm_is_volid_owner
{
2270 my ($storecfg, $vmid, $volid) = @_;
2272 if ($volid !~ m
|^/|) {
2274 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2275 if ($owner && ($owner == $vmid)) {
2283 sub split_flagged_list
{
2284 my $text = shift || '';
2285 $text =~ s/[,;]/ /g;
2287 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2290 sub join_flagged_list
{
2291 my ($how, $lst) = @_;
2292 join $how, map { $lst->{$_} . $_ } keys %$lst;
2295 sub vmconfig_delete_pending_option
{
2296 my ($conf, $key, $force) = @_;
2298 delete $conf->{pending
}->{$key};
2299 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2300 $pending_delete_hash->{$key} = $force ?
'!' : '';
2301 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2304 sub vmconfig_undelete_pending_option
{
2305 my ($conf, $key) = @_;
2307 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2308 delete $pending_delete_hash->{$key};
2310 if (%$pending_delete_hash) {
2311 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2313 delete $conf->{pending
}->{delete};
2317 sub vmconfig_register_unused_drive
{
2318 my ($storecfg, $vmid, $conf, $drive) = @_;
2320 if (drive_is_cloudinit
($drive)) {
2321 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2323 } elsif (!drive_is_cdrom
($drive)) {
2324 my $volid = $drive->{file
};
2325 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2326 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2331 sub vmconfig_cleanup_pending
{
2334 # remove pending changes when nothing changed
2336 foreach my $opt (keys %{$conf->{pending
}}) {
2337 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2339 delete $conf->{pending
}->{$opt};
2343 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2344 my $pending_delete_hash = {};
2345 while (my ($opt, $force) = each %$current_delete_hash) {
2346 if (defined($conf->{$opt})) {
2347 $pending_delete_hash->{$opt} = $force;
2353 if (%$pending_delete_hash) {
2354 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2356 delete $conf->{pending
}->{delete};
2362 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
2366 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2367 format_description
=> 'UUID',
2368 description
=> "Set SMBIOS1 UUID.",
2373 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2374 format_description
=> 'Base64 encoded string',
2375 description
=> "Set SMBIOS1 version.",
2380 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2381 format_description
=> 'Base64 encoded string',
2382 description
=> "Set SMBIOS1 serial number.",
2387 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2388 format_description
=> 'Base64 encoded string',
2389 description
=> "Set SMBIOS1 manufacturer.",
2394 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2395 format_description
=> 'Base64 encoded string',
2396 description
=> "Set SMBIOS1 product ID.",
2401 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2402 format_description
=> 'Base64 encoded string',
2403 description
=> "Set SMBIOS1 SKU string.",
2408 pattern
=> '[A-Za-z0-9+\/]+={0,2}',
2409 format_description
=> 'Base64 encoded string',
2410 description
=> "Set SMBIOS1 family string.",
2415 description
=> 'Flag to indicate that the SMBIOS values are base64 encoded',
2423 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2430 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2433 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2435 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2436 sub verify_bootdisk
{
2437 my ($value, $noerr) = @_;
2439 return $value if is_valid_drivename
($value);
2441 return undef if $noerr;
2443 die "invalid boot disk '$value'\n";
2446 sub parse_watchdog
{
2449 return undef if !$value;
2451 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2456 sub parse_guest_agent
{
2459 return {} if !defined($value->{agent
});
2461 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2464 # if the agent is disabled ignore the other potentially set properties
2465 return {} if !$res->{enabled
};
2472 return {} if !$value;
2473 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2478 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2479 sub verify_usb_device
{
2480 my ($value, $noerr) = @_;
2482 return $value if parse_usb_device
($value);
2484 return undef if $noerr;
2486 die "unable to parse usb device\n";
2489 # add JSON properties for create and set function
2490 sub json_config_properties
{
2493 foreach my $opt (keys %$confdesc) {
2494 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2495 $prop->{$opt} = $confdesc->{$opt};
2501 # return copy of $confdesc_cloudinit to generate documentation
2502 sub cloudinit_config_properties
{
2504 return dclone
($confdesc_cloudinit);
2508 my ($key, $value) = @_;
2510 die "unknown setting '$key'\n" if !$confdesc->{$key};
2512 my $type = $confdesc->{$key}->{type
};
2514 if (!defined($value)) {
2515 die "got undefined value\n";
2518 if ($value =~ m/[\n\r]/) {
2519 die "property contains a line feed\n";
2522 if ($type eq 'boolean') {
2523 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2524 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2525 die "type check ('boolean') failed - got '$value'\n";
2526 } elsif ($type eq 'integer') {
2527 return int($1) if $value =~ m/^(\d+)$/;
2528 die "type check ('integer') failed - got '$value'\n";
2529 } elsif ($type eq 'number') {
2530 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2531 die "type check ('number') failed - got '$value'\n";
2532 } elsif ($type eq 'string') {
2533 if (my $fmt = $confdesc->{$key}->{format
}) {
2534 PVE
::JSONSchema
::check_format
($fmt, $value);
2537 $value =~ s/^\"(.*)\"$/$1/;
2540 die "internal error"
2547 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2548 utime undef, undef, $conf;
2552 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2554 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2556 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2558 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2560 if ($conf->{template
}) {
2561 # check if any base image is still used by a linked clone
2562 foreach_drive
($conf, sub {
2563 my ($ds, $drive) = @_;
2565 return if drive_is_cdrom
($drive);
2567 my $volid = $drive->{file
};
2569 return if !$volid || $volid =~ m
|^/|;
2571 die "base volume '$volid' is still in use by linked cloned\n"
2572 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2577 # only remove disks owned by this VM
2578 foreach_drive
($conf, sub {
2579 my ($ds, $drive) = @_;
2581 return if drive_is_cdrom
($drive, 1);
2583 my $volid = $drive->{file
};
2585 return if !$volid || $volid =~ m
|^/|;
2587 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2588 return if !$path || !$owner || ($owner != $vmid);
2591 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2593 warn "Could not remove disk '$volid', check manually: $@" if $@;
2597 if ($keep_empty_config) {
2598 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2603 # also remove unused disk
2605 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2608 PVE
::Storage
::foreach_volid
($dl, sub {
2609 my ($volid, $sid, $volname, $d) = @_;
2610 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2619 sub parse_vm_config
{
2620 my ($filename, $raw) = @_;
2622 return undef if !defined($raw);
2625 digest
=> Digest
::SHA
::sha1_hex
($raw),
2630 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2631 || die "got strange filename '$filename'";
2639 my @lines = split(/\n/, $raw);
2640 foreach my $line (@lines) {
2641 next if $line =~ m/^\s*$/;
2643 if ($line =~ m/^\[PENDING\]\s*$/i) {
2644 $section = 'pending';
2645 if (defined($descr)) {
2647 $conf->{description
} = $descr;
2650 $conf = $res->{$section} = {};
2653 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2655 if (defined($descr)) {
2657 $conf->{description
} = $descr;
2660 $conf = $res->{snapshots
}->{$section} = {};
2664 if ($line =~ m/^\#(.*)\s*$/) {
2665 $descr = '' if !defined($descr);
2666 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2670 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2671 $descr = '' if !defined($descr);
2672 $descr .= PVE
::Tools
::decode_text
($2);
2673 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2674 $conf->{snapstate
} = $1;
2675 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2678 $conf->{$key} = $value;
2679 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2681 if ($section eq 'pending') {
2682 $conf->{delete} = $value; # we parse this later
2684 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2686 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2689 eval { $value = check_type
($key, $value); };
2691 warn "vm $vmid - unable to parse value of '$key' - $@";
2693 $key = 'ide2' if $key eq 'cdrom';
2694 my $fmt = $confdesc->{$key}->{format
};
2695 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2696 my $v = parse_drive
($key, $value);
2697 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2698 $v->{file
} = $volid;
2699 $value = print_drive
($vmid, $v);
2701 warn "vm $vmid - unable to parse value of '$key'\n";
2706 $conf->{$key} = $value;
2711 if (defined($descr)) {
2713 $conf->{description
} = $descr;
2715 delete $res->{snapstate
}; # just to be sure
2720 sub write_vm_config
{
2721 my ($filename, $conf) = @_;
2723 delete $conf->{snapstate
}; # just to be sure
2725 if ($conf->{cdrom
}) {
2726 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2727 $conf->{ide2
} = $conf->{cdrom
};
2728 delete $conf->{cdrom
};
2731 # we do not use 'smp' any longer
2732 if ($conf->{sockets
}) {
2733 delete $conf->{smp
};
2734 } elsif ($conf->{smp
}) {
2735 $conf->{sockets
} = $conf->{smp
};
2736 delete $conf->{cores
};
2737 delete $conf->{smp
};
2740 my $used_volids = {};
2742 my $cleanup_config = sub {
2743 my ($cref, $pending, $snapname) = @_;
2745 foreach my $key (keys %$cref) {
2746 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2747 $key eq 'snapstate' || $key eq 'pending';
2748 my $value = $cref->{$key};
2749 if ($key eq 'delete') {
2750 die "propertry 'delete' is only allowed in [PENDING]\n"
2752 # fixme: check syntax?
2755 eval { $value = check_type
($key, $value); };
2756 die "unable to parse value of '$key' - $@" if $@;
2758 $cref->{$key} = $value;
2760 if (!$snapname && is_valid_drivename
($key)) {
2761 my $drive = parse_drive
($key, $value);
2762 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2767 &$cleanup_config($conf);
2769 &$cleanup_config($conf->{pending
}, 1);
2771 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2772 die "internal error" if $snapname eq 'pending';
2773 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2776 # remove 'unusedX' settings if we re-add a volume
2777 foreach my $key (keys %$conf) {
2778 my $value = $conf->{$key};
2779 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2780 delete $conf->{$key};
2784 my $generate_raw_config = sub {
2785 my ($conf, $pending) = @_;
2789 # add description as comment to top of file
2790 if (defined(my $descr = $conf->{description
})) {
2792 foreach my $cl (split(/\n/, $descr)) {
2793 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2796 $raw .= "#\n" if $pending;
2800 foreach my $key (sort keys %$conf) {
2801 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2802 $raw .= "$key: $conf->{$key}\n";
2807 my $raw = &$generate_raw_config($conf);
2809 if (scalar(keys %{$conf->{pending
}})){
2810 $raw .= "\n[PENDING]\n";
2811 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2814 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2815 $raw .= "\n[$snapname]\n";
2816 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2826 # we use static defaults from our JSON schema configuration
2827 foreach my $key (keys %$confdesc) {
2828 if (defined(my $default = $confdesc->{$key}->{default})) {
2829 $res->{$key} = $default;
2837 my $vmlist = PVE
::Cluster
::get_vmlist
();
2839 return $res if !$vmlist || !$vmlist->{ids
};
2840 my $ids = $vmlist->{ids
};
2842 foreach my $vmid (keys %$ids) {
2843 my $d = $ids->{$vmid};
2844 next if !$d->{node
} || $d->{node
} ne $nodename;
2845 next if !$d->{type
} || $d->{type
} ne 'qemu';
2846 $res->{$vmid}->{exists} = 1;
2851 # test if VM uses local resources (to prevent migration)
2852 sub check_local_resources
{
2853 my ($conf, $noerr) = @_;
2857 push @loc_res, "hostusb" if $conf->{hostusb
}; # old syntax
2858 push @loc_res, "hostpci" if $conf->{hostpci
}; # old syntax
2860 push @loc_res, "ivshmem" if $conf->{ivshmem
};
2862 foreach my $k (keys %$conf) {
2863 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2864 # sockets are safe: they will recreated be on the target side post-migrate
2865 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2866 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2869 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
2874 # check if used storages are available on all nodes (use by migrate)
2875 sub check_storage_availability
{
2876 my ($storecfg, $conf, $node) = @_;
2878 foreach_drive
($conf, sub {
2879 my ($ds, $drive) = @_;
2881 my $volid = $drive->{file
};
2884 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2887 # check if storage is available on both nodes
2888 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2889 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2893 # list nodes where all VM images are available (used by has_feature API)
2895 my ($conf, $storecfg) = @_;
2897 my $nodelist = PVE
::Cluster
::get_nodelist
();
2898 my $nodehash = { map { $_ => 1 } @$nodelist };
2899 my $nodename = PVE
::INotify
::nodename
();
2901 foreach_drive
($conf, sub {
2902 my ($ds, $drive) = @_;
2904 my $volid = $drive->{file
};
2907 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2909 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2910 if ($scfg->{disable
}) {
2912 } elsif (my $avail = $scfg->{nodes
}) {
2913 foreach my $node (keys %$nodehash) {
2914 delete $nodehash->{$node} if !$avail->{$node};
2916 } elsif (!$scfg->{shared
}) {
2917 foreach my $node (keys %$nodehash) {
2918 delete $nodehash->{$node} if $node ne $nodename
2927 sub check_local_storage_availability
{
2928 my ($conf, $storecfg) = @_;
2930 my $nodelist = PVE
::Cluster
::get_nodelist
();
2931 my $nodehash = { map { $_ => {} } @$nodelist };
2933 foreach_drive
($conf, sub {
2934 my ($ds, $drive) = @_;
2936 my $volid = $drive->{file
};
2939 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2941 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2943 if ($scfg->{disable
}) {
2944 foreach my $node (keys %$nodehash) {
2945 push @{$nodehash->{$node}->{not_available_storages
}}, $storeid;
2947 } elsif (my $avail = $scfg->{nodes
}) {
2948 foreach my $node (keys %$nodehash) {
2949 if (!$avail->{$node}) {
2950 push @{$nodehash->{$node}->{not_available_storages
}}, $storeid;
2961 my ($pidfile, $pid) = @_;
2963 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2967 return undef if !$line;
2968 my @param = split(/\0/, $line);
2970 my $cmd = $param[0];
2971 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2973 for (my $i = 0; $i < scalar (@param); $i++) {
2976 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2977 my $p = $param[$i+1];
2978 return 1 if $p && ($p eq $pidfile);
2987 my ($vmid, $nocheck, $node) = @_;
2989 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2991 die "unable to find configuration file for VM $vmid - no such machine\n"
2992 if !$nocheck && ! -f
$filename;
2994 my $pidfile = pidfile_name
($vmid);
2996 if (my $fd = IO
::File-
>new("<$pidfile")) {
3001 my $mtime = $st->mtime;
3002 if ($mtime > time()) {
3003 warn "file '$filename' modified in future\n";
3006 if ($line =~ m/^(\d+)$/) {
3008 if (check_cmdline
($pidfile, $pid)) {
3009 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
3021 my $vzlist = config_list
();
3023 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
3025 while (defined(my $de = $fd->read)) {
3026 next if $de !~ m/^(\d+)\.pid$/;
3028 next if !defined($vzlist->{$vmid});
3029 if (my $pid = check_running
($vmid)) {
3030 $vzlist->{$vmid}->{pid
} = $pid;
3038 my ($storecfg, $conf) = @_;
3040 my $bootdisk = $conf->{bootdisk
};
3041 return undef if !$bootdisk;
3042 return undef if !is_valid_drivename
($bootdisk);
3044 return undef if !$conf->{$bootdisk};
3046 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
3047 return undef if !defined($drive);
3049 return undef if drive_is_cdrom
($drive);
3051 my $volid = $drive->{file
};
3052 return undef if !$volid;
3054 return $drive->{size
};
3057 our $vmstatus_return_properties = {
3058 vmid
=> get_standard_option
('pve-vmid'),
3060 description
=> "Qemu process status.",
3062 enum
=> ['stopped', 'running'],
3065 description
=> "Maximum memory in bytes.",
3068 renderer
=> 'bytes',
3071 description
=> "Root disk size in bytes.",
3074 renderer
=> 'bytes',
3077 description
=> "VM name.",
3082 description
=> "Qemu QMP agent status.",
3087 description
=> "PID of running qemu process.",
3092 description
=> "Uptime.",
3095 renderer
=> 'duration',
3098 description
=> "Maximum usable CPUs.",
3103 description
=> "The current config lock, if any.",
3109 my $last_proc_pid_stat;
3111 # get VM status information
3112 # This must be fast and should not block ($full == false)
3113 # We only query KVM using QMP if $full == true (this can be slow)
3115 my ($opt_vmid, $full) = @_;
3119 my $storecfg = PVE
::Storage
::config
();
3121 my $list = vzlist
();
3122 my $defaults = load_defaults
();
3124 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3126 my $cpucount = $cpuinfo->{cpus
} || 1;
3128 foreach my $vmid (keys %$list) {
3129 next if $opt_vmid && ($vmid ne $opt_vmid);
3131 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3132 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3134 my $d = { vmid
=> $vmid };
3135 $d->{pid
} = $list->{$vmid}->{pid
};
3137 # fixme: better status?
3138 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3140 my $size = disksize
($storecfg, $conf);
3141 if (defined($size)) {
3142 $d->{disk
} = 0; # no info available
3143 $d->{maxdisk
} = $size;
3149 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3150 * ($conf->{cores
} || $defaults->{cores
});
3151 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3152 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3154 $d->{name
} = $conf->{name
} || "VM $vmid";
3155 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3156 : $defaults->{memory
}*(1024*1024);
3158 if ($conf->{balloon
}) {
3159 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3160 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3161 : $defaults->{shares
};
3172 $d->{diskwrite
} = 0;
3174 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3176 $d->{serial
} = 1 if conf_has_serial
($conf);
3177 $d->{lock} = $conf->{lock} if $conf->{lock};
3182 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3183 foreach my $dev (keys %$netdev) {
3184 next if $dev !~ m/^tap([1-9]\d*)i/;
3186 my $d = $res->{$vmid};
3189 $d->{netout
} += $netdev->{$dev}->{receive
};
3190 $d->{netin
} += $netdev->{$dev}->{transmit
};
3193 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3194 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3199 my $ctime = gettimeofday
;
3201 foreach my $vmid (keys %$list) {
3203 my $d = $res->{$vmid};
3204 my $pid = $d->{pid
};
3207 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3208 next if !$pstat; # not running
3210 my $used = $pstat->{utime} + $pstat->{stime
};
3212 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3214 if ($pstat->{vsize
}) {
3215 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3218 my $old = $last_proc_pid_stat->{$pid};
3220 $last_proc_pid_stat->{$pid} = {
3228 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3230 if ($dtime > 1000) {
3231 my $dutime = $used - $old->{used
};
3233 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3234 $last_proc_pid_stat->{$pid} = {
3240 $d->{cpu
} = $old->{cpu
};
3244 return $res if !$full;
3246 my $qmpclient = PVE
::QMPClient-
>new();
3248 my $ballooncb = sub {
3249 my ($vmid, $resp) = @_;
3251 my $info = $resp->{'return'};
3252 return if !$info->{max_mem
};
3254 my $d = $res->{$vmid};
3256 # use memory assigned to VM
3257 $d->{maxmem
} = $info->{max_mem
};
3258 $d->{balloon
} = $info->{actual
};
3260 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3261 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3262 $d->{freemem
} = $info->{free_mem
};
3265 $d->{ballooninfo
} = $info;
3268 my $blockstatscb = sub {
3269 my ($vmid, $resp) = @_;
3270 my $data = $resp->{'return'} || [];
3271 my $totalrdbytes = 0;
3272 my $totalwrbytes = 0;
3274 for my $blockstat (@$data) {
3275 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3276 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3278 $blockstat->{device
} =~ s/drive-//;
3279 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3281 $res->{$vmid}->{diskread
} = $totalrdbytes;
3282 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3285 my $statuscb = sub {
3286 my ($vmid, $resp) = @_;
3288 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3289 # this fails if ballon driver is not loaded, so this must be
3290 # the last commnand (following command are aborted if this fails).
3291 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3293 my $status = 'unknown';
3294 if (!defined($status = $resp->{'return'}->{status
})) {
3295 warn "unable to get VM status\n";
3299 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3302 foreach my $vmid (keys %$list) {
3303 next if $opt_vmid && ($vmid ne $opt_vmid);
3304 next if !$res->{$vmid}->{pid
}; # not running
3305 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3308 $qmpclient->queue_execute(undef, 2);
3310 foreach my $vmid (keys %$list) {
3311 next if $opt_vmid && ($vmid ne $opt_vmid);
3312 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3319 my ($conf, $func, @param) = @_;
3321 foreach my $ds (valid_drive_names
()) {
3322 next if !defined($conf->{$ds});
3324 my $drive = parse_drive
($ds, $conf->{$ds});
3327 &$func($ds, $drive, @param);
3332 my ($conf, $func, @param) = @_;
3336 my $test_volid = sub {
3337 my ($volid, $is_cdrom, $replicate, $shared, $snapname, $size) = @_;
3341 $volhash->{$volid}->{cdrom
} //= 1;
3342 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3344 $volhash->{$volid}->{replicate
} //= 0;
3345 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3347 $volhash->{$volid}->{shared
} //= 0;
3348 $volhash->{$volid}->{shared
} = 1 if $shared;
3350 $volhash->{$volid}->{referenced_in_config
} //= 0;
3351 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3353 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3354 if defined($snapname);
3355 $volhash->{$volid}->{size
} = $size if $size;
3358 foreach_drive
($conf, sub {
3359 my ($ds, $drive) = @_;
3360 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef, $drive->{size
});
3363 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3364 my $snap = $conf->{snapshots
}->{$snapname};
3365 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3366 foreach_drive
($snap, sub {
3367 my ($ds, $drive) = @_;
3368 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3372 foreach my $volid (keys %$volhash) {
3373 &$func($volid, $volhash->{$volid}, @param);
3377 sub conf_has_serial
{
3380 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3381 if ($conf->{"serial$i"}) {
3389 sub vga_conf_has_spice
{
3392 my $vgaconf = parse_vga
($vga);
3393 my $vgatype = $vgaconf->{type
};
3394 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3399 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3400 sub get_host_arch
() {
3401 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3407 return get_host_arch
() eq $arch;
3410 my $default_machines = {
3415 sub get_basic_machine_info
{
3416 my ($conf, $forcemachine) = @_;
3418 my $arch = $conf->{arch
} // get_host_arch
();
3419 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3420 return ($arch, $machine);
3423 sub get_ovmf_files
($) {
3426 my $ovmf = $OVMF->{$arch}
3427 or die "no OVMF images known for architecture '$arch'\n";
3433 aarch64
=> '/usr/bin/qemu-system-aarch64',
3434 x86_64
=> '/usr/bin/qemu-system-x86_64',
3436 sub get_command_for_arch
($) {
3438 return '/usr/bin/kvm' if is_native
($arch);
3440 my $cmd = $Arch2Qemu->{$arch}
3441 or die "don't know how to emulate architecture '$arch'\n";
3445 sub get_cpu_options
{
3446 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3449 my $ostype = $conf->{ostype
};
3451 my $cpu = $kvm ?
"kvm64" : "qemu64";
3452 if ($arch eq 'aarch64') {
3453 $cpu = 'cortex-a57';
3456 if (my $cputype = $conf->{cpu
}) {
3457 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3458 or die "Cannot parse cpu description: $cputype\n";
3459 $cpu = $cpuconf->{cputype
};
3460 $kvm_off = 1 if $cpuconf->{hidden
};
3461 $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
3463 if (defined(my $flags = $cpuconf->{flags
})) {
3464 push @$cpuFlags, split(";", $flags);
3468 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3470 push @$cpuFlags , '-x2apic'
3471 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3473 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3475 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3477 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3479 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3480 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3483 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough, $hv_vendor_id) if $kvm;
3485 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3487 push @$cpuFlags, 'kvm=off' if $kvm_off;
3489 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3490 push @$cpuFlags, "vendor=${cpu_vendor}"
3491 if $cpu_vendor ne 'default';
3492 } elsif ($arch ne 'aarch64') {
3493 die "internal error"; # should not happen
3496 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3498 return ('-cpu', $cpu);
3501 sub config_to_command
{
3502 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3505 my $globalFlags = [];
3506 my $machineFlags = [];
3511 my $kvmver = kvm_user_version
();
3512 my $vernum = 0; # unknown
3513 my $ostype = $conf->{ostype
};
3514 my $winversion = windows_version
($ostype);
3515 my $kvm = $conf->{kvm
};
3517 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3518 $kvm //= 1 if is_native
($arch);
3521 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3522 if !defined kvm_version
();
3525 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3526 $vernum = $1*1000000+$2*1000;
3527 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3528 $vernum = $1*1000000+$2*1000+$3;
3531 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3533 my $have_ovz = -f
'/proc/vz/vestat';
3535 my $q35 = machine_type_is_q35
($conf);
3536 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3537 my $use_old_bios_files = undef;
3538 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3540 my $cpuunits = defined($conf->{cpuunits
}) ?
3541 $conf->{cpuunits
} : $defaults->{cpuunits
};
3543 push @$cmd, get_command_for_arch
($arch);
3545 push @$cmd, '-id', $vmid;
3547 my $vmname = $conf->{name
} || "vm$vmid";
3549 push @$cmd, '-name', $vmname;
3553 my $qmpsocket = qmp_socket
($vmid);
3554 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3555 push @$cmd, '-mon', "chardev=qmp,mode=control";
3557 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3558 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3559 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3562 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3564 push @$cmd, '-daemonize';
3566 if ($conf->{smbios1
}) {
3567 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3568 if ($smbios_conf->{base64
}) {
3569 # Do not pass base64 flag to qemu
3570 delete $smbios_conf->{base64
};
3571 my $smbios_string = "";
3572 foreach my $key (keys %$smbios_conf) {
3574 if ($key eq "uuid") {
3575 $value = $smbios_conf->{uuid
}
3577 $value = decode_base64
($smbios_conf->{$key});
3579 # qemu accepts any binary data, only commas need escaping by double comma
3581 $smbios_string .= "," . $key . "=" . $value if $value;
3583 push @$cmd, '-smbios', "type=1" . $smbios_string;
3585 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3589 if ($conf->{vmgenid
}) {
3590 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3593 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3594 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3595 die "uefi base image not found\n" if ! -f
$ovmf_code;
3599 if (my $efidisk = $conf->{efidisk0
}) {
3600 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3601 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3602 $format = $d->{format
};
3604 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3605 if (!defined($format)) {
3606 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3607 $format = qemu_img_format
($scfg, $volname);
3611 die "efidisk format must be specified\n"
3612 if !defined($format);
3615 warn "no efidisk configured! Using temporary efivars disk.\n";
3616 $path = "/tmp/$vmid-ovmf.fd";
3617 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3621 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3622 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3626 # add usb controllers
3627 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3628 push @$devices, @usbcontrollers if @usbcontrollers;
3629 my $vga = parse_vga
($conf->{vga
});
3631 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3632 $vga->{type
} = 'qxl' if $qxlnum;
3634 if (!$vga->{type
}) {
3635 if ($arch eq 'aarch64') {
3636 $vga->{type
} = 'virtio';
3637 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3638 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3640 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3644 # enable absolute mouse coordinates (needed by vnc)
3646 if (defined($conf->{tablet
})) {
3647 $tablet = $conf->{tablet
};
3649 $tablet = $defaults->{tablet
};
3650 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3651 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3655 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3656 my $kbd = print_keyboarddevice_full
($conf, $arch);
3657 push @$devices, '-device', $kbd if defined($kbd);
3661 my $gpu_passthrough;
3664 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3665 my $d = parse_hostpci
($conf->{"hostpci$i"});
3668 my $pcie = $d->{pcie
};
3670 die "q35 machine model is not enabled" if !$q35;
3671 # win7 wants to have the pcie devices directly on the pcie bus
3672 # instead of in the root port
3673 if ($winversion == 7) {
3674 $pciaddr = print_pcie_addr
("hostpci${i}bus0");
3676 $pciaddr = print_pcie_addr
("hostpci$i");
3679 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3682 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3683 my $romfile = $d->{romfile
};
3686 if ($d->{'x-vga'}) {
3687 $xvga = ',x-vga=on';
3689 $vga->{type
} = 'none' if !defined($conf->{vga
});
3690 $gpu_passthrough = 1;
3692 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3696 my $pcidevices = $d->{pciid
};
3697 my $multifunction = 1 if @$pcidevices > 1;
3699 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3700 my $id = $pcidevices->[0]->{id
};
3701 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3702 $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3703 } elsif ($d->{mdev
}) {
3704 warn "ignoring mediated device with multifunction device\n";
3708 foreach my $pcidevice (@$pcidevices) {
3710 my $id = "hostpci$i";
3711 $id .= ".$j" if $multifunction;
3712 my $addr = $pciaddr;
3713 $addr .= ".$j" if $multifunction;
3714 my $devicestr = "vfio-pci";
3716 $devicestr .= ",sysfsdev=$sysfspath";
3718 $devicestr .= ",host=$pcidevice->{id}";
3720 $devicestr .= ",id=$id$addr";
3723 $devicestr .= "$rombar$xvga";
3724 $devicestr .= ",multifunction=on" if $multifunction;
3725 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3728 push @$devices, '-device', $devicestr;
3734 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3735 push @$devices, @usbdevices if @usbdevices;
3737 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3738 if (my $path = $conf->{"serial$i"}) {
3739 if ($path eq 'socket') {
3740 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3741 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3742 # On aarch64, serial0 is the UART device. Qemu only allows
3743 # connecting UART devices via the '-serial' command line, as
3744 # the device has a fixed slot on the hardware...
3745 if ($arch eq 'aarch64' && $i == 0) {
3746 push @$devices, '-serial', "chardev:serial$i";
3748 push @$devices, '-device', "isa-serial,chardev=serial$i";
3751 die "no such serial device\n" if ! -c
$path;
3752 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3753 push @$devices, '-device', "isa-serial,chardev=serial$i";
3759 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3760 if (my $path = $conf->{"parallel$i"}) {
3761 die "no such parallel device\n" if ! -c
$path;
3762 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3763 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3764 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3770 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3771 $sockets = $conf->{sockets
} if $conf->{sockets
};
3773 my $cores = $conf->{cores
} || 1;
3775 my $maxcpus = $sockets * $cores;
3777 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3779 my $allowed_vcpus = $cpuinfo->{cpus
};
3781 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3782 if ($allowed_vcpus < $maxcpus);
3784 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3786 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3787 for (my $i = 2; $i <= $vcpus; $i++) {
3788 my $cpustr = print_cpu_device
($conf,$i);
3789 push @$cmd, '-device', $cpustr;
3794 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3796 push @$cmd, '-nodefaults';
3798 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3800 my $bootindex_hash = {};
3802 foreach my $o (split(//, $bootorder)) {
3803 $bootindex_hash->{$o} = $i*100;
3807 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3809 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3811 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3813 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3814 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3815 my $socket = vnc_socket
($vmid);
3816 push @$cmd, '-vnc', "unix:$socket,password";
3818 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3819 push @$cmd, '-nographic';
3823 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3825 my $useLocaltime = $conf->{localtime};
3827 if ($winversion >= 5) { # windows
3828 $useLocaltime = 1 if !defined($conf->{localtime});
3830 # use time drift fix when acpi is enabled
3831 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3832 $tdf = 1 if !defined($conf->{tdf
});
3836 if ($winversion >= 6) {
3837 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3838 push @$cmd, '-no-hpet';
3841 push @$rtcFlags, 'driftfix=slew' if $tdf;
3844 push @$machineFlags, 'accel=tcg';
3847 if ($machine_type) {
3848 push @$machineFlags, "type=${machine_type}";
3851 if ($conf->{startdate
}) {
3852 push @$rtcFlags, "base=$conf->{startdate}";
3853 } elsif ($useLocaltime) {
3854 push @$rtcFlags, 'base=localtime';
3857 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3859 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3861 push @$cmd, '-S' if $conf->{freeze
};
3863 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3866 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3867 #push @$cmd, '-soundhw', 'es1370';
3868 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3870 if (parse_guest_agent
($conf)->{enabled
}) {
3871 my $qgasocket = qmp_socket
($vmid, 1);
3872 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3873 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3874 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3875 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3883 for(my $i = 1; $i < $qxlnum; $i++){
3884 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3887 # assume other OS works like Linux
3888 my ($ram, $vram) = ("134217728", "67108864");
3889 if ($vga->{memory
}) {
3890 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3891 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3893 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3894 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3898 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3900 my $nodename = PVE
::INotify
::nodename
();
3901 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3902 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3903 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3904 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3905 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3907 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3909 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3910 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3911 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3914 # enable balloon by default, unless explicitly disabled
3915 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3916 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3917 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3920 if ($conf->{watchdog
}) {
3921 my $wdopts = parse_watchdog
($conf->{watchdog
});
3922 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3923 my $watchdog = $wdopts->{model
} || 'i6300esb';
3924 push @$devices, '-device', "$watchdog$pciaddr";
3925 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3929 my $scsicontroller = {};
3930 my $ahcicontroller = {};
3931 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3933 # Add iscsi initiator name if available
3934 if (my $initiator = get_initiator_name
()) {
3935 push @$devices, '-iscsi', "initiator-name=$initiator";
3938 foreach_drive
($conf, sub {
3939 my ($ds, $drive) = @_;
3941 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3942 push @$vollist, $drive->{file
};
3945 # ignore efidisk here, already added in bios/fw handling code above
3946 return if $drive->{interface
} eq 'efidisk';
3948 $use_virtio = 1 if $ds =~ m/^virtio/;
3950 if (drive_is_cdrom
($drive)) {
3951 if ($bootindex_hash->{d
}) {
3952 $drive->{bootindex
} = $bootindex_hash->{d
};
3953 $bootindex_hash->{d
} += 1;
3956 if ($bootindex_hash->{c
}) {
3957 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3958 $bootindex_hash->{c
} += 1;
3962 if($drive->{interface
} eq 'virtio'){
3963 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3966 if ($drive->{interface
} eq 'scsi') {
3968 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3970 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3971 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3974 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3975 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3976 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3977 } elsif ($drive->{iothread
}) {
3978 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3982 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3983 $queues = ",num_queues=$drive->{queues}";
3986 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3987 $scsicontroller->{$controller}=1;
3990 if ($drive->{interface
} eq 'sata') {
3991 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3992 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3993 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3994 $ahcicontroller->{$controller}=1;
3997 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3998 push @$devices, '-drive',$drive_cmd;
3999 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
4002 for (my $i = 0; $i < $MAX_NETS; $i++) {
4003 next if !$conf->{"net$i"};
4004 my $d = parse_net
($conf->{"net$i"});
4007 $use_virtio = 1 if $d->{model
} eq 'virtio';
4009 if ($bootindex_hash->{n
}) {
4010 $d->{bootindex
} = $bootindex_hash->{n
};
4011 $bootindex_hash->{n
} += 1;
4014 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
4015 push @$devices, '-netdev', $netdevfull;
4017 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
4018 push @$devices, '-device', $netdevicefull;
4021 if ($conf->{ivshmem
}) {
4022 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
4026 $bus = print_pcie_addr
("ivshmem");
4028 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
4031 my $ivshmem_name = $ivshmem->{name
} // $vmid;
4032 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4034 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4035 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
4040 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
4045 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
4047 while (my ($k, $v) = each %$bridges) {
4048 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
4049 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
4053 push @$cmd, @$devices;
4054 push @$cmd, '-rtc', join(',', @$rtcFlags)
4055 if scalar(@$rtcFlags);
4056 push @$cmd, '-machine', join(',', @$machineFlags)
4057 if scalar(@$machineFlags);
4058 push @$cmd, '-global', join(',', @$globalFlags)
4059 if scalar(@$globalFlags);
4061 if (my $vmstate = $conf->{vmstate
}) {
4062 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
4063 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
4064 push @$cmd, '-loadstate', $statepath;
4068 if ($conf->{args
}) {
4069 my $aa = PVE
::Tools
::split_args
($conf->{args
});
4073 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
4078 return "${var_run_tmpdir}/$vmid.vnc";
4084 my $res = vm_mon_cmd
($vmid, 'query-spice');
4086 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
4090 my ($vmid, $qga, $name) = @_;
4091 my $sockettype = $qga ?
'qga' : 'qmp';
4092 my $ext = $name ?
'-'.$name : '';
4093 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
4098 return "${var_run_tmpdir}/$vmid.pid";
4101 sub vm_devices_list
{
4104 my $res = vm_mon_cmd
($vmid, 'query-pci');
4105 my $devices_to_check = [];
4107 foreach my $pcibus (@$res) {
4108 push @$devices_to_check, @{$pcibus->{devices
}},
4111 while (@$devices_to_check) {
4113 for my $d (@$devices_to_check) {
4114 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4115 next if !$d->{'pci_bridge'};
4117 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
4118 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
4120 $devices_to_check = $to_check;
4123 my $resblock = vm_mon_cmd
($vmid, 'query-block');
4124 foreach my $block (@$resblock) {
4125 if($block->{device
} =~ m/^drive-(\S+)/){
4130 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
4131 foreach my $mice (@$resmice) {
4132 if ($mice->{name
} eq 'QEMU HID Tablet') {
4133 $devices->{tablet
} = 1;
4138 # for usb devices there is no query-usb
4139 # but we can iterate over the entries in
4140 # qom-list path=/machine/peripheral
4141 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4142 foreach my $per (@$resperipheral) {
4143 if ($per->{name
} =~ m/^usb\d+$/) {
4144 $devices->{$per->{name
}} = 1;
4152 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4154 my $q35 = machine_type_is_q35
($conf);
4156 my $devices_list = vm_devices_list
($vmid);
4157 return 1 if defined($devices_list->{$deviceid});
4159 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
4161 if ($deviceid eq 'tablet') {
4163 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4165 } elsif ($deviceid eq 'keyboard') {
4167 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4169 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4171 die "usb hotplug currently not reliable\n";
4172 # since we can't reliably hot unplug all added usb devices
4173 # and usb passthrough disables live migration
4174 # we disable usb hotplugging for now
4175 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
4177 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4179 qemu_iothread_add
($vmid, $deviceid, $device);
4181 qemu_driveadd
($storecfg, $vmid, $device);
4182 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4184 qemu_deviceadd
($vmid, $devicefull);
4185 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4187 eval { qemu_drivedel
($vmid, $deviceid); };
4192 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4195 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4196 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4197 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4199 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4201 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4202 qemu_iothread_add
($vmid, $deviceid, $device);
4203 $devicefull .= ",iothread=iothread-$deviceid";
4206 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4207 $devicefull .= ",num_queues=$device->{queues}";
4210 qemu_deviceadd
($vmid, $devicefull);
4211 qemu_deviceaddverify
($vmid, $deviceid);
4213 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4215 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4216 qemu_driveadd
($storecfg, $vmid, $device);
4218 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4219 eval { qemu_deviceadd
($vmid, $devicefull); };
4221 eval { qemu_drivedel
($vmid, $deviceid); };
4226 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4228 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4230 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4231 my $use_old_bios_files = undef;
4232 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4234 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4235 qemu_deviceadd
($vmid, $netdevicefull);
4237 qemu_deviceaddverify
($vmid, $deviceid);
4238 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4241 eval { qemu_netdevdel
($vmid, $deviceid); };
4246 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4249 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4250 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4252 qemu_deviceadd
($vmid, $devicefull);
4253 qemu_deviceaddverify
($vmid, $deviceid);
4256 die "can't hotplug device '$deviceid'\n";
4262 # fixme: this should raise exceptions on error!
4263 sub vm_deviceunplug
{
4264 my ($vmid, $conf, $deviceid) = @_;
4266 my $devices_list = vm_devices_list
($vmid);
4267 return 1 if !defined($devices_list->{$deviceid});
4269 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4271 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4273 qemu_devicedel
($vmid, $deviceid);
4275 } elsif ($deviceid =~ m/^usb\d+$/) {
4277 die "usb hotplug currently not reliable\n";
4278 # when unplugging usb devices this way,
4279 # there may be remaining usb controllers/hubs
4280 # so we disable it for now
4281 qemu_devicedel
($vmid, $deviceid);
4282 qemu_devicedelverify
($vmid, $deviceid);
4284 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4286 qemu_devicedel
($vmid, $deviceid);
4287 qemu_devicedelverify
($vmid, $deviceid);
4288 qemu_drivedel
($vmid, $deviceid);
4289 qemu_iothread_del
($conf, $vmid, $deviceid);
4291 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4293 qemu_devicedel
($vmid, $deviceid);
4294 qemu_devicedelverify
($vmid, $deviceid);
4295 qemu_iothread_del
($conf, $vmid, $deviceid);
4297 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4299 qemu_devicedel
($vmid, $deviceid);
4300 qemu_drivedel
($vmid, $deviceid);
4301 qemu_deletescsihw
($conf, $vmid, $deviceid);
4303 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4305 qemu_devicedel
($vmid, $deviceid);
4306 qemu_devicedelverify
($vmid, $deviceid);
4307 qemu_netdevdel
($vmid, $deviceid);
4310 die "can't unplug device '$deviceid'\n";
4316 sub qemu_deviceadd
{
4317 my ($vmid, $devicefull) = @_;
4319 $devicefull = "driver=".$devicefull;
4320 my %options = split(/[=,]/, $devicefull);
4322 vm_mon_cmd
($vmid, "device_add" , %options);
4325 sub qemu_devicedel
{
4326 my ($vmid, $deviceid) = @_;
4328 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4331 sub qemu_iothread_add
{
4332 my($vmid, $deviceid, $device) = @_;
4334 if ($device->{iothread
}) {
4335 my $iothreads = vm_iothreads_list
($vmid);
4336 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4340 sub qemu_iothread_del
{
4341 my($conf, $vmid, $deviceid) = @_;
4343 my $confid = $deviceid;
4344 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
4345 $confid = 'scsi' . $1;
4347 my $device = parse_drive
($confid, $conf->{$confid});
4348 if ($device->{iothread
}) {
4349 my $iothreads = vm_iothreads_list
($vmid);
4350 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4354 sub qemu_objectadd
{
4355 my($vmid, $objectid, $qomtype) = @_;
4357 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4362 sub qemu_objectdel
{
4363 my($vmid, $objectid) = @_;
4365 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4371 my ($storecfg, $vmid, $device) = @_;
4373 my $drive = print_drive_full
($storecfg, $vmid, $device);
4374 $drive =~ s/\\/\\\\/g;
4375 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4377 # If the command succeeds qemu prints: "OK
"
4378 return 1 if $ret =~ m/OK/s;
4380 die "adding drive failed
: $ret\n";
4384 my($vmid, $deviceid) = @_;
4386 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4389 return 1 if $ret eq "";
4391 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4392 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4394 die "deleting drive
$deviceid failed
: $ret\n";
4397 sub qemu_deviceaddverify {
4398 my ($vmid, $deviceid) = @_;
4400 for (my $i = 0; $i <= 5; $i++) {
4401 my $devices_list = vm_devices_list($vmid);
4402 return 1 if defined($devices_list->{$deviceid});
4406 die "error on hotplug device
'$deviceid'\n";
4410 sub qemu_devicedelverify {
4411 my ($vmid, $deviceid) = @_;
4413 # need to verify that the device is correctly removed as device_del
4414 # is async and empty return is not reliable
4416 for (my $i = 0; $i <= 5; $i++) {
4417 my $devices_list = vm_devices_list($vmid);
4418 return 1 if !defined($devices_list->{$deviceid});
4422 die "error on hot-unplugging device
'$deviceid'\n";
4425 sub qemu_findorcreatescsihw {
4426 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4428 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4430 my $scsihwid="$controller_prefix$controller";
4431 my $devices_list = vm_devices_list($vmid);
4433 if(!defined($devices_list->{$scsihwid})) {
4434 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4440 sub qemu_deletescsihw {
4441 my ($conf, $vmid, $opt) = @_;
4443 my $device = parse_drive($opt, $conf->{$opt});
4445 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4446 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4450 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4452 my $devices_list = vm_devices_list($vmid);
4453 foreach my $opt (keys %{$devices_list}) {
4454 if (PVE::QemuServer::is_valid_drivename($opt)) {
4455 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4456 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4462 my $scsihwid="scsihw
$controller";
4464 vm_deviceunplug($vmid, $conf, $scsihwid);
4469 sub qemu_add_pci_bridge {
4470 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4476 print_pci_addr($device, $bridges, $arch, $machine_type);
4478 while (my ($k, $v) = each %$bridges) {
4481 return 1 if !defined($bridgeid) || $bridgeid < 1;
4483 my $bridge = "pci
.$bridgeid";
4484 my $devices_list = vm_devices_list($vmid);
4486 if (!defined($devices_list->{$bridge})) {
4487 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4493 sub qemu_set_link_status {
4494 my ($vmid, $device, $up) = @_;
4496 vm_mon_cmd($vmid, "set_link
", name => $device,
4497 up => $up ? JSON::true : JSON::false);
4500 sub qemu_netdevadd {
4501 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4503 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4504 my %options = split(/[=,]/, $netdev);
4506 vm_mon_cmd($vmid, "netdev_add
", %options);
4510 sub qemu_netdevdel {
4511 my ($vmid, $deviceid) = @_;
4513 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4516 sub qemu_usb_hotplug {
4517 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4521 # remove the old one first
4522 vm_deviceunplug($vmid, $conf, $deviceid);
4524 # check if xhci controller is necessary and available
4525 if ($device->{usb3}) {
4527 my $devicelist = vm_devices_list($vmid);
4529 if (!$devicelist->{xhci}) {
4530 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4531 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4534 my $d = parse_usb_device($device->{host});
4535 $d->{usb3} = $device->{usb3};
4538 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4541 sub qemu_cpu_hotplug {
4542 my ($vmid, $conf, $vcpus) = @_;
4544 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4547 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4548 $sockets = $conf->{sockets} if $conf->{sockets};
4549 my $cores = $conf->{cores} || 1;
4550 my $maxcpus = $sockets * $cores;
4552 $vcpus = $maxcpus if !$vcpus;
4554 die "you can
't add more vcpus than maxcpus\n"
4555 if $vcpus > $maxcpus;
4557 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4559 if ($vcpus < $currentvcpus) {
4561 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4563 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4564 qemu_devicedel($vmid, "cpu$i");
4566 my $currentrunningvcpus = undef;
4568 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4569 last if scalar(@{$currentrunningvcpus}) == $i-1;
4570 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4574 #update conf after each succesfull cpu unplug
4575 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4576 PVE::QemuConfig->write_config($vmid, $conf);
4579 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4585 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4586 die "vcpus in running vm does not match its configuration\n"
4587 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4589 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4591 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4592 my $cpustr = print_cpu_device($conf, $i);
4593 qemu_deviceadd($vmid, $cpustr);
4596 my $currentrunningvcpus = undef;
4598 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4599 last if scalar(@{$currentrunningvcpus}) == $i;
4600 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4604 #update conf after each succesfull cpu hotplug
4605 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4606 PVE::QemuConfig->write_config($vmid, $conf);
4610 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4611 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4616 sub qemu_block_set_io_throttle {
4617 my ($vmid, $deviceid,
4618 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4619 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4620 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4621 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4623 return if !check_running($vmid) ;
4625 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4627 bps_rd => int($bps_rd),
4628 bps_wr => int($bps_wr),
4630 iops_rd => int($iops_rd),
4631 iops_wr => int($iops_wr),
4632 bps_max => int($bps_max),
4633 bps_rd_max => int($bps_rd_max),
4634 bps_wr_max => int($bps_wr_max),
4635 iops_max => int($iops_max),
4636 iops_rd_max => int($iops_rd_max),
4637 iops_wr_max => int($iops_wr_max),
4638 bps_max_length => int($bps_max_length),
4639 bps_rd_max_length => int($bps_rd_max_length),
4640 bps_wr_max_length => int($bps_wr_max_length),
4641 iops_max_length => int($iops_max_length),
4642 iops_rd_max_length => int($iops_rd_max_length),
4643 iops_wr_max_length => int($iops_wr_max_length),
4648 # old code, only used to shutdown old VM after update
4650 my ($fh, $timeout) = @_;
4652 my $sel = new IO::Select;
4659 while (scalar (@ready = $sel->can_read($timeout))) {
4661 if ($count = $fh->sysread($buf, 8192)) {
4662 if ($buf =~ /^(.*)\(qemu\) $/s) {
4669 if (!defined($count)) {
4676 die "monitor read timeout\n" if !scalar(@ready);
4681 sub qemu_block_resize {
4682 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4684 my $running = check_running($vmid);
4686 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4688 return if !$running;
4690 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4694 sub qemu_volume_snapshot {
4695 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4697 my $running = check_running($vmid);
4699 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4700 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4702 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4706 sub qemu_volume_snapshot_delete {
4707 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4709 my $running = check_running($vmid);
4714 my $conf = PVE::QemuConfig->load_config($vmid);
4715 foreach_drive($conf, sub {
4716 my ($ds, $drive) = @_;
4717 $running = 1 if $drive->{file} eq $volid;
4721 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4722 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4724 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4728 sub set_migration_caps {
4734 "auto-converge" => 1,
4736 "x-rdma-pin-all" => 0,
4741 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4743 for my $supported_capability (@$supported_capabilities) {
4745 capability => $supported_capability->{capability},
4746 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4750 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4753 my $fast_plug_option = {
4761 'vmstatestorage
' => 1,
4765 # hotplug changes in [PENDING]
4766 # $selection hash can be used to only apply specified options, for
4767 # example: { cores => 1 } (only apply changed 'cores
')
4768 # $errors ref is used to return error messages
4769 sub vmconfig_hotplug_pending {
4770 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4772 my $defaults = load_defaults();
4773 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4775 # commit values which do not have any impact on running VM first
4776 # Note: those option cannot raise errors, we we do not care about
4777 # $selection and always apply them.
4779 my $add_error = sub {
4780 my ($opt, $msg) = @_;
4781 $errors->{$opt} = "hotplug problem - $msg";
4785 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4786 if ($fast_plug_option->{$opt}) {
4787 $conf->{$opt} = $conf->{pending}->{$opt};
4788 delete $conf->{pending}->{$opt};
4794 PVE::QemuConfig->write_config($vmid, $conf);
4795 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4798 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4800 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4801 while (my ($opt, $force) = each %$pending_delete_hash) {
4802 next if $selection && !$selection->{$opt};
4804 if ($opt eq 'hotplug
') {
4805 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4806 } elsif ($opt eq 'tablet
') {
4807 die "skip\n" if !$hotplug_features->{usb};
4808 if ($defaults->{tablet}) {
4809 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4810 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4811 if $arch eq 'aarch64
';
4813 vm_deviceunplug($vmid, $conf, 'tablet
');
4814 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4816 } elsif ($opt =~ m/^usb\d+/) {
4818 # since we cannot reliably hot unplug usb devices
4819 # we are disabling it
4820 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4821 vm_deviceunplug($vmid, $conf, $opt);
4822 } elsif ($opt eq 'vcpus
') {
4823 die "skip\n" if !$hotplug_features->{cpu};
4824 qemu_cpu_hotplug($vmid, $conf, undef);
4825 } elsif ($opt eq 'balloon
') {
4826 # enable balloon device is not hotpluggable
4827 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4828 # here we reset the ballooning value to memory
4829 my $balloon = $conf->{memory} || $defaults->{memory};
4830 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4831 } elsif ($fast_plug_option->{$opt}) {
4833 } elsif ($opt =~ m/^net(\d+)$/) {
4834 die "skip\n" if !$hotplug_features->{network};
4835 vm_deviceunplug($vmid, $conf, $opt);
4836 } elsif (is_valid_drivename($opt)) {
4837 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4838 vm_deviceunplug($vmid, $conf, $opt);
4839 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4840 } elsif ($opt =~ m/^memory$/) {
4841 die "skip\n" if !$hotplug_features->{memory};
4842 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4843 } elsif ($opt eq 'cpuunits
') {
4844 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4845 } elsif ($opt eq 'cpulimit
') {
4846 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4852 &$add_error($opt, $err) if $err ne "skip\n";
4854 # save new config if hotplug was successful
4855 delete $conf->{$opt};
4856 vmconfig_undelete_pending_option($conf, $opt);
4857 PVE::QemuConfig->write_config($vmid, $conf);
4858 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4862 my $apply_pending_cloudinit;
4863 $apply_pending_cloudinit = sub {
4864 my ($key, $value) = @_;
4865 $apply_pending_cloudinit = sub {}; # once is enough
4867 my @cloudinit_opts = keys %$confdesc_cloudinit;
4868 foreach my $opt (keys %{$conf->{pending}}) {
4869 next if !grep { $_ eq $opt } @cloudinit_opts;
4870 $conf->{$opt} = delete $conf->{pending}->{$opt};
4873 my $new_conf = { %$conf };
4874 $new_conf->{$key} = $value;
4875 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4878 foreach my $opt (keys %{$conf->{pending}}) {
4879 next if $selection && !$selection->{$opt};
4880 my $value = $conf->{pending}->{$opt};
4882 if ($opt eq 'hotplug
') {
4883 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4884 } elsif ($opt eq 'tablet
') {
4885 die "skip\n" if !$hotplug_features->{usb};
4887 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4888 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4889 if $arch eq 'aarch64
';
4890 } elsif ($value == 0) {
4891 vm_deviceunplug($vmid, $conf, 'tablet
');
4892 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4894 } elsif ($opt =~ m/^usb\d+$/) {
4896 # since we cannot reliably hot unplug usb devices
4897 # we are disabling it
4898 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4899 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4900 die "skip\n" if !$d;
4901 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4902 } elsif ($opt eq 'vcpus
') {
4903 die "skip\n" if !$hotplug_features->{cpu};
4904 qemu_cpu_hotplug($vmid, $conf, $value);
4905 } elsif ($opt eq 'balloon
') {
4906 # enable/disable balloning device is not hotpluggable
4907 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4908 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4909 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4911 # allow manual ballooning if shares is set to zero
4912 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4913 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4914 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4916 } elsif ($opt =~ m/^net(\d+)$/) {
4917 # some changes can be done without hotplug
4918 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4919 $vmid, $opt, $value, $arch, $machine_type);
4920 } elsif (is_valid_drivename($opt)) {
4921 # some changes can be done without hotplug
4922 my $drive = parse_drive($opt, $value);
4923 if (drive_is_cloudinit($drive)) {
4924 &$apply_pending_cloudinit($opt, $value);
4926 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4927 $vmid, $opt, $value, 1, $arch, $machine_type);
4928 } elsif ($opt =~ m/^memory$/) { #dimms
4929 die "skip\n" if !$hotplug_features->{memory};
4930 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4931 } elsif ($opt eq 'cpuunits
') {
4932 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4933 } elsif ($opt eq 'cpulimit
') {
4934 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4935 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4937 die "skip\n"; # skip non-hot-pluggable options
4941 &$add_error($opt, $err) if $err ne "skip\n";
4943 # save new config if hotplug was successful
4944 $conf->{$opt} = $value;
4945 delete $conf->{pending}->{$opt};
4946 PVE::QemuConfig->write_config($vmid, $conf);
4947 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4952 sub try_deallocate_drive {
4953 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4955 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4956 my $volid = $drive->{file};
4957 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4958 my $sid = PVE::Storage::parse_volume_id($volid);
4959 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4961 # check if the disk is really unused
4962 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4963 if is_volume_in_use($storecfg, $conf, $key, $volid);
4964 PVE::Storage::vdisk_free($storecfg, $volid);
4967 # If vm is not owner of this disk remove from config
4975 sub vmconfig_delete_or_detach_drive {
4976 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4978 my $drive = parse_drive($opt, $conf->{$opt});
4980 my $rpcenv = PVE::RPCEnvironment::get();
4981 my $authuser = $rpcenv->get_user();
4984 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4985 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4987 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4991 sub vmconfig_apply_pending {
4992 my ($vmid, $conf, $storecfg) = @_;
4996 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4997 while (my ($opt, $force) = each %$pending_delete_hash) {
4998 die "internal error" if $opt =~ m/^unused/;
4999 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5000 if (!defined($conf->{$opt})) {
5001 vmconfig_undelete_pending_option($conf, $opt);
5002 PVE::QemuConfig->write_config($vmid, $conf);
5003 } elsif (is_valid_drivename($opt)) {
5004 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
5005 vmconfig_undelete_pending_option($conf, $opt);
5006 delete $conf->{$opt};
5007 PVE::QemuConfig->write_config($vmid, $conf);
5009 vmconfig_undelete_pending_option($conf, $opt);
5010 delete $conf->{$opt};
5011 PVE::QemuConfig->write_config($vmid, $conf);
5015 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5017 foreach my $opt (keys %{$conf->{pending}}) { # add/change
5018 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5020 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
5021 # skip if nothing changed
5022 } elsif (is_valid_drivename($opt)) {
5023 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
5024 if defined($conf->{$opt});
5025 $conf->{$opt} = $conf->{pending}->{$opt};
5027 $conf->{$opt} = $conf->{pending}->{$opt};
5030 delete $conf->{pending}->{$opt};
5031 PVE::QemuConfig->write_config($vmid, $conf);
5035 my $safe_num_ne = sub {
5038 return 0 if !defined($a) && !defined($b);
5039 return 1 if !defined($a);
5040 return 1 if !defined($b);
5045 my $safe_string_ne = sub {
5048 return 0 if !defined($a) && !defined($b);
5049 return 1 if !defined($a);
5050 return 1 if !defined($b);
5055 sub vmconfig_update_net {
5056 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5058 my $newnet = parse_net($value);
5060 if ($conf->{$opt}) {
5061 my $oldnet = parse_net($conf->{$opt});
5063 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5064 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5065 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
5066 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5068 # for non online change, we try to hot-unplug
5069 die "skip\n" if !$hotplug;
5070 vm_deviceunplug($vmid, $conf, $opt);
5073 die "internal error" if $opt !~ m/net(\d+)/;
5074 my $iface = "tap${vmid}i$1";
5076 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5077 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
5078 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
5079 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
5080 PVE::Network::tap_unplug($iface);
5081 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5082 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
5083 # Rate can be applied on its own but any change above needs to
5084 # include the rate in tap_plug since OVS resets everything.
5085 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
5088 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5089 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5097 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5103 sub vmconfig_update_disk {
5104 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
5106 # fixme: do we need force?
5108 my $drive = parse_drive($opt, $value);
5110 if ($conf->{$opt}) {
5112 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5114 my $media = $drive->{media} || 'disk
';
5115 my $oldmedia = $old_drive->{media} || 'disk
';
5116 die "unable to change media type\n" if $media ne $oldmedia;
5118 if (!drive_is_cdrom($old_drive)) {
5120 if ($drive->{file} ne $old_drive->{file}) {
5122 die "skip\n" if !$hotplug;
5124 # unplug and register as unused
5125 vm_deviceunplug($vmid, $conf, $opt);
5126 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5129 # update existing disk
5131 # skip non hotpluggable value
5132 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5133 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5134 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5135 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5140 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5141 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5142 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5143 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5144 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5145 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5146 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5147 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5148 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5149 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5150 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5151 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5152 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5153 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5154 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5155 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5156 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5157 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5159 qemu_block_set_io_throttle($vmid,"drive-$opt",
5160 ($drive->{mbps} || 0)*1024*1024,
5161 ($drive->{mbps_rd} || 0)*1024*1024,
5162 ($drive->{mbps_wr} || 0)*1024*1024,
5163 $drive->{iops} || 0,
5164 $drive->{iops_rd} || 0,
5165 $drive->{iops_wr} || 0,
5166 ($drive->{mbps_max} || 0)*1024*1024,
5167 ($drive->{mbps_rd_max} || 0)*1024*1024,
5168 ($drive->{mbps_wr_max} || 0)*1024*1024,
5169 $drive->{iops_max} || 0,
5170 $drive->{iops_rd_max} || 0,
5171 $drive->{iops_wr_max} || 0,
5172 $drive->{bps_max_length} || 1,
5173 $drive->{bps_rd_max_length} || 1,
5174 $drive->{bps_wr_max_length} || 1,
5175 $drive->{iops_max_length} || 1,
5176 $drive->{iops_rd_max_length} || 1,
5177 $drive->{iops_wr_max_length} || 1);
5186 if ($drive->{file} eq 'none
') {
5187 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5188 if (drive_is_cloudinit($old_drive)) {
5189 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5192 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5193 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5194 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5202 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5204 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5205 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5209 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5210 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5212 PVE::QemuConfig->lock_config($vmid, sub {
5213 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5215 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5217 my $is_suspended = PVE::QemuConfig->has_lock($conf, 'suspended
');
5219 PVE::QemuConfig->check_lock($conf)
5220 if !($skiplock || $is_suspended);
5222 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5224 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5225 vmconfig_apply_pending($vmid, $conf, $storecfg);
5226 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5229 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5231 my $defaults = load_defaults();
5233 # set environment variable useful inside network script
5234 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5236 my $local_volumes = {};
5238 if ($targetstorage) {
5239 foreach_drive($conf, sub {
5240 my ($ds, $drive) = @_;
5242 return if drive_is_cdrom($drive);
5244 my $volid = $drive->{file};
5248 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5250 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5251 return if $scfg->{shared};
5252 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5257 foreach my $opt (sort keys %$local_volumes) {
5259 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5260 my $drive = parse_drive($opt, $conf->{$opt});
5262 #if remote storage is specified, use default format
5263 if ($targetstorage && $targetstorage ne "1") {
5264 $storeid = $targetstorage;
5265 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5266 $format = $defFormat;
5268 #else we use same format than original
5269 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5270 $format = qemu_img_format($scfg, $volid);
5273 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5274 my $newdrive = $drive;
5275 $newdrive->{format} = $format;
5276 $newdrive->{file} = $newvolid;
5277 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5278 $local_volumes->{$opt} = $drivestr;
5279 #pass drive to conf for command line
5280 $conf->{$opt} = $drivestr;
5284 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
5286 if ($is_suspended) {
5287 # enforce machine type on suspended vm to ensure HW compatibility
5288 $forcemachine = $conf->{runningmachine};
5289 print "Resuming suspended VM\n";
5292 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5294 my $migrate_port = 0;
5297 if ($statefile eq 'tcp
') {
5298 my $localip = "localhost";
5299 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5300 my $nodename = PVE::INotify::nodename();
5302 if (!defined($migration_type)) {
5303 if (defined($datacenterconf->{migration}->{type})) {
5304 $migration_type = $datacenterconf->{migration}->{type};
5306 $migration_type = 'secure
';
5310 if ($migration_type eq 'insecure
') {
5311 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5312 if ($migrate_network_addr) {
5313 $localip = $migrate_network_addr;
5315 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5318 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5321 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5322 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5323 $migrate_uri = "tcp:${localip}:${migrate_port}";
5324 push @$cmd, '-incoming
', $migrate_uri;
5327 } elsif ($statefile eq 'unix
') {
5328 # should be default for secure migrations as a ssh TCP forward
5329 # tunnel is not deterministic reliable ready and fails regurarly
5330 # to set up in time, so use UNIX socket forwards
5331 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5332 unlink $socket_addr;
5334 $migrate_uri = "unix:$socket_addr";
5336 push @$cmd, '-incoming
', $migrate_uri;
5340 push @$cmd, '-loadstate
', $statefile;
5347 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5348 my $d = parse_hostpci($conf->{"hostpci$i"});
5350 my $pcidevices = $d->{pciid};
5351 foreach my $pcidevice (@$pcidevices) {
5352 my $pciid = $pcidevice->{id};
5354 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5355 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5356 die "no pci device info for device '$pciid'\n" if !$info;
5359 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5360 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5362 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5363 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5364 die "can
't reset pci device '$pciid'\n"
5365 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5370 PVE::Storage::activate_volumes($storecfg, $vollist);
5373 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5374 outfunc => sub {}, errfunc => sub {});
5376 # Issues with the above 'stop
' not being fully completed are extremely rare, a very low
5377 # timeout should be more than enough here...
5378 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5380 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5381 : $defaults->{cpuunits};
5383 my $start_timeout = ($conf->{hugepages} || $is_suspended) ? 300 : 30;
5384 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5387 Slice => 'qemu
.slice
',
5389 CPUShares => $cpuunits
5392 if (my $cpulimit = $conf->{cpulimit}) {
5393 $properties{CPUQuota} = int($cpulimit * 100);
5395 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5397 my $run_qemu = sub {
5398 PVE::Tools::run_fork sub {
5399 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5400 run_command($cmd, %run_params);
5404 if ($conf->{hugepages}) {
5407 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5408 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5410 PVE::QemuServer::Memory::hugepages_mount();
5411 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5413 eval { $run_qemu->() };
5415 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5419 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5421 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5424 eval { $run_qemu->() };
5428 # deactivate volumes if start fails
5429 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5430 die "start failed: $err";
5433 print "migration listens on $migrate_uri\n" if $migrate_uri;
5435 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5436 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5440 #start nbd server for storage migration
5441 if ($targetstorage) {
5442 my $nodename = PVE::INotify::nodename();
5443 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5444 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5445 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5446 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5448 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5450 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5452 foreach my $opt (sort keys %$local_volumes) {
5453 my $volid = $local_volumes->{$opt};
5454 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5455 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5456 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5460 if ($migratedfrom) {
5462 set_migration_caps($vmid);
5467 print "spice listens on port $spice_port\n";
5468 if ($spice_ticket) {
5469 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5470 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5475 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5476 if !$statefile && $conf->{balloon};
5478 foreach my $opt (keys %$conf) {
5479 next if $opt !~ m/^net\d+$/;
5480 my $nicconf = parse_net($conf->{$opt});
5481 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5485 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5486 path => "machine/peripheral/balloon0",
5487 property => "guest-stats-polling-interval",
5488 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5490 if ($is_suspended && (my $vmstate = $conf->{vmstate})) {
5491 print "Resumed VM, removing state\n";
5492 delete $conf->@{qw(lock vmstate runningmachine)};
5493 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5494 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5495 PVE
::QemuConfig-
>write_config($vmid, $conf);
5498 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5503 my ($vmid, $execute, %params) = @_;
5505 my $cmd = { execute
=> $execute, arguments
=> \
%params };
5506 vm_qmp_command
($vmid, $cmd);
5509 sub vm_mon_cmd_nocheck
{
5510 my ($vmid, $execute, %params) = @_;
5512 my $cmd = { execute
=> $execute, arguments
=> \
%params };
5513 vm_qmp_command
($vmid, $cmd, 1);
5516 sub vm_qmp_command
{
5517 my ($vmid, $cmd, $nocheck) = @_;
5522 if ($cmd->{arguments
}) {
5523 $timeout = delete $cmd->{arguments
}->{timeout
};
5527 die "VM $vmid not running\n" if !check_running
($vmid, $nocheck);
5528 my $sname = qmp_socket
($vmid);
5529 if (-e
$sname) { # test if VM is reasonambe new and supports qmp/qga
5530 my $qmpclient = PVE
::QMPClient-
>new();
5532 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5534 die "unable to open monitor socket\n";
5538 syslog
("err", "VM $vmid qmp command failed - $err");
5545 sub vm_human_monitor_command
{
5546 my ($vmid, $cmdline) = @_;
5551 execute
=> 'human-monitor-command',
5552 arguments
=> { 'command-line' => $cmdline},
5555 return vm_qmp_command
($vmid, $cmd);
5558 sub vm_commandline
{
5559 my ($storecfg, $vmid, $snapname) = @_;
5561 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5564 my $snapshot = $conf->{snapshots
}->{$snapname};
5565 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5567 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5572 my $defaults = load_defaults
();
5574 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults);
5576 return PVE
::Tools
::cmd2string
($cmd);
5580 my ($vmid, $skiplock) = @_;
5582 PVE
::QemuConfig-
>lock_config($vmid, sub {
5584 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5586 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5588 vm_mon_cmd
($vmid, "system_reset");
5592 sub get_vm_volumes
{
5596 foreach_volid
($conf, sub {
5597 my ($volid, $attr) = @_;
5599 return if $volid =~ m
|^/|;
5601 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5604 push @$vollist, $volid;
5610 sub vm_stop_cleanup
{
5611 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5616 my $vollist = get_vm_volumes
($conf);
5617 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5620 foreach my $ext (qw(mon qmp pid vnc qga)) {
5621 unlink "/var/run/qemu-server/${vmid}.$ext";
5624 if ($conf->{ivshmem
}) {
5625 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5626 # just delete it for now, VMs which have this already open do not
5627 # are affected, but new VMs will get a separated one. If this
5628 # becomes an issue we either add some sort of ref-counting or just
5629 # add a "don't delete on stop" flag to the ivshmem format.
5630 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5633 foreach my $key (keys %$conf) {
5634 next if $key !~ m/^hostpci(\d+)$/;
5635 my $hostpciindex = $1;
5636 my $d = parse_hostpci
($conf->{$key});
5637 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5639 foreach my $pci (@{$d->{pciid
}}) {
5640 my $pciid = $pci->{id
};
5641 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5645 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5647 warn $@ if $@; # avoid errors - just warn
5650 # Note: use $nockeck to skip tests if VM configuration file exists.
5651 # We need that when migration VMs to other nodes (files already moved)
5652 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5654 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5656 $force = 1 if !defined($force) && !$shutdown;
5659 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5660 kill 15, $pid if $pid;
5661 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5662 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5666 PVE
::QemuConfig-
>lock_config($vmid, sub {
5668 my $pid = check_running
($vmid, $nocheck);
5673 $conf = PVE
::QemuConfig-
>load_config($vmid);
5674 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5675 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5676 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5677 $timeout = $opts->{down
} if $opts->{down
};
5679 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5684 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5685 vm_qmp_command
($vmid, {
5686 execute
=> "guest-shutdown",
5687 arguments
=> { timeout
=> $timeout }
5690 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5693 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5699 $timeout = 60 if !defined($timeout);
5702 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5707 if ($count >= $timeout) {
5709 warn "VM still running - terminating now with SIGTERM\n";
5712 die "VM quit/powerdown failed - got timeout\n";
5715 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5720 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5723 die "VM quit/powerdown failed\n";
5731 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5736 if ($count >= $timeout) {
5737 warn "VM still running - terminating now with SIGKILL\n";
5742 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5747 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5754 PVE
::QemuConfig-
>lock_config($vmid, sub {
5756 $conf = PVE
::QemuConfig-
>load_config($vmid);
5758 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5759 PVE
::QemuConfig-
>check_lock($conf)
5760 if !($skiplock || $is_backing_up);
5762 die "cannot suspend to disk during backup\n"
5763 if $is_backing_up && $includestate;
5765 if ($includestate) {
5766 $conf->{lock} = 'suspending';
5767 my $date = strftime
("%Y-%m-%d", localtime(time()));
5768 $storecfg = PVE
::Storage
::config
();
5769 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5770 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5771 PVE
::QemuConfig-
>write_config($vmid, $conf);
5773 vm_mon_cmd
($vmid, "stop");
5777 if ($includestate) {
5779 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5782 vm_mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5784 my $state = vm_mon_cmd_nocheck
($vmid, "query-savevm");
5785 if (!$state->{status
}) {
5786 die "savevm not active\n";
5787 } elsif ($state->{status
} eq 'active') {
5790 } elsif ($state->{status
} eq 'completed') {
5791 print "State saved, quitting\n";
5793 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5794 die "query-savevm failed with error '$state->{error}'\n"
5796 die "query-savevm returned status '$state->{status}'\n";
5802 PVE
::QemuConfig-
>lock_config($vmid, sub {
5803 $conf = PVE
::QemuConfig-
>load_config($vmid);
5805 # cleanup, but leave suspending lock, to indicate something went wrong
5807 vm_mon_cmd
($vmid, "savevm-end");
5808 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5809 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5810 delete $conf->@{qw(vmstate runningmachine)};
5811 PVE
::QemuConfig-
>write_config($vmid, $conf);
5817 die "lock changed unexpectedly\n"
5818 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5820 vm_qmp_command
($vmid, { execute
=> "quit" });
5821 $conf->{lock} = 'suspended';
5822 PVE
::QemuConfig-
>write_config($vmid, $conf);
5828 my ($vmid, $skiplock, $nocheck) = @_;
5830 PVE
::QemuConfig-
>lock_config($vmid, sub {
5831 my $vm_mon_cmd = $nocheck ? \
&vm_mon_cmd_nocheck
: \
&vm_mon_cmd
;
5832 my $res = $vm_mon_cmd->($vmid, 'query-status');
5833 my $resume_cmd = 'cont';
5835 if ($res->{status
} && $res->{status
} eq 'suspended') {
5836 $resume_cmd = 'system_wakeup';
5841 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5843 PVE
::QemuConfig-
>check_lock($conf)
5844 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5847 $vm_mon_cmd->($vmid, $resume_cmd);
5852 my ($vmid, $skiplock, $key) = @_;
5854 PVE
::QemuConfig-
>lock_config($vmid, sub {
5856 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5858 # there is no qmp command, so we use the human monitor command
5859 vm_human_monitor_command
($vmid, "sendkey $key");
5864 my ($storecfg, $vmid, $skiplock) = @_;
5866 PVE
::QemuConfig-
>lock_config($vmid, sub {
5868 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5870 if (!check_running
($vmid)) {
5871 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5873 die "VM $vmid is running - destroy failed\n";
5878 # vzdump restore implementaion
5880 sub tar_archive_read_firstfile
{
5881 my $archive = shift;
5883 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5885 # try to detect archive type first
5886 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5887 die "unable to open file '$archive'\n";
5888 my $firstfile = <$fh>;
5892 die "ERROR: archive contaions no data\n" if !$firstfile;
5898 sub tar_restore_cleanup
{
5899 my ($storecfg, $statfile) = @_;
5901 print STDERR
"starting cleanup\n";
5903 if (my $fd = IO
::File-
>new($statfile, "r")) {
5904 while (defined(my $line = <$fd>)) {
5905 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5908 if ($volid =~ m
|^/|) {
5909 unlink $volid || die 'unlink failed\n';
5911 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5913 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5915 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5917 print STDERR
"unable to parse line in statfile - $line";
5924 sub restore_archive
{
5925 my ($archive, $vmid, $user, $opts) = @_;
5927 my $format = $opts->{format
};
5930 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5931 $format = 'tar' if !$format;
5933 } elsif ($archive =~ m/\.tar$/) {
5934 $format = 'tar' if !$format;
5935 } elsif ($archive =~ m/.tar.lzo$/) {
5936 $format = 'tar' if !$format;
5938 } elsif ($archive =~ m/\.vma$/) {
5939 $format = 'vma' if !$format;
5940 } elsif ($archive =~ m/\.vma\.gz$/) {
5941 $format = 'vma' if !$format;
5943 } elsif ($archive =~ m/\.vma\.lzo$/) {
5944 $format = 'vma' if !$format;
5947 $format = 'vma' if !$format; # default
5950 # try to detect archive format
5951 if ($format eq 'tar') {
5952 return restore_tar_archive
($archive, $vmid, $user, $opts);
5954 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5958 sub restore_update_config_line
{
5959 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5961 return if $line =~ m/^\#qmdump\#/;
5962 return if $line =~ m/^\#vzdump\#/;
5963 return if $line =~ m/^lock:/;
5964 return if $line =~ m/^unused\d+:/;
5965 return if $line =~ m/^parent:/;
5967 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5968 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5969 # try to convert old 1.X settings
5970 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5971 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5972 my ($model, $macaddr) = split(/\=/, $devconfig);
5973 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5976 bridge
=> "vmbr$ind",
5977 macaddr
=> $macaddr,
5979 my $netstr = print_net
($net);
5981 print $outfd "net$cookie->{netcount}: $netstr\n";
5982 $cookie->{netcount
}++;
5984 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5985 my ($id, $netstr) = ($1, $2);
5986 my $net = parse_net
($netstr);
5987 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5988 $netstr = print_net
($net);
5989 print $outfd "$id: $netstr\n";
5990 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5993 my $di = parse_drive
($virtdev, $value);
5994 if (defined($di->{backup
}) && !$di->{backup
}) {
5995 print $outfd "#$line";
5996 } elsif ($map->{$virtdev}) {
5997 delete $di->{format
}; # format can change on restore
5998 $di->{file
} = $map->{$virtdev};
5999 $value = print_drive
($vmid, $di);
6000 print $outfd "$virtdev: $value\n";
6004 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6006 if ($vmgenid ne '0') {
6007 # always generate a new vmgenid if there was a valid one setup
6008 $vmgenid = generate_uuid
();
6010 print $outfd "vmgenid: $vmgenid\n";
6011 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6012 my ($uuid, $uuid_str);
6013 UUID
::generate
($uuid);
6014 UUID
::unparse
($uuid, $uuid_str);
6015 my $smbios1 = parse_smbios1
($2);
6016 $smbios1->{uuid
} = $uuid_str;
6017 print $outfd $1.print_smbios1
($smbios1)."\n";
6024 my ($cfg, $vmid) = @_;
6026 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
6028 my $volid_hash = {};
6029 foreach my $storeid (keys %$info) {
6030 foreach my $item (@{$info->{$storeid}}) {
6031 next if !($item->{volid
} && $item->{size
});
6032 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6033 $volid_hash->{$item->{volid
}} = $item;
6040 sub is_volume_in_use
{
6041 my ($storecfg, $conf, $skip_drive, $volid) = @_;
6043 my $path = PVE
::Storage
::path
($storecfg, $volid);
6045 my $scan_config = sub {
6046 my ($cref, $snapname) = @_;
6048 foreach my $key (keys %$cref) {
6049 my $value = $cref->{$key};
6050 if (is_valid_drivename
($key)) {
6051 next if $skip_drive && $key eq $skip_drive;
6052 my $drive = parse_drive
($key, $value);
6053 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
6054 return 1 if $volid eq $drive->{file
};
6055 if ($drive->{file
} =~ m!^/!) {
6056 return 1 if $drive->{file
} eq $path;
6058 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
6060 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
6062 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
6070 return 1 if &$scan_config($conf);
6074 foreach my $snapname (keys %{$conf->{snapshots
}}) {
6075 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
6081 sub update_disksize
{
6082 my ($vmid, $conf, $volid_hash) = @_;
6085 my $prefix = "VM $vmid:";
6087 # used and unused disks
6088 my $referenced = {};
6090 # Note: it is allowed to define multiple storages with same path (alias), so
6091 # we need to check both 'volid' and real 'path' (two different volid can point
6092 # to the same path).
6094 my $referencedpath = {};
6097 foreach my $opt (keys %$conf) {
6098 if (is_valid_drivename
($opt)) {
6099 my $drive = parse_drive
($opt, $conf->{$opt});
6100 my $volid = $drive->{file
};
6103 $referenced->{$volid} = 1;
6104 if ($volid_hash->{$volid} &&
6105 (my $path = $volid_hash->{$volid}->{path
})) {
6106 $referencedpath->{$path} = 1;
6109 next if drive_is_cdrom
($drive);
6110 next if !$volid_hash->{$volid};
6112 $drive->{size
} = $volid_hash->{$volid}->{size
};
6113 my $new = print_drive
($vmid, $drive);
6114 if ($new ne $conf->{$opt}) {
6116 $conf->{$opt} = $new;
6117 print "$prefix update disk '$opt' information.\n";
6122 # remove 'unusedX' entry if volume is used
6123 foreach my $opt (keys %$conf) {
6124 next if $opt !~ m/^unused\d+$/;
6125 my $volid = $conf->{$opt};
6126 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6127 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6128 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
6130 delete $conf->{$opt};
6133 $referenced->{$volid} = 1;
6134 $referencedpath->{$path} = 1 if $path;
6137 foreach my $volid (sort keys %$volid_hash) {
6138 next if $volid =~ m/vm-$vmid-state-/;
6139 next if $referenced->{$volid};
6140 my $path = $volid_hash->{$volid}->{path
};
6141 next if !$path; # just to be sure
6142 next if $referencedpath->{$path};
6144 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6145 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
6146 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6153 my ($vmid, $nolock, $dryrun) = @_;
6155 my $cfg = PVE
::Storage
::config
();
6157 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
6158 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
6159 foreach my $stor (keys %{$cfg->{ids
}}) {
6160 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
6163 print "rescan volumes...\n";
6164 my $volid_hash = scan_volids
($cfg, $vmid);
6166 my $updatefn = sub {
6169 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6171 PVE
::QemuConfig-
>check_lock($conf);
6174 foreach my $volid (keys %$volid_hash) {
6175 my $info = $volid_hash->{$volid};
6176 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6179 my $changes = update_disksize
($vmid, $conf, $vm_volids);
6181 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6184 if (defined($vmid)) {
6188 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6191 my $vmlist = config_list
();
6192 foreach my $vmid (keys %$vmlist) {
6196 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6202 sub restore_vma_archive
{
6203 my ($archive, $vmid, $user, $opts, $comp) = @_;
6205 my $readfrom = $archive;
6207 my $cfg = PVE
::Storage
::config
();
6209 my $bwlimit = $opts->{bwlimit
};
6211 my $dbg_cmdstring = '';
6212 my $add_pipe = sub {
6214 push @$commands, $cmd;
6215 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6216 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6221 if ($archive eq '-') {
6224 # If we use a backup from a PVE defined storage we also consider that
6225 # storage's rate limit:
6226 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6227 if (defined($volid)) {
6228 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6229 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6231 print STDERR
"applying read rate limit: $readlimit\n";
6232 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6233 $add_pipe->($cstream);
6240 if ($comp eq 'gzip') {
6241 $cmd = ['zcat', $readfrom];
6242 } elsif ($comp eq 'lzop') {
6243 $cmd = ['lzop', '-d', '-c', $readfrom];
6245 die "unknown compression method '$comp'\n";
6250 my $tmpdir = "/var/tmp/vzdumptmp$$";
6253 # disable interrupts (always do cleanups)
6257 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6259 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6260 POSIX
::mkfifo
($mapfifo, 0600);
6263 my $openfifo = sub {
6264 open($fifofh, '>', $mapfifo) || die $!;
6267 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6274 my $rpcenv = PVE
::RPCEnvironment
::get
();
6276 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6277 my $tmpfn = "$conffile.$$.tmp";
6279 # Note: $oldconf is undef if VM does not exists
6280 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6281 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6285 my $print_devmap = sub {
6286 my $virtdev_hash = {};
6288 my $cfgfn = "$tmpdir/qemu-server.conf";
6290 # we can read the config - that is already extracted
6291 my $fh = IO
::File-
>new($cfgfn, "r") ||
6292 "unable to read qemu-server.conf - $!\n";
6294 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6296 my $pve_firewall_dir = '/etc/pve/firewall';
6297 mkdir $pve_firewall_dir; # make sure the dir exists
6298 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6301 while (defined(my $line = <$fh>)) {
6302 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6303 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6304 die "archive does not contain data for drive '$virtdev'\n"
6305 if !$devinfo->{$devname};
6306 if (defined($opts->{storage
})) {
6307 $storeid = $opts->{storage
} || 'local';
6308 } elsif (!$storeid) {
6311 $format = 'raw' if !$format;
6312 $devinfo->{$devname}->{devname
} = $devname;
6313 $devinfo->{$devname}->{virtdev
} = $virtdev;
6314 $devinfo->{$devname}->{format
} = $format;
6315 $devinfo->{$devname}->{storeid
} = $storeid;
6317 # check permission on storage
6318 my $pool = $opts->{pool
}; # todo: do we need that?
6319 if ($user ne 'root@pam') {
6320 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6323 $storage_limits{$storeid} = $bwlimit;
6325 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6326 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6328 my $drive = parse_drive
($virtdev, $2);
6329 if (drive_is_cloudinit
($drive)) {
6330 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6331 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6332 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
6336 storeid
=> $opts->{storage
} // $storeid,
6337 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6338 file
=> $drive->{file
}, # to make drive_is_cloudinit check possible
6339 name
=> "vm-$vmid-cloudinit",
6342 $virtdev_hash->{$virtdev} = $d;
6347 foreach my $key (keys %storage_limits) {
6348 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6350 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6351 $storage_limits{$key} = $limit * 1024;
6354 foreach my $devname (keys %$devinfo) {
6355 die "found no device mapping information for device '$devname'\n"
6356 if !$devinfo->{$devname}->{virtdev
};
6359 # create empty/temp config
6361 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6362 foreach_drive
($oldconf, sub {
6363 my ($ds, $drive) = @_;
6365 return if !$drive->{is_cloudinit
} && drive_is_cdrom
($drive);
6367 my $volid = $drive->{file
};
6368 return if !$volid || $volid =~ m
|^/|;
6370 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6371 return if !$path || !$owner || ($owner != $vmid);
6373 # Note: only delete disk we want to restore
6374 # other volumes will become unused
6375 if ($virtdev_hash->{$ds}) {
6376 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6383 # delete vmstate files, after the restore we have no snapshots anymore
6384 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6385 my $snap = $oldconf->{snapshots
}->{$snapname};
6386 if ($snap->{vmstate
}) {
6387 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6396 foreach my $virtdev (sort keys %$virtdev_hash) {
6397 my $d = $virtdev_hash->{$virtdev};
6398 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6399 my $storeid = $d->{storeid
};
6400 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6403 if (my $limit = $storage_limits{$storeid}) {
6404 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6407 # test if requested format is supported
6408 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6409 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6410 $d->{format
} = $defFormat if !$supported;
6413 if ($d->{is_cloudinit
}) {
6415 $name .= ".$d->{format}" if $d->{format
} ne 'raw';
6418 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6419 print STDERR
"new volume ID is '$volid'\n";
6420 $d->{volid
} = $volid;
6422 PVE
::Storage
::activate_volumes
($cfg, [$volid]);
6424 my $write_zeros = 1;
6425 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6429 if (!$d->{is_cloudinit
}) {
6430 my $path = PVE
::Storage
::path
($cfg, $volid);
6432 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6434 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6436 $map->{$virtdev} = $volid;
6439 $fh->seek(0, 0) || die "seek failed - $!\n";
6441 my $outfd = new IO
::File
($tmpfn, "w") ||
6442 die "unable to write config for VM $vmid\n";
6444 my $cookie = { netcount
=> 0 };
6445 while (defined(my $line = <$fh>)) {
6446 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6459 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6460 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6462 $oldtimeout = alarm($timeout);
6469 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6470 my ($dev_id, $size, $devname) = ($1, $2, $3);
6471 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6472 } elsif ($line =~ m/^CTIME: /) {
6473 # we correctly received the vma config, so we can disable
6474 # the timeout now for disk allocation (set to 10 minutes, so
6475 # that we always timeout if something goes wrong)
6478 print $fifofh "done\n";
6479 my $tmp = $oldtimeout || 0;
6480 $oldtimeout = undef;
6486 print "restore vma archive: $dbg_cmdstring\n";
6487 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6491 alarm($oldtimeout) if $oldtimeout;
6494 foreach my $devname (keys %$devinfo) {
6495 my $volid = $devinfo->{$devname}->{volid
};
6496 push @$vollist, $volid if $volid;
6499 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6507 foreach my $devname (keys %$devinfo) {
6508 my $volid = $devinfo->{$devname}->{volid
};
6511 if ($volid =~ m
|^/|) {
6512 unlink $volid || die 'unlink failed\n';
6514 PVE
::Storage
::vdisk_free
($cfg, $volid);
6516 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6518 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6525 rename($tmpfn, $conffile) ||
6526 die "unable to commit configuration file '$conffile'\n";
6528 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6530 eval { rescan
($vmid, 1); };
6534 sub restore_tar_archive
{
6535 my ($archive, $vmid, $user, $opts) = @_;
6537 if ($archive ne '-') {
6538 my $firstfile = tar_archive_read_firstfile
($archive);
6539 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6540 if $firstfile ne 'qemu-server.conf';
6543 my $storecfg = PVE
::Storage
::config
();
6545 # destroy existing data - keep empty config
6546 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6547 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6549 my $tocmd = "/usr/lib/qemu-server/qmextract";
6551 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6552 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6553 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6554 $tocmd .= ' --info' if $opts->{info
};
6556 # tar option "xf" does not autodetect compression when read from STDIN,
6557 # so we pipe to zcat
6558 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6559 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6561 my $tmpdir = "/var/tmp/vzdumptmp$$";
6564 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6565 local $ENV{VZDUMP_VMID
} = $vmid;
6566 local $ENV{VZDUMP_USER
} = $user;
6568 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6569 my $tmpfn = "$conffile.$$.tmp";
6571 # disable interrupts (always do cleanups)
6575 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6583 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6585 if ($archive eq '-') {
6586 print "extracting archive from STDIN\n";
6587 run_command
($cmd, input
=> "<&STDIN");
6589 print "extracting archive '$archive'\n";
6593 return if $opts->{info
};
6597 my $statfile = "$tmpdir/qmrestore.stat";
6598 if (my $fd = IO
::File-
>new($statfile, "r")) {
6599 while (defined (my $line = <$fd>)) {
6600 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6601 $map->{$1} = $2 if $1;
6603 print STDERR
"unable to parse line in statfile - $line\n";
6609 my $confsrc = "$tmpdir/qemu-server.conf";
6611 my $srcfd = new IO
::File
($confsrc, "r") ||
6612 die "unable to open file '$confsrc'\n";
6614 my $outfd = new IO
::File
($tmpfn, "w") ||
6615 die "unable to write config for VM $vmid\n";
6617 my $cookie = { netcount
=> 0 };
6618 while (defined (my $line = <$srcfd>)) {
6619 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6631 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6638 rename $tmpfn, $conffile ||
6639 die "unable to commit configuration file '$conffile'\n";
6641 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6643 eval { rescan
($vmid, 1); };
6647 sub foreach_storage_used_by_vm
{
6648 my ($conf, $func) = @_;
6652 foreach_drive
($conf, sub {
6653 my ($ds, $drive) = @_;
6654 return if drive_is_cdrom
($drive);
6656 my $volid = $drive->{file
};
6658 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6659 $sidhash->{$sid} = $sid if $sid;
6662 foreach my $sid (sort keys %$sidhash) {
6667 sub do_snapshots_with_qemu
{
6668 my ($storecfg, $volid) = @_;
6670 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6671 my $scfg = $storecfg->{ids
}->{$storage_name};
6673 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6677 if ($volid =~ m/\.(qcow2|qed)$/){
6684 sub qga_check_running
{
6685 my ($vmid, $nowarn) = @_;
6687 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6689 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6695 sub template_create
{
6696 my ($vmid, $conf, $disk) = @_;
6698 my $storecfg = PVE
::Storage
::config
();
6700 foreach_drive
($conf, sub {
6701 my ($ds, $drive) = @_;
6703 return if drive_is_cdrom
($drive);
6704 return if $disk && $ds ne $disk;
6706 my $volid = $drive->{file
};
6707 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6709 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6710 $drive->{file
} = $voliddst;
6711 $conf->{$ds} = print_drive
($vmid, $drive);
6712 PVE
::QemuConfig-
>write_config($vmid, $conf);
6716 sub convert_iscsi_path
{
6719 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6724 my $initiator_name = get_initiator_name
();
6726 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6727 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6730 die "cannot convert iscsi path '$path', unkown format\n";
6733 sub qemu_img_convert
{
6734 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6736 my $storecfg = PVE
::Storage
::config
();
6737 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6738 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6740 if ($src_storeid && $dst_storeid) {
6742 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6744 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6745 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6747 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6748 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6750 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6751 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6753 my $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6754 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6757 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6758 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6759 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6760 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6762 if ($src_is_iscsi) {
6763 push @$cmd, '--image-opts';
6764 $src_path = convert_iscsi_path
($src_path);
6766 push @$cmd, '-f', $src_format;
6769 if ($dst_is_iscsi) {
6770 push @$cmd, '--target-image-opts';
6771 $dst_path = convert_iscsi_path
($dst_path);
6773 push @$cmd, '-O', $dst_format;
6776 push @$cmd, $src_path;
6778 if (!$dst_is_iscsi && $is_zero_initialized) {
6779 push @$cmd, "zeroinit:$dst_path";
6781 push @$cmd, $dst_path;
6786 if($line =~ m/\((\S+)\/100\
%\)/){
6788 my $transferred = int($size * $percent / 100);
6789 my $remaining = $size - $transferred;
6791 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6796 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6798 die "copy failed: $err" if $err;
6802 sub qemu_img_format
{
6803 my ($scfg, $volname) = @_;
6805 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6812 sub qemu_drive_mirror
{
6813 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
6815 $jobs = {} if !$jobs;
6819 $jobs->{"drive-$drive"} = {};
6821 if ($dst_volid =~ /^nbd:/) {
6822 $qemu_target = $dst_volid;
6825 my $storecfg = PVE
::Storage
::config
();
6826 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6828 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6830 $format = qemu_img_format
($dst_scfg, $dst_volname);
6832 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6834 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6837 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6838 $opts->{format
} = $format if $format;
6840 if (defined($bwlimit)) {
6841 $opts->{speed
} = $bwlimit * 1024;
6842 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
6844 print "drive mirror is starting for drive-$drive\n";
6847 # if a job already runs for this device we get an error, catch it for cleanup
6848 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); };
6850 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6852 die "mirroring error: $err\n";
6855 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6858 sub qemu_drive_mirror_monitor
{
6859 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6862 my $err_complete = 0;
6865 die "storage migration timed out\n" if $err_complete > 300;
6867 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6869 my $running_mirror_jobs = {};
6870 foreach my $stat (@$stats) {
6871 next if $stat->{type
} ne 'mirror';
6872 $running_mirror_jobs->{$stat->{device
}} = $stat;
6875 my $readycounter = 0;
6877 foreach my $job (keys %$jobs) {
6879 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6880 print "$job : finished\n";
6881 delete $jobs->{$job};
6885 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6887 my $busy = $running_mirror_jobs->{$job}->{busy
};
6888 my $ready = $running_mirror_jobs->{$job}->{ready
};
6889 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6890 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6891 my $remaining = $total - $transferred;
6892 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6894 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6897 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6900 last if scalar(keys %$jobs) == 0;
6902 if ($readycounter == scalar(keys %$jobs)) {
6903 print "all mirroring jobs are ready \n";
6904 last if $skipcomplete; #do the complete later
6906 if ($vmiddst && $vmiddst != $vmid) {
6907 my $agent_running = $qga && qga_check_running
($vmid);
6908 if ($agent_running) {
6909 print "freeze filesystem\n";
6910 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6912 print "suspend vm\n";
6913 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6916 # if we clone a disk for a new target vm, we don't switch the disk
6917 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6919 if ($agent_running) {
6920 print "unfreeze filesystem\n";
6921 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6923 print "resume vm\n";
6924 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6930 foreach my $job (keys %$jobs) {
6931 # try to switch the disk if source and destination are on the same guest
6932 print "$job: Completing block job...\n";
6934 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6935 if ($@ =~ m/cannot be completed/) {
6936 print "$job: Block job cannot be completed, try again.\n";
6939 print "$job: Completed successfully.\n";
6940 $jobs->{$job}->{complete
} = 1;
6951 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6952 die "mirroring error: $err";
6957 sub qemu_blockjobs_cancel
{
6958 my ($vmid, $jobs) = @_;
6960 foreach my $job (keys %$jobs) {
6961 print "$job: Cancelling block job\n";
6962 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6963 $jobs->{$job}->{cancel
} = 1;
6967 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6969 my $running_jobs = {};
6970 foreach my $stat (@$stats) {
6971 $running_jobs->{$stat->{device
}} = $stat;
6974 foreach my $job (keys %$jobs) {
6976 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6977 print "$job: Done.\n";
6978 delete $jobs->{$job};
6982 last if scalar(keys %$jobs) == 0;
6989 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6990 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
6995 print "create linked clone of drive $drivename ($drive->{file})\n";
6996 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6997 push @$newvollist, $newvolid;
7000 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7001 $storeid = $storage if $storage;
7003 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7004 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
7006 print "create full clone of drive $drivename ($drive->{file})\n";
7008 if (drive_is_cloudinit
($drive)) {
7009 $name = "vm-$newvmid-cloudinit";
7011 # we only get here if it's supported by QEMU_FORMAT_RE, so just accept
7012 if ($dst_format ne 'raw') {
7013 $name .= ".$dst_format";
7016 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
7017 push @$newvollist, $newvolid;
7019 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7021 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7022 if (!$running || $snapname) {
7023 # TODO: handle bwlimits
7024 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7027 my $kvmver = get_running_qemu_version
($vmid);
7028 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
7029 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7030 if $drive->{iothread
};
7033 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga, $bwlimit);
7037 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
7040 $disk->{format
} = undef;
7041 $disk->{file
} = $newvolid;
7042 $disk->{size
} = $size;
7047 # this only works if VM is running
7048 sub get_current_qemu_machine
{
7051 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
7052 my $res = vm_qmp_command
($vmid, $cmd);
7054 my ($current, $default);
7055 foreach my $e (@$res) {
7056 $default = $e->{name
} if $e->{'is-default'};
7057 $current = $e->{name
} if $e->{'is-current'};
7060 # fallback to the default machine if current is not supported by qemu
7061 return $current || $default || 'pc';
7064 sub get_running_qemu_version
{
7066 my $cmd = { execute
=> 'query-version', arguments
=> {} };
7067 my $res = vm_qmp_command
($vmid, $cmd);
7068 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7071 sub qemu_machine_feature_enabled
{
7072 my ($machine, $kvmver, $version_major, $version_minor) = @_;
7077 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
7079 $current_major = $3;
7080 $current_minor = $4;
7082 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
7084 $current_major = $1;
7085 $current_minor = $2;
7088 return 1 if $current_major > $version_major ||
7089 ($current_major == $version_major &&
7090 $current_minor >= $version_minor);
7093 sub qemu_machine_pxe
{
7094 my ($vmid, $conf, $machine) = @_;
7096 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
7098 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
7105 sub qemu_use_old_bios_files
{
7106 my ($machine_type) = @_;
7108 return if !$machine_type;
7110 my $use_old_bios_files = undef;
7112 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7114 $use_old_bios_files = 1;
7116 my $kvmver = kvm_user_version
();
7117 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7118 # load new efi bios files on migration. So this hack is required to allow
7119 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7120 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7121 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
7124 return ($use_old_bios_files, $machine_type);
7127 sub create_efidisk
($$$$$) {
7128 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
7130 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
7131 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7133 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
7134 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7135 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7137 my $path = PVE
::Storage
::path
($storecfg, $volid);
7139 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
7141 die "Copying EFI vars image failed: $@" if $@;
7143 return ($volid, $vars_size);
7146 sub vm_iothreads_list
{
7149 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
7152 foreach my $iothread (@$res) {
7153 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7160 my ($conf, $drive) = @_;
7164 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7166 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7172 my $controller = int($drive->{index} / $maxdev);
7173 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
7175 return ($maxdev, $controller, $controller_prefix);
7178 sub add_hyperv_enlightenments
{
7179 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
7181 return if $winversion < 6;
7182 return if $bios && $bios eq 'ovmf' && $winversion < 8;
7184 if ($gpu_passthrough || defined($hv_vendor_id)) {
7185 $hv_vendor_id //= 'proxmox';
7186 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
7189 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
7190 push @$cpuFlags , 'hv_spinlocks=0x1fff';
7191 push @$cpuFlags , 'hv_vapic';
7192 push @$cpuFlags , 'hv_time';
7194 push @$cpuFlags , 'hv_spinlocks=0xffff';
7197 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
7198 push @$cpuFlags , 'hv_reset';
7199 push @$cpuFlags , 'hv_vpindex';
7200 push @$cpuFlags , 'hv_runtime';
7203 if ($winversion >= 7) {
7204 push @$cpuFlags , 'hv_relaxed';
7206 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
7207 push @$cpuFlags , 'hv_synic';
7208 push @$cpuFlags , 'hv_stimer';
7211 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 3, 1)) {
7212 push @$cpuFlags , 'hv_tlbflush';
7213 push @$cpuFlags , 'hv_ipi';
7214 # FIXME: AMD does not supports this currently, only add with special flag??
7215 #push @$cpuFlags , 'hv_evmcs';
7220 sub windows_version
{
7223 return 0 if !$ostype;
7227 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7229 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7231 } elsif ($ostype =~ m/^win(\d+)$/) {
7238 sub resolve_dst_disk_format
{
7239 my ($storecfg, $storeid, $src_volname, $format) = @_;
7240 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7243 # if no target format is specified, use the source disk format as hint
7245 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7246 $format = qemu_img_format
($scfg, $src_volname);
7252 # test if requested format is supported - else use default
7253 my $supported = grep { $_ eq $format } @$validFormats;
7254 $format = $defFormat if !$supported;
7258 sub resolve_first_disk
{
7260 my @disks = PVE
::QemuServer
::valid_drive_names
();
7262 foreach my $ds (reverse @disks) {
7263 next if !$conf->{$ds};
7264 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
7265 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
7272 my ($uuid, $uuid_str);
7273 UUID
::generate
($uuid);
7274 UUID
::unparse
($uuid, $uuid_str);
7278 sub generate_smbios1_uuid
{
7279 return "uuid=".generate_uuid
();
7285 vm_mon_cmd
($vmid, 'nbd-server-stop');
7288 # bash completion helper
7290 sub complete_backup_archives
{
7291 my ($cmdname, $pname, $cvalue) = @_;
7293 my $cfg = PVE
::Storage
::config
();
7297 if ($cvalue =~ m/^([^:]+):/) {
7301 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7304 foreach my $id (keys %$data) {
7305 foreach my $item (@{$data->{$id}}) {
7306 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7307 push @$res, $item->{volid
} if defined($item->{volid
});
7314 my $complete_vmid_full = sub {
7317 my $idlist = vmstatus
();
7321 foreach my $id (keys %$idlist) {
7322 my $d = $idlist->{$id};
7323 if (defined($running)) {
7324 next if $d->{template
};
7325 next if $running && $d->{status
} ne 'running';
7326 next if !$running && $d->{status
} eq 'running';
7335 return &$complete_vmid_full();
7338 sub complete_vmid_stopped
{
7339 return &$complete_vmid_full(0);
7342 sub complete_vmid_running
{
7343 return &$complete_vmid_full(1);
7346 sub complete_storage
{
7348 my $cfg = PVE
::Storage
::config
();
7349 my $ids = $cfg->{ids
};
7352 foreach my $sid (keys %$ids) {
7353 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7354 next if !$ids->{$sid}->{content
}->{images
};