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 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2947 } elsif (my $avail = $scfg->{nodes
}) {
2948 foreach my $node (keys %$nodehash) {
2949 if (!$avail->{$node}) {
2950 $nodehash->{$node}->{unavailable_storages
}->{$storeid} = 1;
2957 foreach my $node (values %$nodehash) {
2958 if (my $unavail = $node->{unavailable_storages
}) {
2959 $node->{unavailable_storages
} = [ sort keys %$unavail ];
2967 my ($pidfile, $pid) = @_;
2969 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2973 return undef if !$line;
2974 my @param = split(/\0/, $line);
2976 my $cmd = $param[0];
2977 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2979 for (my $i = 0; $i < scalar (@param); $i++) {
2982 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2983 my $p = $param[$i+1];
2984 return 1 if $p && ($p eq $pidfile);
2993 my ($vmid, $nocheck, $node) = @_;
2995 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2997 die "unable to find configuration file for VM $vmid - no such machine\n"
2998 if !$nocheck && ! -f
$filename;
3000 my $pidfile = pidfile_name
($vmid);
3002 if (my $fd = IO
::File-
>new("<$pidfile")) {
3007 my $mtime = $st->mtime;
3008 if ($mtime > time()) {
3009 warn "file '$filename' modified in future\n";
3012 if ($line =~ m/^(\d+)$/) {
3014 if (check_cmdline
($pidfile, $pid)) {
3015 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
3027 my $vzlist = config_list
();
3029 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
3031 while (defined(my $de = $fd->read)) {
3032 next if $de !~ m/^(\d+)\.pid$/;
3034 next if !defined($vzlist->{$vmid});
3035 if (my $pid = check_running
($vmid)) {
3036 $vzlist->{$vmid}->{pid
} = $pid;
3044 my ($storecfg, $conf) = @_;
3046 my $bootdisk = $conf->{bootdisk
};
3047 return undef if !$bootdisk;
3048 return undef if !is_valid_drivename
($bootdisk);
3050 return undef if !$conf->{$bootdisk};
3052 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
3053 return undef if !defined($drive);
3055 return undef if drive_is_cdrom
($drive);
3057 my $volid = $drive->{file
};
3058 return undef if !$volid;
3060 return $drive->{size
};
3063 our $vmstatus_return_properties = {
3064 vmid
=> get_standard_option
('pve-vmid'),
3066 description
=> "Qemu process status.",
3068 enum
=> ['stopped', 'running'],
3071 description
=> "Maximum memory in bytes.",
3074 renderer
=> 'bytes',
3077 description
=> "Root disk size in bytes.",
3080 renderer
=> 'bytes',
3083 description
=> "VM name.",
3088 description
=> "Qemu QMP agent status.",
3093 description
=> "PID of running qemu process.",
3098 description
=> "Uptime.",
3101 renderer
=> 'duration',
3104 description
=> "Maximum usable CPUs.",
3109 description
=> "The current config lock, if any.",
3115 my $last_proc_pid_stat;
3117 # get VM status information
3118 # This must be fast and should not block ($full == false)
3119 # We only query KVM using QMP if $full == true (this can be slow)
3121 my ($opt_vmid, $full) = @_;
3125 my $storecfg = PVE
::Storage
::config
();
3127 my $list = vzlist
();
3128 my $defaults = load_defaults
();
3130 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3132 my $cpucount = $cpuinfo->{cpus
} || 1;
3134 foreach my $vmid (keys %$list) {
3135 next if $opt_vmid && ($vmid ne $opt_vmid);
3137 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3138 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3140 my $d = { vmid
=> $vmid };
3141 $d->{pid
} = $list->{$vmid}->{pid
};
3143 # fixme: better status?
3144 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3146 my $size = disksize
($storecfg, $conf);
3147 if (defined($size)) {
3148 $d->{disk
} = 0; # no info available
3149 $d->{maxdisk
} = $size;
3155 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3156 * ($conf->{cores
} || $defaults->{cores
});
3157 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3158 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3160 $d->{name
} = $conf->{name
} || "VM $vmid";
3161 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3162 : $defaults->{memory
}*(1024*1024);
3164 if ($conf->{balloon
}) {
3165 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3166 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3167 : $defaults->{shares
};
3178 $d->{diskwrite
} = 0;
3180 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3182 $d->{serial
} = 1 if conf_has_serial
($conf);
3183 $d->{lock} = $conf->{lock} if $conf->{lock};
3188 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3189 foreach my $dev (keys %$netdev) {
3190 next if $dev !~ m/^tap([1-9]\d*)i/;
3192 my $d = $res->{$vmid};
3195 $d->{netout
} += $netdev->{$dev}->{receive
};
3196 $d->{netin
} += $netdev->{$dev}->{transmit
};
3199 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3200 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3205 my $ctime = gettimeofday
;
3207 foreach my $vmid (keys %$list) {
3209 my $d = $res->{$vmid};
3210 my $pid = $d->{pid
};
3213 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3214 next if !$pstat; # not running
3216 my $used = $pstat->{utime} + $pstat->{stime
};
3218 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3220 if ($pstat->{vsize
}) {
3221 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3224 my $old = $last_proc_pid_stat->{$pid};
3226 $last_proc_pid_stat->{$pid} = {
3234 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3236 if ($dtime > 1000) {
3237 my $dutime = $used - $old->{used
};
3239 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3240 $last_proc_pid_stat->{$pid} = {
3246 $d->{cpu
} = $old->{cpu
};
3250 return $res if !$full;
3252 my $qmpclient = PVE
::QMPClient-
>new();
3254 my $ballooncb = sub {
3255 my ($vmid, $resp) = @_;
3257 my $info = $resp->{'return'};
3258 return if !$info->{max_mem
};
3260 my $d = $res->{$vmid};
3262 # use memory assigned to VM
3263 $d->{maxmem
} = $info->{max_mem
};
3264 $d->{balloon
} = $info->{actual
};
3266 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3267 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3268 $d->{freemem
} = $info->{free_mem
};
3271 $d->{ballooninfo
} = $info;
3274 my $blockstatscb = sub {
3275 my ($vmid, $resp) = @_;
3276 my $data = $resp->{'return'} || [];
3277 my $totalrdbytes = 0;
3278 my $totalwrbytes = 0;
3280 for my $blockstat (@$data) {
3281 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3282 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3284 $blockstat->{device
} =~ s/drive-//;
3285 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3287 $res->{$vmid}->{diskread
} = $totalrdbytes;
3288 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3291 my $statuscb = sub {
3292 my ($vmid, $resp) = @_;
3294 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3295 # this fails if ballon driver is not loaded, so this must be
3296 # the last commnand (following command are aborted if this fails).
3297 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3299 my $status = 'unknown';
3300 if (!defined($status = $resp->{'return'}->{status
})) {
3301 warn "unable to get VM status\n";
3305 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3308 foreach my $vmid (keys %$list) {
3309 next if $opt_vmid && ($vmid ne $opt_vmid);
3310 next if !$res->{$vmid}->{pid
}; # not running
3311 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3314 $qmpclient->queue_execute(undef, 2);
3316 foreach my $vmid (keys %$list) {
3317 next if $opt_vmid && ($vmid ne $opt_vmid);
3318 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3325 my ($conf, $func, @param) = @_;
3327 foreach my $ds (valid_drive_names
()) {
3328 next if !defined($conf->{$ds});
3330 my $drive = parse_drive
($ds, $conf->{$ds});
3333 &$func($ds, $drive, @param);
3338 my ($conf, $func, @param) = @_;
3342 my $test_volid = sub {
3343 my ($volid, $is_cdrom, $replicate, $shared, $snapname, $size) = @_;
3347 $volhash->{$volid}->{cdrom
} //= 1;
3348 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3350 $volhash->{$volid}->{replicate
} //= 0;
3351 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3353 $volhash->{$volid}->{shared
} //= 0;
3354 $volhash->{$volid}->{shared
} = 1 if $shared;
3356 $volhash->{$volid}->{referenced_in_config
} //= 0;
3357 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3359 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3360 if defined($snapname);
3361 $volhash->{$volid}->{size
} = $size if $size;
3364 foreach_drive
($conf, sub {
3365 my ($ds, $drive) = @_;
3366 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef, $drive->{size
});
3369 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3370 my $snap = $conf->{snapshots
}->{$snapname};
3371 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3372 foreach_drive
($snap, sub {
3373 my ($ds, $drive) = @_;
3374 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3378 foreach my $volid (keys %$volhash) {
3379 &$func($volid, $volhash->{$volid}, @param);
3383 sub conf_has_serial
{
3386 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3387 if ($conf->{"serial$i"}) {
3395 sub vga_conf_has_spice
{
3398 my $vgaconf = parse_vga
($vga);
3399 my $vgatype = $vgaconf->{type
};
3400 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3405 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3406 sub get_host_arch
() {
3407 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3413 return get_host_arch
() eq $arch;
3416 my $default_machines = {
3421 sub get_basic_machine_info
{
3422 my ($conf, $forcemachine) = @_;
3424 my $arch = $conf->{arch
} // get_host_arch
();
3425 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3426 return ($arch, $machine);
3429 sub get_ovmf_files
($) {
3432 my $ovmf = $OVMF->{$arch}
3433 or die "no OVMF images known for architecture '$arch'\n";
3439 aarch64
=> '/usr/bin/qemu-system-aarch64',
3440 x86_64
=> '/usr/bin/qemu-system-x86_64',
3442 sub get_command_for_arch
($) {
3444 return '/usr/bin/kvm' if is_native
($arch);
3446 my $cmd = $Arch2Qemu->{$arch}
3447 or die "don't know how to emulate architecture '$arch'\n";
3451 sub get_cpu_options
{
3452 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3455 my $ostype = $conf->{ostype
};
3457 my $cpu = $kvm ?
"kvm64" : "qemu64";
3458 if ($arch eq 'aarch64') {
3459 $cpu = 'cortex-a57';
3462 if (my $cputype = $conf->{cpu
}) {
3463 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3464 or die "Cannot parse cpu description: $cputype\n";
3465 $cpu = $cpuconf->{cputype
};
3466 $kvm_off = 1 if $cpuconf->{hidden
};
3467 $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
3469 if (defined(my $flags = $cpuconf->{flags
})) {
3470 push @$cpuFlags, split(";", $flags);
3474 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3476 push @$cpuFlags , '-x2apic'
3477 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3479 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3481 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3483 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3485 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3486 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3489 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough, $hv_vendor_id) if $kvm;
3491 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3493 push @$cpuFlags, 'kvm=off' if $kvm_off;
3495 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3496 push @$cpuFlags, "vendor=${cpu_vendor}"
3497 if $cpu_vendor ne 'default';
3498 } elsif ($arch ne 'aarch64') {
3499 die "internal error"; # should not happen
3502 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3504 return ('-cpu', $cpu);
3507 sub config_to_command
{
3508 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3511 my $globalFlags = [];
3512 my $machineFlags = [];
3517 my $kvmver = kvm_user_version
();
3518 my $vernum = 0; # unknown
3519 my $ostype = $conf->{ostype
};
3520 my $winversion = windows_version
($ostype);
3521 my $kvm = $conf->{kvm
};
3523 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3524 $kvm //= 1 if is_native
($arch);
3527 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3528 if !defined kvm_version
();
3531 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3532 $vernum = $1*1000000+$2*1000;
3533 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3534 $vernum = $1*1000000+$2*1000+$3;
3537 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3539 my $have_ovz = -f
'/proc/vz/vestat';
3541 my $q35 = machine_type_is_q35
($conf);
3542 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3543 my $use_old_bios_files = undef;
3544 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3546 my $cpuunits = defined($conf->{cpuunits
}) ?
3547 $conf->{cpuunits
} : $defaults->{cpuunits
};
3549 push @$cmd, get_command_for_arch
($arch);
3551 push @$cmd, '-id', $vmid;
3553 my $vmname = $conf->{name
} || "vm$vmid";
3555 push @$cmd, '-name', $vmname;
3559 my $qmpsocket = qmp_socket
($vmid);
3560 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3561 push @$cmd, '-mon', "chardev=qmp,mode=control";
3563 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3564 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3565 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3568 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3570 push @$cmd, '-daemonize';
3572 if ($conf->{smbios1
}) {
3573 my $smbios_conf = parse_smbios1
($conf->{smbios1
});
3574 if ($smbios_conf->{base64
}) {
3575 # Do not pass base64 flag to qemu
3576 delete $smbios_conf->{base64
};
3577 my $smbios_string = "";
3578 foreach my $key (keys %$smbios_conf) {
3580 if ($key eq "uuid") {
3581 $value = $smbios_conf->{uuid
}
3583 $value = decode_base64
($smbios_conf->{$key});
3585 # qemu accepts any binary data, only commas need escaping by double comma
3587 $smbios_string .= "," . $key . "=" . $value if $value;
3589 push @$cmd, '-smbios', "type=1" . $smbios_string;
3591 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3595 if ($conf->{vmgenid
}) {
3596 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3599 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3600 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3601 die "uefi base image not found\n" if ! -f
$ovmf_code;
3605 if (my $efidisk = $conf->{efidisk0
}) {
3606 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3607 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3608 $format = $d->{format
};
3610 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3611 if (!defined($format)) {
3612 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3613 $format = qemu_img_format
($scfg, $volname);
3617 die "efidisk format must be specified\n"
3618 if !defined($format);
3621 warn "no efidisk configured! Using temporary efivars disk.\n";
3622 $path = "/tmp/$vmid-ovmf.fd";
3623 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3627 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3628 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3632 # add usb controllers
3633 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3634 push @$devices, @usbcontrollers if @usbcontrollers;
3635 my $vga = parse_vga
($conf->{vga
});
3637 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3638 $vga->{type
} = 'qxl' if $qxlnum;
3640 if (!$vga->{type
}) {
3641 if ($arch eq 'aarch64') {
3642 $vga->{type
} = 'virtio';
3643 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3644 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3646 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3650 # enable absolute mouse coordinates (needed by vnc)
3652 if (defined($conf->{tablet
})) {
3653 $tablet = $conf->{tablet
};
3655 $tablet = $defaults->{tablet
};
3656 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3657 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3661 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3662 my $kbd = print_keyboarddevice_full
($conf, $arch);
3663 push @$devices, '-device', $kbd if defined($kbd);
3667 my $gpu_passthrough;
3670 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3671 my $d = parse_hostpci
($conf->{"hostpci$i"});
3674 my $pcie = $d->{pcie
};
3676 die "q35 machine model is not enabled" if !$q35;
3677 # win7 wants to have the pcie devices directly on the pcie bus
3678 # instead of in the root port
3679 if ($winversion == 7) {
3680 $pciaddr = print_pcie_addr
("hostpci${i}bus0");
3682 $pciaddr = print_pcie_addr
("hostpci$i");
3685 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3688 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3689 my $romfile = $d->{romfile
};
3692 if ($d->{'x-vga'}) {
3693 $xvga = ',x-vga=on';
3695 $vga->{type
} = 'none' if !defined($conf->{vga
});
3696 $gpu_passthrough = 1;
3698 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3702 my $pcidevices = $d->{pciid
};
3703 my $multifunction = 1 if @$pcidevices > 1;
3705 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3706 my $id = $pcidevices->[0]->{id
};
3707 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3708 $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3709 } elsif ($d->{mdev
}) {
3710 warn "ignoring mediated device with multifunction device\n";
3714 foreach my $pcidevice (@$pcidevices) {
3716 my $id = "hostpci$i";
3717 $id .= ".$j" if $multifunction;
3718 my $addr = $pciaddr;
3719 $addr .= ".$j" if $multifunction;
3720 my $devicestr = "vfio-pci";
3722 $devicestr .= ",sysfsdev=$sysfspath";
3724 $devicestr .= ",host=$pcidevice->{id}";
3726 $devicestr .= ",id=$id$addr";
3729 $devicestr .= "$rombar$xvga";
3730 $devicestr .= ",multifunction=on" if $multifunction;
3731 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3734 push @$devices, '-device', $devicestr;
3740 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3741 push @$devices, @usbdevices if @usbdevices;
3743 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3744 if (my $path = $conf->{"serial$i"}) {
3745 if ($path eq 'socket') {
3746 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3747 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3748 # On aarch64, serial0 is the UART device. Qemu only allows
3749 # connecting UART devices via the '-serial' command line, as
3750 # the device has a fixed slot on the hardware...
3751 if ($arch eq 'aarch64' && $i == 0) {
3752 push @$devices, '-serial', "chardev:serial$i";
3754 push @$devices, '-device', "isa-serial,chardev=serial$i";
3757 die "no such serial device\n" if ! -c
$path;
3758 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3759 push @$devices, '-device', "isa-serial,chardev=serial$i";
3765 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3766 if (my $path = $conf->{"parallel$i"}) {
3767 die "no such parallel device\n" if ! -c
$path;
3768 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3769 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3770 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3776 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3777 $sockets = $conf->{sockets
} if $conf->{sockets
};
3779 my $cores = $conf->{cores
} || 1;
3781 my $maxcpus = $sockets * $cores;
3783 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3785 my $allowed_vcpus = $cpuinfo->{cpus
};
3787 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3788 if ($allowed_vcpus < $maxcpus);
3790 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3792 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3793 for (my $i = 2; $i <= $vcpus; $i++) {
3794 my $cpustr = print_cpu_device
($conf,$i);
3795 push @$cmd, '-device', $cpustr;
3800 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3802 push @$cmd, '-nodefaults';
3804 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3806 my $bootindex_hash = {};
3808 foreach my $o (split(//, $bootorder)) {
3809 $bootindex_hash->{$o} = $i*100;
3813 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3815 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3817 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3819 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3820 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3821 my $socket = vnc_socket
($vmid);
3822 push @$cmd, '-vnc', "unix:$socket,password";
3824 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3825 push @$cmd, '-nographic';
3829 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3831 my $useLocaltime = $conf->{localtime};
3833 if ($winversion >= 5) { # windows
3834 $useLocaltime = 1 if !defined($conf->{localtime});
3836 # use time drift fix when acpi is enabled
3837 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3838 $tdf = 1 if !defined($conf->{tdf
});
3842 if ($winversion >= 6) {
3843 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3844 push @$cmd, '-no-hpet';
3847 push @$rtcFlags, 'driftfix=slew' if $tdf;
3850 push @$machineFlags, 'accel=tcg';
3853 if ($machine_type) {
3854 push @$machineFlags, "type=${machine_type}";
3857 if (($conf->{startdate
}) && ($conf->{startdate
} ne 'now')) {
3858 push @$rtcFlags, "base=$conf->{startdate}";
3859 } elsif ($useLocaltime) {
3860 push @$rtcFlags, 'base=localtime';
3863 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3865 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3867 push @$cmd, '-S' if $conf->{freeze
};
3869 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3872 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3873 #push @$cmd, '-soundhw', 'es1370';
3874 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3876 if (parse_guest_agent
($conf)->{enabled
}) {
3877 my $qgasocket = qmp_socket
($vmid, 1);
3878 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3879 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3880 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3881 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3889 for(my $i = 1; $i < $qxlnum; $i++){
3890 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3893 # assume other OS works like Linux
3894 my ($ram, $vram) = ("134217728", "67108864");
3895 if ($vga->{memory
}) {
3896 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3897 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3899 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3900 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3904 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3906 my $nodename = PVE
::INotify
::nodename
();
3907 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3908 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3909 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3910 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3911 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3913 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3915 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3916 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3917 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3920 # enable balloon by default, unless explicitly disabled
3921 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3922 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3923 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3926 if ($conf->{watchdog
}) {
3927 my $wdopts = parse_watchdog
($conf->{watchdog
});
3928 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3929 my $watchdog = $wdopts->{model
} || 'i6300esb';
3930 push @$devices, '-device', "$watchdog$pciaddr";
3931 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3935 my $scsicontroller = {};
3936 my $ahcicontroller = {};
3937 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3939 # Add iscsi initiator name if available
3940 if (my $initiator = get_initiator_name
()) {
3941 push @$devices, '-iscsi', "initiator-name=$initiator";
3944 foreach_drive
($conf, sub {
3945 my ($ds, $drive) = @_;
3947 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3948 push @$vollist, $drive->{file
};
3951 # ignore efidisk here, already added in bios/fw handling code above
3952 return if $drive->{interface
} eq 'efidisk';
3954 $use_virtio = 1 if $ds =~ m/^virtio/;
3956 if (drive_is_cdrom
($drive)) {
3957 if ($bootindex_hash->{d
}) {
3958 $drive->{bootindex
} = $bootindex_hash->{d
};
3959 $bootindex_hash->{d
} += 1;
3962 if ($bootindex_hash->{c
}) {
3963 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3964 $bootindex_hash->{c
} += 1;
3968 if($drive->{interface
} eq 'virtio'){
3969 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3972 if ($drive->{interface
} eq 'scsi') {
3974 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3976 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3977 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3980 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3981 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3982 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3983 } elsif ($drive->{iothread
}) {
3984 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3988 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3989 $queues = ",num_queues=$drive->{queues}";
3992 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3993 $scsicontroller->{$controller}=1;
3996 if ($drive->{interface
} eq 'sata') {
3997 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3998 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3999 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
4000 $ahcicontroller->{$controller}=1;
4003 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
4004 push @$devices, '-drive',$drive_cmd;
4005 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
4008 for (my $i = 0; $i < $MAX_NETS; $i++) {
4009 next if !$conf->{"net$i"};
4010 my $d = parse_net
($conf->{"net$i"});
4013 $use_virtio = 1 if $d->{model
} eq 'virtio';
4015 if ($bootindex_hash->{n
}) {
4016 $d->{bootindex
} = $bootindex_hash->{n
};
4017 $bootindex_hash->{n
} += 1;
4020 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
4021 push @$devices, '-netdev', $netdevfull;
4023 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
4024 push @$devices, '-device', $netdevicefull;
4027 if ($conf->{ivshmem
}) {
4028 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
4032 $bus = print_pcie_addr
("ivshmem");
4034 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
4037 my $ivshmem_name = $ivshmem->{name
} // $vmid;
4038 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4040 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4041 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
4046 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
4051 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
4053 while (my ($k, $v) = each %$bridges) {
4054 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
4055 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
4059 push @$cmd, @$devices;
4060 push @$cmd, '-rtc', join(',', @$rtcFlags)
4061 if scalar(@$rtcFlags);
4062 push @$cmd, '-machine', join(',', @$machineFlags)
4063 if scalar(@$machineFlags);
4064 push @$cmd, '-global', join(',', @$globalFlags)
4065 if scalar(@$globalFlags);
4067 if (my $vmstate = $conf->{vmstate
}) {
4068 my $statepath = PVE
::Storage
::path
($storecfg, $vmstate);
4069 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
4070 push @$cmd, '-loadstate', $statepath;
4074 if ($conf->{args
}) {
4075 my $aa = PVE
::Tools
::split_args
($conf->{args
});
4079 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
4084 return "${var_run_tmpdir}/$vmid.vnc";
4090 my $res = vm_mon_cmd
($vmid, 'query-spice');
4092 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
4096 my ($vmid, $qga, $name) = @_;
4097 my $sockettype = $qga ?
'qga' : 'qmp';
4098 my $ext = $name ?
'-'.$name : '';
4099 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
4104 return "${var_run_tmpdir}/$vmid.pid";
4107 sub vm_devices_list
{
4110 my $res = vm_mon_cmd
($vmid, 'query-pci');
4111 my $devices_to_check = [];
4113 foreach my $pcibus (@$res) {
4114 push @$devices_to_check, @{$pcibus->{devices
}},
4117 while (@$devices_to_check) {
4119 for my $d (@$devices_to_check) {
4120 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4121 next if !$d->{'pci_bridge'};
4123 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
4124 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
4126 $devices_to_check = $to_check;
4129 my $resblock = vm_mon_cmd
($vmid, 'query-block');
4130 foreach my $block (@$resblock) {
4131 if($block->{device
} =~ m/^drive-(\S+)/){
4136 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
4137 foreach my $mice (@$resmice) {
4138 if ($mice->{name
} eq 'QEMU HID Tablet') {
4139 $devices->{tablet
} = 1;
4144 # for usb devices there is no query-usb
4145 # but we can iterate over the entries in
4146 # qom-list path=/machine/peripheral
4147 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4148 foreach my $per (@$resperipheral) {
4149 if ($per->{name
} =~ m/^usb\d+$/) {
4150 $devices->{$per->{name
}} = 1;
4158 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4160 my $q35 = machine_type_is_q35
($conf);
4162 my $devices_list = vm_devices_list
($vmid);
4163 return 1 if defined($devices_list->{$deviceid});
4165 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
4167 if ($deviceid eq 'tablet') {
4169 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4171 } elsif ($deviceid eq 'keyboard') {
4173 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4175 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4177 die "usb hotplug currently not reliable\n";
4178 # since we can't reliably hot unplug all added usb devices
4179 # and usb passthrough disables live migration
4180 # we disable usb hotplugging for now
4181 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
4183 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4185 qemu_iothread_add
($vmid, $deviceid, $device);
4187 qemu_driveadd
($storecfg, $vmid, $device);
4188 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4190 qemu_deviceadd
($vmid, $devicefull);
4191 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4193 eval { qemu_drivedel
($vmid, $deviceid); };
4198 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4201 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4202 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4203 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4205 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4207 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4208 qemu_iothread_add
($vmid, $deviceid, $device);
4209 $devicefull .= ",iothread=iothread-$deviceid";
4212 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4213 $devicefull .= ",num_queues=$device->{queues}";
4216 qemu_deviceadd
($vmid, $devicefull);
4217 qemu_deviceaddverify
($vmid, $deviceid);
4219 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4221 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4222 qemu_driveadd
($storecfg, $vmid, $device);
4224 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4225 eval { qemu_deviceadd
($vmid, $devicefull); };
4227 eval { qemu_drivedel
($vmid, $deviceid); };
4232 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4234 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4236 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4237 my $use_old_bios_files = undef;
4238 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4240 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4241 qemu_deviceadd
($vmid, $netdevicefull);
4243 qemu_deviceaddverify
($vmid, $deviceid);
4244 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4247 eval { qemu_netdevdel
($vmid, $deviceid); };
4252 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4255 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4256 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4258 qemu_deviceadd
($vmid, $devicefull);
4259 qemu_deviceaddverify
($vmid, $deviceid);
4262 die "can't hotplug device '$deviceid'\n";
4268 # fixme: this should raise exceptions on error!
4269 sub vm_deviceunplug
{
4270 my ($vmid, $conf, $deviceid) = @_;
4272 my $devices_list = vm_devices_list
($vmid);
4273 return 1 if !defined($devices_list->{$deviceid});
4275 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4277 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4279 qemu_devicedel
($vmid, $deviceid);
4281 } elsif ($deviceid =~ m/^usb\d+$/) {
4283 die "usb hotplug currently not reliable\n";
4284 # when unplugging usb devices this way,
4285 # there may be remaining usb controllers/hubs
4286 # so we disable it for now
4287 qemu_devicedel
($vmid, $deviceid);
4288 qemu_devicedelverify
($vmid, $deviceid);
4290 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4292 qemu_devicedel
($vmid, $deviceid);
4293 qemu_devicedelverify
($vmid, $deviceid);
4294 qemu_drivedel
($vmid, $deviceid);
4295 qemu_iothread_del
($conf, $vmid, $deviceid);
4297 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4299 qemu_devicedel
($vmid, $deviceid);
4300 qemu_devicedelverify
($vmid, $deviceid);
4301 qemu_iothread_del
($conf, $vmid, $deviceid);
4303 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4305 qemu_devicedel
($vmid, $deviceid);
4306 qemu_drivedel
($vmid, $deviceid);
4307 qemu_deletescsihw
($conf, $vmid, $deviceid);
4309 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4311 qemu_devicedel
($vmid, $deviceid);
4312 qemu_devicedelverify
($vmid, $deviceid);
4313 qemu_netdevdel
($vmid, $deviceid);
4316 die "can't unplug device '$deviceid'\n";
4322 sub qemu_deviceadd
{
4323 my ($vmid, $devicefull) = @_;
4325 $devicefull = "driver=".$devicefull;
4326 my %options = split(/[=,]/, $devicefull);
4328 vm_mon_cmd
($vmid, "device_add" , %options);
4331 sub qemu_devicedel
{
4332 my ($vmid, $deviceid) = @_;
4334 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4337 sub qemu_iothread_add
{
4338 my($vmid, $deviceid, $device) = @_;
4340 if ($device->{iothread
}) {
4341 my $iothreads = vm_iothreads_list
($vmid);
4342 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4346 sub qemu_iothread_del
{
4347 my($conf, $vmid, $deviceid) = @_;
4349 my $confid = $deviceid;
4350 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
4351 $confid = 'scsi' . $1;
4353 my $device = parse_drive
($confid, $conf->{$confid});
4354 if ($device->{iothread
}) {
4355 my $iothreads = vm_iothreads_list
($vmid);
4356 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4360 sub qemu_objectadd
{
4361 my($vmid, $objectid, $qomtype) = @_;
4363 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4368 sub qemu_objectdel
{
4369 my($vmid, $objectid) = @_;
4371 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4377 my ($storecfg, $vmid, $device) = @_;
4379 my $drive = print_drive_full
($storecfg, $vmid, $device);
4380 $drive =~ s/\\/\\\\/g;
4381 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4383 # If the command succeeds qemu prints: "OK
"
4384 return 1 if $ret =~ m/OK/s;
4386 die "adding drive failed
: $ret\n";
4390 my($vmid, $deviceid) = @_;
4392 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4395 return 1 if $ret eq "";
4397 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4398 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4400 die "deleting drive
$deviceid failed
: $ret\n";
4403 sub qemu_deviceaddverify {
4404 my ($vmid, $deviceid) = @_;
4406 for (my $i = 0; $i <= 5; $i++) {
4407 my $devices_list = vm_devices_list($vmid);
4408 return 1 if defined($devices_list->{$deviceid});
4412 die "error on hotplug device
'$deviceid'\n";
4416 sub qemu_devicedelverify {
4417 my ($vmid, $deviceid) = @_;
4419 # need to verify that the device is correctly removed as device_del
4420 # is async and empty return is not reliable
4422 for (my $i = 0; $i <= 5; $i++) {
4423 my $devices_list = vm_devices_list($vmid);
4424 return 1 if !defined($devices_list->{$deviceid});
4428 die "error on hot-unplugging device
'$deviceid'\n";
4431 sub qemu_findorcreatescsihw {
4432 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4434 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4436 my $scsihwid="$controller_prefix$controller";
4437 my $devices_list = vm_devices_list($vmid);
4439 if(!defined($devices_list->{$scsihwid})) {
4440 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4446 sub qemu_deletescsihw {
4447 my ($conf, $vmid, $opt) = @_;
4449 my $device = parse_drive($opt, $conf->{$opt});
4451 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4452 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4456 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4458 my $devices_list = vm_devices_list($vmid);
4459 foreach my $opt (keys %{$devices_list}) {
4460 if (PVE::QemuServer::is_valid_drivename($opt)) {
4461 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4462 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4468 my $scsihwid="scsihw
$controller";
4470 vm_deviceunplug($vmid, $conf, $scsihwid);
4475 sub qemu_add_pci_bridge {
4476 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4482 print_pci_addr($device, $bridges, $arch, $machine_type);
4484 while (my ($k, $v) = each %$bridges) {
4487 return 1 if !defined($bridgeid) || $bridgeid < 1;
4489 my $bridge = "pci
.$bridgeid";
4490 my $devices_list = vm_devices_list($vmid);
4492 if (!defined($devices_list->{$bridge})) {
4493 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4499 sub qemu_set_link_status {
4500 my ($vmid, $device, $up) = @_;
4502 vm_mon_cmd($vmid, "set_link
", name => $device,
4503 up => $up ? JSON::true : JSON::false);
4506 sub qemu_netdevadd {
4507 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4509 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4510 my %options = split(/[=,]/, $netdev);
4512 vm_mon_cmd($vmid, "netdev_add
", %options);
4516 sub qemu_netdevdel {
4517 my ($vmid, $deviceid) = @_;
4519 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4522 sub qemu_usb_hotplug {
4523 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4527 # remove the old one first
4528 vm_deviceunplug($vmid, $conf, $deviceid);
4530 # check if xhci controller is necessary and available
4531 if ($device->{usb3}) {
4533 my $devicelist = vm_devices_list($vmid);
4535 if (!$devicelist->{xhci}) {
4536 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4537 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4540 my $d = parse_usb_device($device->{host});
4541 $d->{usb3} = $device->{usb3};
4544 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4547 sub qemu_cpu_hotplug {
4548 my ($vmid, $conf, $vcpus) = @_;
4550 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4553 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4554 $sockets = $conf->{sockets} if $conf->{sockets};
4555 my $cores = $conf->{cores} || 1;
4556 my $maxcpus = $sockets * $cores;
4558 $vcpus = $maxcpus if !$vcpus;
4560 die "you can
't add more vcpus than maxcpus\n"
4561 if $vcpus > $maxcpus;
4563 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4565 if ($vcpus < $currentvcpus) {
4567 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4569 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4570 qemu_devicedel($vmid, "cpu$i");
4572 my $currentrunningvcpus = undef;
4574 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4575 last if scalar(@{$currentrunningvcpus}) == $i-1;
4576 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4580 #update conf after each succesfull cpu unplug
4581 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4582 PVE::QemuConfig->write_config($vmid, $conf);
4585 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4591 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4592 die "vcpus in running vm does not match its configuration\n"
4593 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4595 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4597 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4598 my $cpustr = print_cpu_device($conf, $i);
4599 qemu_deviceadd($vmid, $cpustr);
4602 my $currentrunningvcpus = undef;
4604 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4605 last if scalar(@{$currentrunningvcpus}) == $i;
4606 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4610 #update conf after each succesfull cpu hotplug
4611 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4612 PVE::QemuConfig->write_config($vmid, $conf);
4616 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4617 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4622 sub qemu_block_set_io_throttle {
4623 my ($vmid, $deviceid,
4624 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4625 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4626 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4627 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4629 return if !check_running($vmid) ;
4631 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4633 bps_rd => int($bps_rd),
4634 bps_wr => int($bps_wr),
4636 iops_rd => int($iops_rd),
4637 iops_wr => int($iops_wr),
4638 bps_max => int($bps_max),
4639 bps_rd_max => int($bps_rd_max),
4640 bps_wr_max => int($bps_wr_max),
4641 iops_max => int($iops_max),
4642 iops_rd_max => int($iops_rd_max),
4643 iops_wr_max => int($iops_wr_max),
4644 bps_max_length => int($bps_max_length),
4645 bps_rd_max_length => int($bps_rd_max_length),
4646 bps_wr_max_length => int($bps_wr_max_length),
4647 iops_max_length => int($iops_max_length),
4648 iops_rd_max_length => int($iops_rd_max_length),
4649 iops_wr_max_length => int($iops_wr_max_length),
4654 # old code, only used to shutdown old VM after update
4656 my ($fh, $timeout) = @_;
4658 my $sel = new IO::Select;
4665 while (scalar (@ready = $sel->can_read($timeout))) {
4667 if ($count = $fh->sysread($buf, 8192)) {
4668 if ($buf =~ /^(.*)\(qemu\) $/s) {
4675 if (!defined($count)) {
4682 die "monitor read timeout\n" if !scalar(@ready);
4687 sub qemu_block_resize {
4688 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4690 my $running = check_running($vmid);
4692 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4694 return if !$running;
4696 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4700 sub qemu_volume_snapshot {
4701 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4703 my $running = check_running($vmid);
4705 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4706 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4708 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4712 sub qemu_volume_snapshot_delete {
4713 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4715 my $running = check_running($vmid);
4720 my $conf = PVE::QemuConfig->load_config($vmid);
4721 foreach_drive($conf, sub {
4722 my ($ds, $drive) = @_;
4723 $running = 1 if $drive->{file} eq $volid;
4727 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4728 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4730 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4734 sub set_migration_caps {
4740 "auto-converge" => 1,
4742 "x-rdma-pin-all" => 0,
4747 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4749 for my $supported_capability (@$supported_capabilities) {
4751 capability => $supported_capability->{capability},
4752 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4756 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4759 my $fast_plug_option = {
4767 'vmstatestorage
' => 1,
4771 # hotplug changes in [PENDING]
4772 # $selection hash can be used to only apply specified options, for
4773 # example: { cores => 1 } (only apply changed 'cores
')
4774 # $errors ref is used to return error messages
4775 sub vmconfig_hotplug_pending {
4776 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4778 my $defaults = load_defaults();
4779 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4781 # commit values which do not have any impact on running VM first
4782 # Note: those option cannot raise errors, we we do not care about
4783 # $selection and always apply them.
4785 my $add_error = sub {
4786 my ($opt, $msg) = @_;
4787 $errors->{$opt} = "hotplug problem - $msg";
4791 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4792 if ($fast_plug_option->{$opt}) {
4793 $conf->{$opt} = $conf->{pending}->{$opt};
4794 delete $conf->{pending}->{$opt};
4800 PVE::QemuConfig->write_config($vmid, $conf);
4801 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4804 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4806 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4807 while (my ($opt, $force) = each %$pending_delete_hash) {
4808 next if $selection && !$selection->{$opt};
4810 if ($opt eq 'hotplug
') {
4811 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4812 } elsif ($opt eq 'tablet
') {
4813 die "skip\n" if !$hotplug_features->{usb};
4814 if ($defaults->{tablet}) {
4815 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4816 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4817 if $arch eq 'aarch64
';
4819 vm_deviceunplug($vmid, $conf, 'tablet
');
4820 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4822 } elsif ($opt =~ m/^usb\d+/) {
4824 # since we cannot reliably hot unplug usb devices
4825 # we are disabling it
4826 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4827 vm_deviceunplug($vmid, $conf, $opt);
4828 } elsif ($opt eq 'vcpus
') {
4829 die "skip\n" if !$hotplug_features->{cpu};
4830 qemu_cpu_hotplug($vmid, $conf, undef);
4831 } elsif ($opt eq 'balloon
') {
4832 # enable balloon device is not hotpluggable
4833 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4834 # here we reset the ballooning value to memory
4835 my $balloon = $conf->{memory} || $defaults->{memory};
4836 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4837 } elsif ($fast_plug_option->{$opt}) {
4839 } elsif ($opt =~ m/^net(\d+)$/) {
4840 die "skip\n" if !$hotplug_features->{network};
4841 vm_deviceunplug($vmid, $conf, $opt);
4842 } elsif (is_valid_drivename($opt)) {
4843 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4844 vm_deviceunplug($vmid, $conf, $opt);
4845 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4846 } elsif ($opt =~ m/^memory$/) {
4847 die "skip\n" if !$hotplug_features->{memory};
4848 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4849 } elsif ($opt eq 'cpuunits
') {
4850 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4851 } elsif ($opt eq 'cpulimit
') {
4852 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4858 &$add_error($opt, $err) if $err ne "skip\n";
4860 # save new config if hotplug was successful
4861 delete $conf->{$opt};
4862 vmconfig_undelete_pending_option($conf, $opt);
4863 PVE::QemuConfig->write_config($vmid, $conf);
4864 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4868 my $apply_pending_cloudinit;
4869 $apply_pending_cloudinit = sub {
4870 my ($key, $value) = @_;
4871 $apply_pending_cloudinit = sub {}; # once is enough
4873 my @cloudinit_opts = keys %$confdesc_cloudinit;
4874 foreach my $opt (keys %{$conf->{pending}}) {
4875 next if !grep { $_ eq $opt } @cloudinit_opts;
4876 $conf->{$opt} = delete $conf->{pending}->{$opt};
4879 my $new_conf = { %$conf };
4880 $new_conf->{$key} = $value;
4881 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4884 foreach my $opt (keys %{$conf->{pending}}) {
4885 next if $selection && !$selection->{$opt};
4886 my $value = $conf->{pending}->{$opt};
4888 if ($opt eq 'hotplug
') {
4889 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4890 } elsif ($opt eq 'tablet
') {
4891 die "skip\n" if !$hotplug_features->{usb};
4893 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4894 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4895 if $arch eq 'aarch64
';
4896 } elsif ($value == 0) {
4897 vm_deviceunplug($vmid, $conf, 'tablet
');
4898 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4900 } elsif ($opt =~ m/^usb\d+$/) {
4902 # since we cannot reliably hot unplug usb devices
4903 # we are disabling it
4904 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4905 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4906 die "skip\n" if !$d;
4907 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4908 } elsif ($opt eq 'vcpus
') {
4909 die "skip\n" if !$hotplug_features->{cpu};
4910 qemu_cpu_hotplug($vmid, $conf, $value);
4911 } elsif ($opt eq 'balloon
') {
4912 # enable/disable balloning device is not hotpluggable
4913 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4914 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4915 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4917 # allow manual ballooning if shares is set to zero
4918 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4919 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4920 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4922 } elsif ($opt =~ m/^net(\d+)$/) {
4923 # some changes can be done without hotplug
4924 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4925 $vmid, $opt, $value, $arch, $machine_type);
4926 } elsif (is_valid_drivename($opt)) {
4927 # some changes can be done without hotplug
4928 my $drive = parse_drive($opt, $value);
4929 if (drive_is_cloudinit($drive)) {
4930 &$apply_pending_cloudinit($opt, $value);
4932 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4933 $vmid, $opt, $value, 1, $arch, $machine_type);
4934 } elsif ($opt =~ m/^memory$/) { #dimms
4935 die "skip\n" if !$hotplug_features->{memory};
4936 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4937 } elsif ($opt eq 'cpuunits
') {
4938 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4939 } elsif ($opt eq 'cpulimit
') {
4940 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4941 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4943 die "skip\n"; # skip non-hot-pluggable options
4947 &$add_error($opt, $err) if $err ne "skip\n";
4949 # save new config if hotplug was successful
4950 $conf->{$opt} = $value;
4951 delete $conf->{pending}->{$opt};
4952 PVE::QemuConfig->write_config($vmid, $conf);
4953 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4958 sub try_deallocate_drive {
4959 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4961 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4962 my $volid = $drive->{file};
4963 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4964 my $sid = PVE::Storage::parse_volume_id($volid);
4965 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4967 # check if the disk is really unused
4968 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4969 if is_volume_in_use($storecfg, $conf, $key, $volid);
4970 PVE::Storage::vdisk_free($storecfg, $volid);
4973 # If vm is not owner of this disk remove from config
4981 sub vmconfig_delete_or_detach_drive {
4982 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4984 my $drive = parse_drive($opt, $conf->{$opt});
4986 my $rpcenv = PVE::RPCEnvironment::get();
4987 my $authuser = $rpcenv->get_user();
4990 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4991 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4993 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4997 sub vmconfig_apply_pending {
4998 my ($vmid, $conf, $storecfg) = @_;
5002 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
5003 while (my ($opt, $force) = each %$pending_delete_hash) {
5004 die "internal error" if $opt =~ m/^unused/;
5005 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5006 if (!defined($conf->{$opt})) {
5007 vmconfig_undelete_pending_option($conf, $opt);
5008 PVE::QemuConfig->write_config($vmid, $conf);
5009 } elsif (is_valid_drivename($opt)) {
5010 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
5011 vmconfig_undelete_pending_option($conf, $opt);
5012 delete $conf->{$opt};
5013 PVE::QemuConfig->write_config($vmid, $conf);
5015 vmconfig_undelete_pending_option($conf, $opt);
5016 delete $conf->{$opt};
5017 PVE::QemuConfig->write_config($vmid, $conf);
5021 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5023 foreach my $opt (keys %{$conf->{pending}}) { # add/change
5024 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5026 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
5027 # skip if nothing changed
5028 } elsif (is_valid_drivename($opt)) {
5029 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
5030 if defined($conf->{$opt});
5031 $conf->{$opt} = $conf->{pending}->{$opt};
5033 $conf->{$opt} = $conf->{pending}->{$opt};
5036 delete $conf->{pending}->{$opt};
5037 PVE::QemuConfig->write_config($vmid, $conf);
5041 my $safe_num_ne = sub {
5044 return 0 if !defined($a) && !defined($b);
5045 return 1 if !defined($a);
5046 return 1 if !defined($b);
5051 my $safe_string_ne = sub {
5054 return 0 if !defined($a) && !defined($b);
5055 return 1 if !defined($a);
5056 return 1 if !defined($b);
5061 sub vmconfig_update_net {
5062 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
5064 my $newnet = parse_net($value);
5066 if ($conf->{$opt}) {
5067 my $oldnet = parse_net($conf->{$opt});
5069 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5070 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5071 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
5072 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5074 # for non online change, we try to hot-unplug
5075 die "skip\n" if !$hotplug;
5076 vm_deviceunplug($vmid, $conf, $opt);
5079 die "internal error" if $opt !~ m/net(\d+)/;
5080 my $iface = "tap${vmid}i$1";
5082 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5083 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
5084 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
5085 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
5086 PVE::Network::tap_unplug($iface);
5087 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5088 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
5089 # Rate can be applied on its own but any change above needs to
5090 # include the rate in tap_plug since OVS resets everything.
5091 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
5094 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5095 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5103 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5109 sub vmconfig_update_disk {
5110 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
5112 # fixme: do we need force?
5114 my $drive = parse_drive($opt, $value);
5116 if ($conf->{$opt}) {
5118 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5120 my $media = $drive->{media} || 'disk
';
5121 my $oldmedia = $old_drive->{media} || 'disk
';
5122 die "unable to change media type\n" if $media ne $oldmedia;
5124 if (!drive_is_cdrom($old_drive)) {
5126 if ($drive->{file} ne $old_drive->{file}) {
5128 die "skip\n" if !$hotplug;
5130 # unplug and register as unused
5131 vm_deviceunplug($vmid, $conf, $opt);
5132 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5135 # update existing disk
5137 # skip non hotpluggable value
5138 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5139 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5140 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5141 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5146 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5147 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5148 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5149 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5150 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5151 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5152 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5153 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5154 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5155 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5156 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5157 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5158 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5159 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5160 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5161 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5162 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5163 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5165 qemu_block_set_io_throttle($vmid,"drive-$opt",
5166 ($drive->{mbps} || 0)*1024*1024,
5167 ($drive->{mbps_rd} || 0)*1024*1024,
5168 ($drive->{mbps_wr} || 0)*1024*1024,
5169 $drive->{iops} || 0,
5170 $drive->{iops_rd} || 0,
5171 $drive->{iops_wr} || 0,
5172 ($drive->{mbps_max} || 0)*1024*1024,
5173 ($drive->{mbps_rd_max} || 0)*1024*1024,
5174 ($drive->{mbps_wr_max} || 0)*1024*1024,
5175 $drive->{iops_max} || 0,
5176 $drive->{iops_rd_max} || 0,
5177 $drive->{iops_wr_max} || 0,
5178 $drive->{bps_max_length} || 1,
5179 $drive->{bps_rd_max_length} || 1,
5180 $drive->{bps_wr_max_length} || 1,
5181 $drive->{iops_max_length} || 1,
5182 $drive->{iops_rd_max_length} || 1,
5183 $drive->{iops_wr_max_length} || 1);
5192 if ($drive->{file} eq 'none
') {
5193 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5194 if (drive_is_cloudinit($old_drive)) {
5195 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5198 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5199 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5200 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5208 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5210 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5211 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5215 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5216 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5218 PVE::QemuConfig->lock_config($vmid, sub {
5219 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5221 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5223 my $is_suspended = PVE::QemuConfig->has_lock($conf, 'suspended
');
5225 PVE::QemuConfig->check_lock($conf)
5226 if !($skiplock || $is_suspended);
5228 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5230 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5231 vmconfig_apply_pending($vmid, $conf, $storecfg);
5232 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5235 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5237 my $defaults = load_defaults();
5239 # set environment variable useful inside network script
5240 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5242 my $local_volumes = {};
5244 if ($targetstorage) {
5245 foreach_drive($conf, sub {
5246 my ($ds, $drive) = @_;
5248 return if drive_is_cdrom($drive);
5250 my $volid = $drive->{file};
5254 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5256 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5257 return if $scfg->{shared};
5258 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5263 foreach my $opt (sort keys %$local_volumes) {
5265 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5266 my $drive = parse_drive($opt, $conf->{$opt});
5268 #if remote storage is specified, use default format
5269 if ($targetstorage && $targetstorage ne "1") {
5270 $storeid = $targetstorage;
5271 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5272 $format = $defFormat;
5274 #else we use same format than original
5275 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5276 $format = qemu_img_format($scfg, $volid);
5279 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5280 my $newdrive = $drive;
5281 $newdrive->{format} = $format;
5282 $newdrive->{file} = $newvolid;
5283 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5284 $local_volumes->{$opt} = $drivestr;
5285 #pass drive to conf for command line
5286 $conf->{$opt} = $drivestr;
5290 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
5292 if ($is_suspended) {
5293 # enforce machine type on suspended vm to ensure HW compatibility
5294 $forcemachine = $conf->{runningmachine};
5295 print "Resuming suspended VM\n";
5298 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5300 my $migrate_port = 0;
5303 if ($statefile eq 'tcp
') {
5304 my $localip = "localhost";
5305 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5306 my $nodename = PVE::INotify::nodename();
5308 if (!defined($migration_type)) {
5309 if (defined($datacenterconf->{migration}->{type})) {
5310 $migration_type = $datacenterconf->{migration}->{type};
5312 $migration_type = 'secure
';
5316 if ($migration_type eq 'insecure
') {
5317 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5318 if ($migrate_network_addr) {
5319 $localip = $migrate_network_addr;
5321 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5324 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5327 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5328 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5329 $migrate_uri = "tcp:${localip}:${migrate_port}";
5330 push @$cmd, '-incoming
', $migrate_uri;
5333 } elsif ($statefile eq 'unix
') {
5334 # should be default for secure migrations as a ssh TCP forward
5335 # tunnel is not deterministic reliable ready and fails regurarly
5336 # to set up in time, so use UNIX socket forwards
5337 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5338 unlink $socket_addr;
5340 $migrate_uri = "unix:$socket_addr";
5342 push @$cmd, '-incoming
', $migrate_uri;
5346 push @$cmd, '-loadstate
', $statefile;
5353 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5354 my $d = parse_hostpci($conf->{"hostpci$i"});
5356 my $pcidevices = $d->{pciid};
5357 foreach my $pcidevice (@$pcidevices) {
5358 my $pciid = $pcidevice->{id};
5360 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5361 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5362 die "no pci device info for device '$pciid'\n" if !$info;
5365 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5366 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5368 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5369 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5370 die "can
't reset pci device '$pciid'\n"
5371 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5376 PVE::Storage::activate_volumes($storecfg, $vollist);
5379 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5380 outfunc => sub {}, errfunc => sub {});
5382 # Issues with the above 'stop
' not being fully completed are extremely rare, a very low
5383 # timeout should be more than enough here...
5384 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
5386 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5387 : $defaults->{cpuunits};
5389 my $start_timeout = ($conf->{hugepages} || $is_suspended) ? 300 : 30;
5390 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5393 Slice => 'qemu
.slice
',
5395 CPUShares => $cpuunits
5398 if (my $cpulimit = $conf->{cpulimit}) {
5399 $properties{CPUQuota} = int($cpulimit * 100);
5401 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5403 my $run_qemu = sub {
5404 PVE::Tools::run_fork sub {
5405 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5406 run_command($cmd, %run_params);
5410 if ($conf->{hugepages}) {
5413 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5414 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5416 PVE::QemuServer::Memory::hugepages_mount();
5417 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5419 eval { $run_qemu->() };
5421 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5425 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5427 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5430 eval { $run_qemu->() };
5434 # deactivate volumes if start fails
5435 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5436 die "start failed: $err";
5439 print "migration listens on $migrate_uri\n" if $migrate_uri;
5441 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5442 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5446 #start nbd server for storage migration
5447 if ($targetstorage) {
5448 my $nodename = PVE::INotify::nodename();
5449 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5450 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5451 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5452 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5454 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5456 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5458 foreach my $opt (sort keys %$local_volumes) {
5459 my $volid = $local_volumes->{$opt};
5460 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5461 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5462 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5466 if ($migratedfrom) {
5468 set_migration_caps($vmid);
5473 print "spice listens on port $spice_port\n";
5474 if ($spice_ticket) {
5475 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5476 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5481 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5482 if !$statefile && $conf->{balloon};
5484 foreach my $opt (keys %$conf) {
5485 next if $opt !~ m/^net\d+$/;
5486 my $nicconf = parse_net($conf->{$opt});
5487 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5491 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5492 path => "machine/peripheral/balloon0",
5493 property => "guest-stats-polling-interval",
5494 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5496 if ($is_suspended && (my $vmstate = $conf->{vmstate})) {
5497 print "Resumed VM, removing state\n";
5498 delete $conf->@{qw(lock vmstate runningmachine)};
5499 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5500 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5501 PVE
::QemuConfig-
>write_config($vmid, $conf);
5504 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'post-start');
5509 my ($vmid, $execute, %params) = @_;
5511 my $cmd = { execute
=> $execute, arguments
=> \
%params };
5512 vm_qmp_command
($vmid, $cmd);
5515 sub vm_mon_cmd_nocheck
{
5516 my ($vmid, $execute, %params) = @_;
5518 my $cmd = { execute
=> $execute, arguments
=> \
%params };
5519 vm_qmp_command
($vmid, $cmd, 1);
5522 sub vm_qmp_command
{
5523 my ($vmid, $cmd, $nocheck) = @_;
5528 if ($cmd->{arguments
}) {
5529 $timeout = delete $cmd->{arguments
}->{timeout
};
5533 die "VM $vmid not running\n" if !check_running
($vmid, $nocheck);
5534 my $sname = qmp_socket
($vmid);
5535 if (-e
$sname) { # test if VM is reasonambe new and supports qmp/qga
5536 my $qmpclient = PVE
::QMPClient-
>new();
5538 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5540 die "unable to open monitor socket\n";
5544 syslog
("err", "VM $vmid qmp command failed - $err");
5551 sub vm_human_monitor_command
{
5552 my ($vmid, $cmdline) = @_;
5557 execute
=> 'human-monitor-command',
5558 arguments
=> { 'command-line' => $cmdline},
5561 return vm_qmp_command
($vmid, $cmd);
5564 sub vm_commandline
{
5565 my ($storecfg, $vmid, $snapname) = @_;
5567 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5570 my $snapshot = $conf->{snapshots
}->{$snapname};
5571 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5573 $snapshot->{digest
} = $conf->{digest
}; # keep file digest for API
5578 my $defaults = load_defaults
();
5580 my $cmd = config_to_command
($storecfg, $vmid, $conf, $defaults);
5582 return PVE
::Tools
::cmd2string
($cmd);
5586 my ($vmid, $skiplock) = @_;
5588 PVE
::QemuConfig-
>lock_config($vmid, sub {
5590 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5592 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5594 vm_mon_cmd
($vmid, "system_reset");
5598 sub get_vm_volumes
{
5602 foreach_volid
($conf, sub {
5603 my ($volid, $attr) = @_;
5605 return if $volid =~ m
|^/|;
5607 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5610 push @$vollist, $volid;
5616 sub vm_stop_cleanup
{
5617 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5622 my $vollist = get_vm_volumes
($conf);
5623 PVE
::Storage
::deactivate_volumes
($storecfg, $vollist);
5626 foreach my $ext (qw(mon qmp pid vnc qga)) {
5627 unlink "/var/run/qemu-server/${vmid}.$ext";
5630 if ($conf->{ivshmem
}) {
5631 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5632 # just delete it for now, VMs which have this already open do not
5633 # are affected, but new VMs will get a separated one. If this
5634 # becomes an issue we either add some sort of ref-counting or just
5635 # add a "don't delete on stop" flag to the ivshmem format.
5636 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5639 foreach my $key (keys %$conf) {
5640 next if $key !~ m/^hostpci(\d+)$/;
5641 my $hostpciindex = $1;
5642 my $d = parse_hostpci
($conf->{$key});
5643 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5645 foreach my $pci (@{$d->{pciid
}}) {
5646 my $pciid = $pci->{id
};
5647 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5651 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5653 warn $@ if $@; # avoid errors - just warn
5656 # Note: use $nockeck to skip tests if VM configuration file exists.
5657 # We need that when migration VMs to other nodes (files already moved)
5658 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5660 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5662 $force = 1 if !defined($force) && !$shutdown;
5665 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5666 kill 15, $pid if $pid;
5667 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5668 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5672 PVE
::QemuConfig-
>lock_config($vmid, sub {
5674 my $pid = check_running
($vmid, $nocheck);
5679 $conf = PVE
::QemuConfig-
>load_config($vmid);
5680 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5681 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5682 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5683 $timeout = $opts->{down
} if $opts->{down
};
5685 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5690 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5691 vm_qmp_command
($vmid, {
5692 execute
=> "guest-shutdown",
5693 arguments
=> { timeout
=> $timeout }
5696 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5699 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5705 $timeout = 60 if !defined($timeout);
5708 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5713 if ($count >= $timeout) {
5715 warn "VM still running - terminating now with SIGTERM\n";
5718 die "VM quit/powerdown failed - got timeout\n";
5721 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5726 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5729 die "VM quit/powerdown failed\n";
5737 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5742 if ($count >= $timeout) {
5743 warn "VM still running - terminating now with SIGKILL\n";
5748 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5753 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
5760 PVE
::QemuConfig-
>lock_config($vmid, sub {
5762 $conf = PVE
::QemuConfig-
>load_config($vmid);
5764 my $is_backing_up = PVE
::QemuConfig-
>has_lock($conf, 'backup');
5765 PVE
::QemuConfig-
>check_lock($conf)
5766 if !($skiplock || $is_backing_up);
5768 die "cannot suspend to disk during backup\n"
5769 if $is_backing_up && $includestate;
5771 if ($includestate) {
5772 $conf->{lock} = 'suspending';
5773 my $date = strftime
("%Y-%m-%d", localtime(time()));
5774 $storecfg = PVE
::Storage
::config
();
5775 $vmstate = PVE
::QemuConfig-
>__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
5776 $path = PVE
::Storage
::path
($storecfg, $vmstate);
5777 PVE
::QemuConfig-
>write_config($vmid, $conf);
5779 vm_mon_cmd
($vmid, "stop");
5783 if ($includestate) {
5785 PVE
::Storage
::activate_volumes
($storecfg, [$vmstate]);
5788 vm_mon_cmd
($vmid, "savevm-start", statefile
=> $path);
5790 my $state = vm_mon_cmd_nocheck
($vmid, "query-savevm");
5791 if (!$state->{status
}) {
5792 die "savevm not active\n";
5793 } elsif ($state->{status
} eq 'active') {
5796 } elsif ($state->{status
} eq 'completed') {
5797 print "State saved, quitting\n";
5799 } elsif ($state->{status
} eq 'failed' && $state->{error
}) {
5800 die "query-savevm failed with error '$state->{error}'\n"
5802 die "query-savevm returned status '$state->{status}'\n";
5808 PVE
::QemuConfig-
>lock_config($vmid, sub {
5809 $conf = PVE
::QemuConfig-
>load_config($vmid);
5811 # cleanup, but leave suspending lock, to indicate something went wrong
5813 vm_mon_cmd
($vmid, "savevm-end");
5814 PVE
::Storage
::deactivate_volumes
($storecfg, [$vmstate]);
5815 PVE
::Storage
::vdisk_free
($storecfg, $vmstate);
5816 delete $conf->@{qw(vmstate runningmachine)};
5817 PVE
::QemuConfig-
>write_config($vmid, $conf);
5823 die "lock changed unexpectedly\n"
5824 if !PVE
::QemuConfig-
>has_lock($conf, 'suspending');
5826 vm_qmp_command
($vmid, { execute
=> "quit" });
5827 $conf->{lock} = 'suspended';
5828 PVE
::QemuConfig-
>write_config($vmid, $conf);
5834 my ($vmid, $skiplock, $nocheck) = @_;
5836 PVE
::QemuConfig-
>lock_config($vmid, sub {
5837 my $vm_mon_cmd = $nocheck ? \
&vm_mon_cmd_nocheck
: \
&vm_mon_cmd
;
5838 my $res = $vm_mon_cmd->($vmid, 'query-status');
5839 my $resume_cmd = 'cont';
5841 if ($res->{status
} && $res->{status
} eq 'suspended') {
5842 $resume_cmd = 'system_wakeup';
5847 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5849 PVE
::QemuConfig-
>check_lock($conf)
5850 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5853 $vm_mon_cmd->($vmid, $resume_cmd);
5858 my ($vmid, $skiplock, $key) = @_;
5860 PVE
::QemuConfig-
>lock_config($vmid, sub {
5862 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5864 # there is no qmp command, so we use the human monitor command
5865 vm_human_monitor_command
($vmid, "sendkey $key");
5870 my ($storecfg, $vmid, $skiplock) = @_;
5872 PVE
::QemuConfig-
>lock_config($vmid, sub {
5874 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5876 if (!check_running
($vmid)) {
5877 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5879 die "VM $vmid is running - destroy failed\n";
5884 # vzdump restore implementaion
5886 sub tar_archive_read_firstfile
{
5887 my $archive = shift;
5889 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5891 # try to detect archive type first
5892 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5893 die "unable to open file '$archive'\n";
5894 my $firstfile = <$fh>;
5898 die "ERROR: archive contaions no data\n" if !$firstfile;
5904 sub tar_restore_cleanup
{
5905 my ($storecfg, $statfile) = @_;
5907 print STDERR
"starting cleanup\n";
5909 if (my $fd = IO
::File-
>new($statfile, "r")) {
5910 while (defined(my $line = <$fd>)) {
5911 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5914 if ($volid =~ m
|^/|) {
5915 unlink $volid || die 'unlink failed\n';
5917 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5919 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5921 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5923 print STDERR
"unable to parse line in statfile - $line";
5930 sub restore_archive
{
5931 my ($archive, $vmid, $user, $opts) = @_;
5933 my $format = $opts->{format
};
5936 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5937 $format = 'tar' if !$format;
5939 } elsif ($archive =~ m/\.tar$/) {
5940 $format = 'tar' if !$format;
5941 } elsif ($archive =~ m/.tar.lzo$/) {
5942 $format = 'tar' if !$format;
5944 } elsif ($archive =~ m/\.vma$/) {
5945 $format = 'vma' if !$format;
5946 } elsif ($archive =~ m/\.vma\.gz$/) {
5947 $format = 'vma' if !$format;
5949 } elsif ($archive =~ m/\.vma\.lzo$/) {
5950 $format = 'vma' if !$format;
5953 $format = 'vma' if !$format; # default
5956 # try to detect archive format
5957 if ($format eq 'tar') {
5958 return restore_tar_archive
($archive, $vmid, $user, $opts);
5960 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5964 sub restore_update_config_line
{
5965 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5967 return if $line =~ m/^\#qmdump\#/;
5968 return if $line =~ m/^\#vzdump\#/;
5969 return if $line =~ m/^lock:/;
5970 return if $line =~ m/^unused\d+:/;
5971 return if $line =~ m/^parent:/;
5973 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5974 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5975 # try to convert old 1.X settings
5976 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5977 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5978 my ($model, $macaddr) = split(/\=/, $devconfig);
5979 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5982 bridge
=> "vmbr$ind",
5983 macaddr
=> $macaddr,
5985 my $netstr = print_net
($net);
5987 print $outfd "net$cookie->{netcount}: $netstr\n";
5988 $cookie->{netcount
}++;
5990 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5991 my ($id, $netstr) = ($1, $2);
5992 my $net = parse_net
($netstr);
5993 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5994 $netstr = print_net
($net);
5995 print $outfd "$id: $netstr\n";
5996 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5999 my $di = parse_drive
($virtdev, $value);
6000 if (defined($di->{backup
}) && !$di->{backup
}) {
6001 print $outfd "#$line";
6002 } elsif ($map->{$virtdev}) {
6003 delete $di->{format
}; # format can change on restore
6004 $di->{file
} = $map->{$virtdev};
6005 $value = print_drive
($vmid, $di);
6006 print $outfd "$virtdev: $value\n";
6010 } elsif (($line =~ m/^vmgenid: (.*)/)) {
6012 if ($vmgenid ne '0') {
6013 # always generate a new vmgenid if there was a valid one setup
6014 $vmgenid = generate_uuid
();
6016 print $outfd "vmgenid: $vmgenid\n";
6017 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6018 my ($uuid, $uuid_str);
6019 UUID
::generate
($uuid);
6020 UUID
::unparse
($uuid, $uuid_str);
6021 my $smbios1 = parse_smbios1
($2);
6022 $smbios1->{uuid
} = $uuid_str;
6023 print $outfd $1.print_smbios1
($smbios1)."\n";
6030 my ($cfg, $vmid) = @_;
6032 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
6034 my $volid_hash = {};
6035 foreach my $storeid (keys %$info) {
6036 foreach my $item (@{$info->{$storeid}}) {
6037 next if !($item->{volid
} && $item->{size
});
6038 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
6039 $volid_hash->{$item->{volid
}} = $item;
6046 sub is_volume_in_use
{
6047 my ($storecfg, $conf, $skip_drive, $volid) = @_;
6049 my $path = PVE
::Storage
::path
($storecfg, $volid);
6051 my $scan_config = sub {
6052 my ($cref, $snapname) = @_;
6054 foreach my $key (keys %$cref) {
6055 my $value = $cref->{$key};
6056 if (is_valid_drivename
($key)) {
6057 next if $skip_drive && $key eq $skip_drive;
6058 my $drive = parse_drive
($key, $value);
6059 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
6060 return 1 if $volid eq $drive->{file
};
6061 if ($drive->{file
} =~ m!^/!) {
6062 return 1 if $drive->{file
} eq $path;
6064 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
6066 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
6068 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
6076 return 1 if &$scan_config($conf);
6080 foreach my $snapname (keys %{$conf->{snapshots
}}) {
6081 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
6087 sub update_disksize
{
6088 my ($vmid, $conf, $volid_hash) = @_;
6091 my $prefix = "VM $vmid:";
6093 # used and unused disks
6094 my $referenced = {};
6096 # Note: it is allowed to define multiple storages with same path (alias), so
6097 # we need to check both 'volid' and real 'path' (two different volid can point
6098 # to the same path).
6100 my $referencedpath = {};
6103 foreach my $opt (keys %$conf) {
6104 if (is_valid_drivename
($opt)) {
6105 my $drive = parse_drive
($opt, $conf->{$opt});
6106 my $volid = $drive->{file
};
6109 $referenced->{$volid} = 1;
6110 if ($volid_hash->{$volid} &&
6111 (my $path = $volid_hash->{$volid}->{path
})) {
6112 $referencedpath->{$path} = 1;
6115 next if drive_is_cdrom
($drive);
6116 next if !$volid_hash->{$volid};
6118 $drive->{size
} = $volid_hash->{$volid}->{size
};
6119 my $new = print_drive
($vmid, $drive);
6120 if ($new ne $conf->{$opt}) {
6122 $conf->{$opt} = $new;
6123 print "$prefix update disk '$opt' information.\n";
6128 # remove 'unusedX' entry if volume is used
6129 foreach my $opt (keys %$conf) {
6130 next if $opt !~ m/^unused\d+$/;
6131 my $volid = $conf->{$opt};
6132 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
6133 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
6134 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
6136 delete $conf->{$opt};
6139 $referenced->{$volid} = 1;
6140 $referencedpath->{$path} = 1 if $path;
6143 foreach my $volid (sort keys %$volid_hash) {
6144 next if $volid =~ m/vm-$vmid-state-/;
6145 next if $referenced->{$volid};
6146 my $path = $volid_hash->{$volid}->{path
};
6147 next if !$path; # just to be sure
6148 next if $referencedpath->{$path};
6150 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
6151 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
6152 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
6159 my ($vmid, $nolock, $dryrun) = @_;
6161 my $cfg = PVE
::Storage
::config
();
6163 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
6164 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
6165 foreach my $stor (keys %{$cfg->{ids
}}) {
6166 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
6169 print "rescan volumes...\n";
6170 my $volid_hash = scan_volids
($cfg, $vmid);
6172 my $updatefn = sub {
6175 my $conf = PVE
::QemuConfig-
>load_config($vmid);
6177 PVE
::QemuConfig-
>check_lock($conf);
6180 foreach my $volid (keys %$volid_hash) {
6181 my $info = $volid_hash->{$volid};
6182 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
6185 my $changes = update_disksize
($vmid, $conf, $vm_volids);
6187 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6190 if (defined($vmid)) {
6194 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6197 my $vmlist = config_list
();
6198 foreach my $vmid (keys %$vmlist) {
6202 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6208 sub restore_vma_archive
{
6209 my ($archive, $vmid, $user, $opts, $comp) = @_;
6211 my $readfrom = $archive;
6213 my $cfg = PVE
::Storage
::config
();
6215 my $bwlimit = $opts->{bwlimit
};
6217 my $dbg_cmdstring = '';
6218 my $add_pipe = sub {
6220 push @$commands, $cmd;
6221 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6222 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6227 if ($archive eq '-') {
6230 # If we use a backup from a PVE defined storage we also consider that
6231 # storage's rate limit:
6232 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6233 if (defined($volid)) {
6234 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6235 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6237 print STDERR
"applying read rate limit: $readlimit\n";
6238 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6239 $add_pipe->($cstream);
6246 if ($comp eq 'gzip') {
6247 $cmd = ['zcat', $readfrom];
6248 } elsif ($comp eq 'lzop') {
6249 $cmd = ['lzop', '-d', '-c', $readfrom];
6251 die "unknown compression method '$comp'\n";
6256 my $tmpdir = "/var/tmp/vzdumptmp$$";
6259 # disable interrupts (always do cleanups)
6263 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6265 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6266 POSIX
::mkfifo
($mapfifo, 0600);
6269 my $openfifo = sub {
6270 open($fifofh, '>', $mapfifo) || die $!;
6273 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6280 my $rpcenv = PVE
::RPCEnvironment
::get
();
6282 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6283 my $tmpfn = "$conffile.$$.tmp";
6285 # Note: $oldconf is undef if VM does not exists
6286 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6287 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6291 my $print_devmap = sub {
6292 my $virtdev_hash = {};
6294 my $cfgfn = "$tmpdir/qemu-server.conf";
6296 # we can read the config - that is already extracted
6297 my $fh = IO
::File-
>new($cfgfn, "r") ||
6298 "unable to read qemu-server.conf - $!\n";
6300 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6302 my $pve_firewall_dir = '/etc/pve/firewall';
6303 mkdir $pve_firewall_dir; # make sure the dir exists
6304 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6307 while (defined(my $line = <$fh>)) {
6308 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6309 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6310 die "archive does not contain data for drive '$virtdev'\n"
6311 if !$devinfo->{$devname};
6312 if (defined($opts->{storage
})) {
6313 $storeid = $opts->{storage
} || 'local';
6314 } elsif (!$storeid) {
6317 $format = 'raw' if !$format;
6318 $devinfo->{$devname}->{devname
} = $devname;
6319 $devinfo->{$devname}->{virtdev
} = $virtdev;
6320 $devinfo->{$devname}->{format
} = $format;
6321 $devinfo->{$devname}->{storeid
} = $storeid;
6323 # check permission on storage
6324 my $pool = $opts->{pool
}; # todo: do we need that?
6325 if ($user ne 'root@pam') {
6326 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6329 $storage_limits{$storeid} = $bwlimit;
6331 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6332 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6334 my $drive = parse_drive
($virtdev, $2);
6335 if (drive_is_cloudinit
($drive)) {
6336 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6337 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6338 my $format = qemu_img_format
($scfg, $volname); # has 'raw' fallback
6342 storeid
=> $opts->{storage
} // $storeid,
6343 size
=> PVE
::QemuServer
::Cloudinit
::CLOUDINIT_DISK_SIZE
,
6344 file
=> $drive->{file
}, # to make drive_is_cloudinit check possible
6345 name
=> "vm-$vmid-cloudinit",
6348 $virtdev_hash->{$virtdev} = $d;
6353 foreach my $key (keys %storage_limits) {
6354 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6356 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6357 $storage_limits{$key} = $limit * 1024;
6360 foreach my $devname (keys %$devinfo) {
6361 die "found no device mapping information for device '$devname'\n"
6362 if !$devinfo->{$devname}->{virtdev
};
6365 # create empty/temp config
6367 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6368 foreach_drive
($oldconf, sub {
6369 my ($ds, $drive) = @_;
6371 return if !$drive->{is_cloudinit
} && drive_is_cdrom
($drive);
6373 my $volid = $drive->{file
};
6374 return if !$volid || $volid =~ m
|^/|;
6376 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6377 return if !$path || !$owner || ($owner != $vmid);
6379 # Note: only delete disk we want to restore
6380 # other volumes will become unused
6381 if ($virtdev_hash->{$ds}) {
6382 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6389 # delete vmstate files, after the restore we have no snapshots anymore
6390 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6391 my $snap = $oldconf->{snapshots
}->{$snapname};
6392 if ($snap->{vmstate
}) {
6393 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6402 foreach my $virtdev (sort keys %$virtdev_hash) {
6403 my $d = $virtdev_hash->{$virtdev};
6404 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6405 my $storeid = $d->{storeid
};
6406 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6409 if (my $limit = $storage_limits{$storeid}) {
6410 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6413 # test if requested format is supported
6414 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6415 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6416 $d->{format
} = $defFormat if !$supported;
6419 if ($d->{is_cloudinit
}) {
6421 $name .= ".$d->{format}" if $d->{format
} ne 'raw';
6424 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid, $d->{format
}, $name, $alloc_size);
6425 print STDERR
"new volume ID is '$volid'\n";
6426 $d->{volid
} = $volid;
6428 PVE
::Storage
::activate_volumes
($cfg, [$volid]);
6430 my $write_zeros = 1;
6431 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6435 if (!$d->{is_cloudinit
}) {
6436 my $path = PVE
::Storage
::path
($cfg, $volid);
6438 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6440 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6442 $map->{$virtdev} = $volid;
6445 $fh->seek(0, 0) || die "seek failed - $!\n";
6447 my $outfd = new IO
::File
($tmpfn, "w") ||
6448 die "unable to write config for VM $vmid\n";
6450 my $cookie = { netcount
=> 0 };
6451 while (defined(my $line = <$fh>)) {
6452 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6465 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6466 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6468 $oldtimeout = alarm($timeout);
6475 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6476 my ($dev_id, $size, $devname) = ($1, $2, $3);
6477 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6478 } elsif ($line =~ m/^CTIME: /) {
6479 # we correctly received the vma config, so we can disable
6480 # the timeout now for disk allocation (set to 10 minutes, so
6481 # that we always timeout if something goes wrong)
6484 print $fifofh "done\n";
6485 my $tmp = $oldtimeout || 0;
6486 $oldtimeout = undef;
6492 print "restore vma archive: $dbg_cmdstring\n";
6493 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6497 alarm($oldtimeout) if $oldtimeout;
6500 foreach my $devname (keys %$devinfo) {
6501 my $volid = $devinfo->{$devname}->{volid
};
6502 push @$vollist, $volid if $volid;
6505 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6513 foreach my $devname (keys %$devinfo) {
6514 my $volid = $devinfo->{$devname}->{volid
};
6517 if ($volid =~ m
|^/|) {
6518 unlink $volid || die 'unlink failed\n';
6520 PVE
::Storage
::vdisk_free
($cfg, $volid);
6522 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6524 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6531 rename($tmpfn, $conffile) ||
6532 die "unable to commit configuration file '$conffile'\n";
6534 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6536 eval { rescan
($vmid, 1); };
6540 sub restore_tar_archive
{
6541 my ($archive, $vmid, $user, $opts) = @_;
6543 if ($archive ne '-') {
6544 my $firstfile = tar_archive_read_firstfile
($archive);
6545 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6546 if $firstfile ne 'qemu-server.conf';
6549 my $storecfg = PVE
::Storage
::config
();
6551 # destroy existing data - keep empty config
6552 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6553 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6555 my $tocmd = "/usr/lib/qemu-server/qmextract";
6557 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6558 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6559 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6560 $tocmd .= ' --info' if $opts->{info
};
6562 # tar option "xf" does not autodetect compression when read from STDIN,
6563 # so we pipe to zcat
6564 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6565 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6567 my $tmpdir = "/var/tmp/vzdumptmp$$";
6570 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6571 local $ENV{VZDUMP_VMID
} = $vmid;
6572 local $ENV{VZDUMP_USER
} = $user;
6574 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6575 my $tmpfn = "$conffile.$$.tmp";
6577 # disable interrupts (always do cleanups)
6581 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6589 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6591 if ($archive eq '-') {
6592 print "extracting archive from STDIN\n";
6593 run_command
($cmd, input
=> "<&STDIN");
6595 print "extracting archive '$archive'\n";
6599 return if $opts->{info
};
6603 my $statfile = "$tmpdir/qmrestore.stat";
6604 if (my $fd = IO
::File-
>new($statfile, "r")) {
6605 while (defined (my $line = <$fd>)) {
6606 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6607 $map->{$1} = $2 if $1;
6609 print STDERR
"unable to parse line in statfile - $line\n";
6615 my $confsrc = "$tmpdir/qemu-server.conf";
6617 my $srcfd = new IO
::File
($confsrc, "r") ||
6618 die "unable to open file '$confsrc'\n";
6620 my $outfd = new IO
::File
($tmpfn, "w") ||
6621 die "unable to write config for VM $vmid\n";
6623 my $cookie = { netcount
=> 0 };
6624 while (defined (my $line = <$srcfd>)) {
6625 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6637 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6644 rename $tmpfn, $conffile ||
6645 die "unable to commit configuration file '$conffile'\n";
6647 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6649 eval { rescan
($vmid, 1); };
6653 sub foreach_storage_used_by_vm
{
6654 my ($conf, $func) = @_;
6658 foreach_drive
($conf, sub {
6659 my ($ds, $drive) = @_;
6660 return if drive_is_cdrom
($drive);
6662 my $volid = $drive->{file
};
6664 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6665 $sidhash->{$sid} = $sid if $sid;
6668 foreach my $sid (sort keys %$sidhash) {
6673 sub do_snapshots_with_qemu
{
6674 my ($storecfg, $volid) = @_;
6676 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6677 my $scfg = $storecfg->{ids
}->{$storage_name};
6679 if ($qemu_snap_storage->{$scfg->{type
}} && !$scfg->{krbd
}){
6683 if ($volid =~ m/\.(qcow2|qed)$/){
6690 sub qga_check_running
{
6691 my ($vmid, $nowarn) = @_;
6693 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6695 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6701 sub template_create
{
6702 my ($vmid, $conf, $disk) = @_;
6704 my $storecfg = PVE
::Storage
::config
();
6706 foreach_drive
($conf, sub {
6707 my ($ds, $drive) = @_;
6709 return if drive_is_cdrom
($drive);
6710 return if $disk && $ds ne $disk;
6712 my $volid = $drive->{file
};
6713 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6715 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6716 $drive->{file
} = $voliddst;
6717 $conf->{$ds} = print_drive
($vmid, $drive);
6718 PVE
::QemuConfig-
>write_config($vmid, $conf);
6722 sub convert_iscsi_path
{
6725 if ($path =~ m
|^iscsi
://([^/]+)/([^/]+)/(.+)$|) {
6730 my $initiator_name = get_initiator_name
();
6732 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6733 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6736 die "cannot convert iscsi path '$path', unkown format\n";
6739 sub qemu_img_convert
{
6740 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6742 my $storecfg = PVE
::Storage
::config
();
6743 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6744 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6746 if ($src_storeid && $dst_storeid) {
6748 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6750 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6751 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6753 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6754 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6756 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6757 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6759 my $src_is_iscsi = ($src_path =~ m
|^iscsi
://|);
6760 my $dst_is_iscsi = ($dst_path =~ m
|^iscsi
://|);
6763 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6764 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6765 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6766 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6768 if ($src_is_iscsi) {
6769 push @$cmd, '--image-opts';
6770 $src_path = convert_iscsi_path
($src_path);
6772 push @$cmd, '-f', $src_format;
6775 if ($dst_is_iscsi) {
6776 push @$cmd, '--target-image-opts';
6777 $dst_path = convert_iscsi_path
($dst_path);
6779 push @$cmd, '-O', $dst_format;
6782 push @$cmd, $src_path;
6784 if (!$dst_is_iscsi && $is_zero_initialized) {
6785 push @$cmd, "zeroinit:$dst_path";
6787 push @$cmd, $dst_path;
6792 if($line =~ m/\((\S+)\/100\
%\)/){
6794 my $transferred = int($size * $percent / 100);
6795 my $remaining = $size - $transferred;
6797 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6802 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6804 die "copy failed: $err" if $err;
6808 sub qemu_img_format
{
6809 my ($scfg, $volname) = @_;
6811 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6818 sub qemu_drive_mirror
{
6819 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
6821 $jobs = {} if !$jobs;
6825 $jobs->{"drive-$drive"} = {};
6827 if ($dst_volid =~ /^nbd:/) {
6828 $qemu_target = $dst_volid;
6831 my $storecfg = PVE
::Storage
::config
();
6832 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6834 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6836 $format = qemu_img_format
($dst_scfg, $dst_volname);
6838 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6840 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6843 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6844 $opts->{format
} = $format if $format;
6846 if (defined($bwlimit)) {
6847 $opts->{speed
} = $bwlimit * 1024;
6848 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
6850 print "drive mirror is starting for drive-$drive\n";
6853 # if a job already runs for this device we get an error, catch it for cleanup
6854 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); };
6856 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6858 die "mirroring error: $err\n";
6861 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6864 sub qemu_drive_mirror_monitor
{
6865 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6868 my $err_complete = 0;
6871 die "storage migration timed out\n" if $err_complete > 300;
6873 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6875 my $running_mirror_jobs = {};
6876 foreach my $stat (@$stats) {
6877 next if $stat->{type
} ne 'mirror';
6878 $running_mirror_jobs->{$stat->{device
}} = $stat;
6881 my $readycounter = 0;
6883 foreach my $job (keys %$jobs) {
6885 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6886 print "$job : finished\n";
6887 delete $jobs->{$job};
6891 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6893 my $busy = $running_mirror_jobs->{$job}->{busy
};
6894 my $ready = $running_mirror_jobs->{$job}->{ready
};
6895 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6896 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6897 my $remaining = $total - $transferred;
6898 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6900 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6903 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6906 last if scalar(keys %$jobs) == 0;
6908 if ($readycounter == scalar(keys %$jobs)) {
6909 print "all mirroring jobs are ready \n";
6910 last if $skipcomplete; #do the complete later
6912 if ($vmiddst && $vmiddst != $vmid) {
6913 my $agent_running = $qga && qga_check_running
($vmid);
6914 if ($agent_running) {
6915 print "freeze filesystem\n";
6916 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6918 print "suspend vm\n";
6919 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6922 # if we clone a disk for a new target vm, we don't switch the disk
6923 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6925 if ($agent_running) {
6926 print "unfreeze filesystem\n";
6927 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6929 print "resume vm\n";
6930 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6936 foreach my $job (keys %$jobs) {
6937 # try to switch the disk if source and destination are on the same guest
6938 print "$job: Completing block job...\n";
6940 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6941 if ($@ =~ m/cannot be completed/) {
6942 print "$job: Block job cannot be completed, try again.\n";
6945 print "$job: Completed successfully.\n";
6946 $jobs->{$job}->{complete
} = 1;
6957 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6958 die "mirroring error: $err";
6963 sub qemu_blockjobs_cancel
{
6964 my ($vmid, $jobs) = @_;
6966 foreach my $job (keys %$jobs) {
6967 print "$job: Cancelling block job\n";
6968 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6969 $jobs->{$job}->{cancel
} = 1;
6973 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6975 my $running_jobs = {};
6976 foreach my $stat (@$stats) {
6977 $running_jobs->{$stat->{device
}} = $stat;
6980 foreach my $job (keys %$jobs) {
6982 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6983 print "$job: Done.\n";
6984 delete $jobs->{$job};
6988 last if scalar(keys %$jobs) == 0;
6995 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6996 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
7001 print "create linked clone of drive $drivename ($drive->{file})\n";
7002 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
7003 push @$newvollist, $newvolid;
7006 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
7007 $storeid = $storage if $storage;
7009 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
7010 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
7012 print "create full clone of drive $drivename ($drive->{file})\n";
7014 if (drive_is_cloudinit
($drive)) {
7015 $name = "vm-$newvmid-cloudinit";
7017 # we only get here if it's supported by QEMU_FORMAT_RE, so just accept
7018 if ($dst_format ne 'raw') {
7019 $name .= ".$dst_format";
7022 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
7023 push @$newvollist, $newvolid;
7025 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
7027 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
7028 if (!$running || $snapname) {
7029 # TODO: handle bwlimits
7030 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
7033 my $kvmver = get_running_qemu_version
($vmid);
7034 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
7035 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7036 if $drive->{iothread
};
7039 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga, $bwlimit);
7043 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
7046 $disk->{format
} = undef;
7047 $disk->{file
} = $newvolid;
7048 $disk->{size
} = $size;
7053 # this only works if VM is running
7054 sub get_current_qemu_machine
{
7057 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
7058 my $res = vm_qmp_command
($vmid, $cmd);
7060 my ($current, $default);
7061 foreach my $e (@$res) {
7062 $default = $e->{name
} if $e->{'is-default'};
7063 $current = $e->{name
} if $e->{'is-current'};
7066 # fallback to the default machine if current is not supported by qemu
7067 return $current || $default || 'pc';
7070 sub get_running_qemu_version
{
7072 my $cmd = { execute
=> 'query-version', arguments
=> {} };
7073 my $res = vm_qmp_command
($vmid, $cmd);
7074 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7077 sub qemu_machine_feature_enabled
{
7078 my ($machine, $kvmver, $version_major, $version_minor) = @_;
7083 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
7085 $current_major = $3;
7086 $current_minor = $4;
7088 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
7090 $current_major = $1;
7091 $current_minor = $2;
7094 return 1 if $current_major > $version_major ||
7095 ($current_major == $version_major &&
7096 $current_minor >= $version_minor);
7099 sub qemu_machine_pxe
{
7100 my ($vmid, $conf, $machine) = @_;
7102 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
7104 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
7111 sub qemu_use_old_bios_files
{
7112 my ($machine_type) = @_;
7114 return if !$machine_type;
7116 my $use_old_bios_files = undef;
7118 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7120 $use_old_bios_files = 1;
7122 my $kvmver = kvm_user_version
();
7123 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7124 # load new efi bios files on migration. So this hack is required to allow
7125 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7126 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
7127 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
7130 return ($use_old_bios_files, $machine_type);
7133 sub create_efidisk
($$$$$) {
7134 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
7136 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
7137 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
7139 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
7140 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7141 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
7143 my $path = PVE
::Storage
::path
($storecfg, $volid);
7145 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
7147 die "Copying EFI vars image failed: $@" if $@;
7149 return ($volid, $vars_size);
7152 sub vm_iothreads_list
{
7155 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
7158 foreach my $iothread (@$res) {
7159 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
7166 my ($conf, $drive) = @_;
7170 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
7172 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
7178 my $controller = int($drive->{index} / $maxdev);
7179 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
7181 return ($maxdev, $controller, $controller_prefix);
7184 sub add_hyperv_enlightenments
{
7185 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
7187 return if $winversion < 6;
7188 return if $bios && $bios eq 'ovmf' && $winversion < 8;
7190 if ($gpu_passthrough || defined($hv_vendor_id)) {
7191 $hv_vendor_id //= 'proxmox';
7192 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
7195 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
7196 push @$cpuFlags , 'hv_spinlocks=0x1fff';
7197 push @$cpuFlags , 'hv_vapic';
7198 push @$cpuFlags , 'hv_time';
7200 push @$cpuFlags , 'hv_spinlocks=0xffff';
7203 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
7204 push @$cpuFlags , 'hv_reset';
7205 push @$cpuFlags , 'hv_vpindex';
7206 push @$cpuFlags , 'hv_runtime';
7209 if ($winversion >= 7) {
7210 push @$cpuFlags , 'hv_relaxed';
7212 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
7213 push @$cpuFlags , 'hv_synic';
7214 push @$cpuFlags , 'hv_stimer';
7217 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 3, 1)) {
7218 push @$cpuFlags , 'hv_tlbflush';
7219 push @$cpuFlags , 'hv_ipi';
7220 # FIXME: AMD does not supports this currently, only add with special flag??
7221 #push @$cpuFlags , 'hv_evmcs';
7226 sub windows_version
{
7229 return 0 if !$ostype;
7233 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7235 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7237 } elsif ($ostype =~ m/^win(\d+)$/) {
7244 sub resolve_dst_disk_format
{
7245 my ($storecfg, $storeid, $src_volname, $format) = @_;
7246 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
7249 # if no target format is specified, use the source disk format as hint
7251 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
7252 $format = qemu_img_format
($scfg, $src_volname);
7258 # test if requested format is supported - else use default
7259 my $supported = grep { $_ eq $format } @$validFormats;
7260 $format = $defFormat if !$supported;
7264 sub resolve_first_disk
{
7266 my @disks = PVE
::QemuServer
::valid_drive_names
();
7268 foreach my $ds (reverse @disks) {
7269 next if !$conf->{$ds};
7270 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
7271 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
7278 my ($uuid, $uuid_str);
7279 UUID
::generate
($uuid);
7280 UUID
::unparse
($uuid, $uuid_str);
7284 sub generate_smbios1_uuid
{
7285 return "uuid=".generate_uuid
();
7291 vm_mon_cmd
($vmid, 'nbd-server-stop');
7294 # bash completion helper
7296 sub complete_backup_archives
{
7297 my ($cmdname, $pname, $cvalue) = @_;
7299 my $cfg = PVE
::Storage
::config
();
7303 if ($cvalue =~ m/^([^:]+):/) {
7307 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7310 foreach my $id (keys %$data) {
7311 foreach my $item (@{$data->{$id}}) {
7312 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7313 push @$res, $item->{volid
} if defined($item->{volid
});
7320 my $complete_vmid_full = sub {
7323 my $idlist = vmstatus
();
7327 foreach my $id (keys %$idlist) {
7328 my $d = $idlist->{$id};
7329 if (defined($running)) {
7330 next if $d->{template
};
7331 next if $running && $d->{status
} ne 'running';
7332 next if !$running && $d->{status
} eq 'running';
7341 return &$complete_vmid_full();
7344 sub complete_vmid_stopped
{
7345 return &$complete_vmid_full(0);
7348 sub complete_vmid_running
{
7349 return &$complete_vmid_full(1);
7352 sub complete_storage
{
7354 my $cfg = PVE
::Storage
::config
();
7355 my $ids = $cfg->{ids
};
7358 foreach my $sid (keys %$ids) {
7359 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7360 next if !$ids->{$sid}->{content
}->{images
};