1 package PVE
::QemuServer
;
22 use Storable
qw(dclone);
23 use PVE
::Exception
qw(raise raise_param_exc);
25 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
26 use PVE
::JSONSchema
qw(get_standard_option);
27 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
32 use PVE
::RPCEnvironment
;
33 use PVE
::GuestHelpers
;
34 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
35 use PVE
::QemuServer
::Memory
;
36 use PVE
::QemuServer
::USB
qw(parse_usb_device);
37 use PVE
::QemuServer
::Cloudinit
;
40 use Time
::HiRes
qw(gettimeofday);
41 use File
::Copy
qw(copy);
44 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
47 "$EDK2_FW_BASE/OVMF_CODE.fd",
48 "$EDK2_FW_BASE/OVMF_VARS.fd"
51 "$EDK2_FW_BASE/AAVMF_CODE.fd",
52 "$EDK2_FW_BASE/AAVMF_VARS.fd"
56 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
58 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
60 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
62 # Note about locking: we use flock on the config file protect
63 # against concurent actions.
64 # Aditionaly, we have a 'lock' setting in the config file. This
65 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
66 # allowed when such lock is set. But you can ignore this kind of
67 # lock with the --skiplock flag.
69 cfs_register_file
('/qemu-server/',
73 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
74 description
=> "Some command save/restore state from this location.",
80 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
81 description
=> "The name of the snapshot.",
82 type
=> 'string', format
=> 'pve-configid',
86 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
88 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
89 description
=> "The drive's backing file's data format.",
93 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
94 description
=> "Specifies the Qemu machine type.",
96 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
101 #no warnings 'redefine';
104 my ($controller, $vmid, $option, $value) = @_;
106 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
107 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
111 my $nodename = PVE
::INotify
::nodename
();
113 mkdir "/etc/pve/nodes/$nodename";
114 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
117 my $var_run_tmpdir = "/var/run/qemu-server";
118 mkdir $var_run_tmpdir;
120 my $lock_dir = "/var/lock/qemu-server";
123 my $cpu_vendor_list = {
125 486 => 'GenuineIntel',
126 pentium
=> 'GenuineIntel',
127 pentium2
=> 'GenuineIntel',
128 pentium3
=> 'GenuineIntel',
129 coreduo
=> 'GenuineIntel',
130 core2duo
=> 'GenuineIntel',
131 Conroe
=> 'GenuineIntel',
132 Penryn
=> 'GenuineIntel',
133 Nehalem
=> 'GenuineIntel',
134 'Nehalem-IBRS' => 'GenuineIntel',
135 Westmere
=> 'GenuineIntel',
136 'Westmere-IBRS' => 'GenuineIntel',
137 SandyBridge
=> 'GenuineIntel',
138 'SandyBridge-IBRS' => 'GenuineIntel',
139 IvyBridge
=> 'GenuineIntel',
140 'IvyBridge-IBRS' => 'GenuineIntel',
141 Haswell
=> 'GenuineIntel',
142 'Haswell-IBRS' => 'GenuineIntel',
143 'Haswell-noTSX' => 'GenuineIntel',
144 'Haswell-noTSX-IBRS' => 'GenuineIntel',
145 Broadwell
=> 'GenuineIntel',
146 'Broadwell-IBRS' => 'GenuineIntel',
147 'Broadwell-noTSX' => 'GenuineIntel',
148 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
149 'Skylake-Client' => 'GenuineIntel',
150 'Skylake-Client-IBRS' => 'GenuineIntel',
151 'Skylake-Server' => 'GenuineIntel',
152 'Skylake-Server-IBRS' => 'GenuineIntel',
155 athlon
=> 'AuthenticAMD',
156 phenom
=> 'AuthenticAMD',
157 Opteron_G1
=> 'AuthenticAMD',
158 Opteron_G2
=> 'AuthenticAMD',
159 Opteron_G3
=> 'AuthenticAMD',
160 Opteron_G4
=> 'AuthenticAMD',
161 Opteron_G5
=> 'AuthenticAMD',
162 EPYC
=> 'AuthenticAMD',
163 'EPYC-IBPB' => 'AuthenticAMD',
165 # generic types, use vendor from host node
174 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
178 description
=> "Emulated CPU type.",
180 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
185 description
=> "Do not identify as a KVM virtual machine.",
192 pattern
=> qr/[a-zA-Z0-9]{1,12}/,
193 format_description
=> 'vendor-id',
194 description
=> 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
198 description
=> "List of additional CPU flags separated by ';'."
199 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
200 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
201 format_description
=> '+FLAG[;-FLAG...]',
203 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
212 enum
=> [qw(i6300esb ib700)],
213 description
=> "Watchdog type to emulate.",
214 default => 'i6300esb',
219 enum
=> [qw(reset shutdown poweroff pause debug none)],
220 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
224 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
228 description
=> "Enable/disable Qemu GuestAgent.",
233 fstrim_cloned_disks
=> {
234 description
=> "Run fstrim after cloning/moving a disk.",
243 description
=> "Select the VGA type.",
248 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
251 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
263 description
=> "The size of the file in MB.",
267 pattern
=> '[a-zA-Z0-9\-]+',
269 format_description
=> 'string',
270 description
=> "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
278 description
=> "Specifies whether a VM will be started during system bootup.",
284 description
=> "Automatic restart after crash (currently ignored).",
289 type
=> 'string', format
=> 'pve-hotplug-features',
290 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'.",
291 default => 'network,disk,usb',
296 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
302 description
=> "Lock/unlock the VM.",
303 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete)],
308 description
=> "Limit of CPU usage.",
309 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.",
317 description
=> "CPU weight for a VM.",
318 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.",
326 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
333 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
339 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.",
347 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
348 "It should not be necessary to set it.",
349 enum
=> PVE
::Tools
::kvmkeymaplist
(),
354 type
=> 'string', format
=> 'dns-name',
355 description
=> "Set a name for the VM. Only used on the configuration web interface.",
360 description
=> "SCSI controller model",
361 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
367 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
372 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
373 description
=> "Specify guest operating system.",
374 verbose_description
=> <<EODESC,
375 Specify guest operating system. This is used to enable special
376 optimization/features for specific operating systems:
379 other;; unspecified OS
380 wxp;; Microsoft Windows XP
381 w2k;; Microsoft Windows 2000
382 w2k3;; Microsoft Windows 2003
383 w2k8;; Microsoft Windows 2008
384 wvista;; Microsoft Windows Vista
385 win7;; Microsoft Windows 7
386 win8;; Microsoft Windows 8/2012/2012r2
387 win10;; Microsoft Windows 10/2016
388 l24;; Linux 2.4 Kernel
389 l26;; Linux 2.6/3.X Kernel
390 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
396 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
397 pattern
=> '[acdn]{1,4}',
402 type
=> 'string', format
=> 'pve-qm-bootdisk',
403 description
=> "Enable booting from specified disk.",
404 pattern
=> '(ide|sata|scsi|virtio)\d+',
409 description
=> "The number of CPUs. Please use option -sockets instead.",
416 description
=> "The number of CPU sockets.",
423 description
=> "The number of cores per socket.",
430 description
=> "Enable/disable NUMA.",
436 description
=> "Enable/disable hugepages memory.",
437 enum
=> [qw(any 2 1024)],
442 description
=> "Number of hotplugged vcpus.",
449 description
=> "Enable/disable ACPI.",
454 description
=> "Enable/disable Qemu GuestAgent and its properties.",
456 format
=> $agent_fmt,
461 description
=> "Enable/disable KVM hardware virtualization.",
467 description
=> "Enable/disable time drift fix.",
473 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
478 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
482 type
=> 'string', format
=> $vga_fmt,
483 description
=> "Configure the VGA hardware.",
484 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
485 "high resolution modes (>= 1280x1024x16) you may need to increase " .
486 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
487 "is 'std' for all OS types besides some Windows versions (XP and " .
488 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
489 "display server. For win* OS you can select how many independent " .
490 "displays you want, Linux guests can add displays them self.\n".
491 "You can also run without any graphic card, using a serial device as terminal.",
495 type
=> 'string', format
=> 'pve-qm-watchdog',
496 description
=> "Create a virtual hardware watchdog device.",
497 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
498 " (by a guest action), the watchdog must be periodically polled " .
499 "by an agent inside the guest or else the watchdog will reset " .
500 "the guest (or execute the respective action specified)",
505 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
506 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'.",
507 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
510 startup
=> get_standard_option
('pve-startup-order'),
514 description
=> "Enable/disable Template.",
520 description
=> "Arbitrary arguments passed to kvm.",
521 verbose_description
=> <<EODESCR,
522 Arbitrary arguments passed to kvm, for example:
524 args: -no-reboot -no-hpet
526 NOTE: this option is for experts only.
533 description
=> "Enable/disable the USB tablet device.",
534 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
535 "usually needed to allow absolute mouse positioning with VNC. " .
536 "Else the mouse runs out of sync with normal VNC clients. " .
537 "If you're running lots of console-only guests on one host, " .
538 "you may consider disabling this to save some context switches. " .
539 "This is turned off by default if you use spice (-vga=qxl).",
544 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
548 migrate_downtime
=> {
551 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
557 type
=> 'string', format
=> 'pve-qm-ide',
558 typetext
=> '<volume>',
559 description
=> "This is an alias for option -ide2",
563 description
=> "Emulated CPU type.",
567 parent
=> get_standard_option
('pve-snapshot-name', {
569 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
573 description
=> "Timestamp for snapshots.",
579 type
=> 'string', format
=> 'pve-volume-id',
580 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
582 vmstatestorage
=> get_standard_option
('pve-storage-id', {
583 description
=> "Default storage for VM state volumes/files.",
586 runningmachine
=> get_standard_option
('pve-qemu-machine', {
587 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
589 machine
=> get_standard_option
('pve-qemu-machine'),
591 description
=> "Virtual processor architecture. Defaults to the host.",
594 enum
=> [qw(x86_64 aarch64)],
597 description
=> "Specify SMBIOS type 1 fields.",
598 type
=> 'string', format
=> 'pve-qm-smbios1',
605 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
611 enum
=> [ qw(seabios ovmf) ],
612 description
=> "Select BIOS implementation.",
613 default => 'seabios',
617 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
618 format_description
=> 'UUID',
619 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
620 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
621 " 128-bit integer value identifier to the guest OS. This allows to".
622 " notify the guest operating system when the virtual machine is".
623 " executed with a different configuration (e.g. snapshot execution".
624 " or creation from a template). The guest operating system notices".
625 " the change, and is then able to react as appropriate by marking".
626 " its copies of distributed databases as dirty, re-initializing its".
627 " random number generator, etc.\n".
628 "Note that auto-creation only works when done throug API/CLI create".
629 " or update methods, but not when manually editing the config file.",
630 default => "1 (autogenerated)",
635 format
=> 'pve-volume-id',
637 description
=> "Script that will be executed during various steps in the vms lifetime.",
641 format
=> $ivshmem_fmt,
642 description
=> "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
647 my $confdesc_cloudinit = {
651 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.',
652 enum
=> ['configdrive2', 'nocloud'],
657 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
662 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.',
667 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.",
671 type
=> 'string', format
=> 'address-list',
672 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.",
677 format
=> 'urlencoded',
678 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
682 # what about other qemu settings ?
684 #machine => 'string',
697 ##soundhw => 'string',
699 while (my ($k, $v) = each %$confdesc) {
700 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
703 my $MAX_IDE_DISKS = 4;
704 my $MAX_SCSI_DISKS = 14;
705 my $MAX_VIRTIO_DISKS = 16;
706 my $MAX_SATA_DISKS = 6;
707 my $MAX_USB_DEVICES = 5;
709 my $MAX_UNUSED_DISKS = 256;
710 my $MAX_HOSTPCI_DEVICES = 4;
711 my $MAX_SERIAL_PORTS = 4;
712 my $MAX_PARALLEL_PORTS = 3;
718 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
719 description
=> "CPUs accessing this NUMA node.",
720 format_description
=> "id[-id];...",
724 description
=> "Amount of memory this NUMA node provides.",
729 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
730 description
=> "Host NUMA nodes to use.",
731 format_description
=> "id[-id];...",
736 enum
=> [qw(preferred bind interleave)],
737 description
=> "NUMA allocation policy.",
741 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
744 type
=> 'string', format
=> $numa_fmt,
745 description
=> "NUMA topology.",
747 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
749 for (my $i = 0; $i < $MAX_NUMA; $i++) {
750 $confdesc->{"numa$i"} = $numadesc;
753 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
754 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
755 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
756 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
758 my $net_fmt_bridge_descr = <<__EOD__;
759 Bridge to attach the network device to. The Proxmox VE standard bridge
762 If you do not specify a bridge, we create a kvm user (NATed) network
763 device, which provides DHCP and DNS services. The following addresses
770 The DHCP server assign addresses to the guest starting from 10.0.2.15.
776 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
777 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
778 format_description
=> "XX:XX:XX:XX:XX:XX",
783 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'.",
784 enum
=> $nic_model_list,
787 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
790 description
=> $net_fmt_bridge_descr,
791 format_description
=> 'bridge',
796 minimum
=> 0, maximum
=> 16,
797 description
=> 'Number of packet queues to be used on the device.',
803 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
808 minimum
=> 1, maximum
=> 4094,
809 description
=> 'VLAN tag to apply to packets on this interface.',
814 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
815 description
=> 'VLAN trunks to pass through this interface.',
816 format_description
=> 'vlanid[;vlanid...]',
821 description
=> 'Whether this interface should be protected by the firewall.',
826 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
833 type
=> 'string', format
=> $net_fmt,
834 description
=> "Specify network devices.",
837 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
842 format
=> 'pve-ipv4-config',
843 format_description
=> 'IPv4Format/CIDR',
844 description
=> 'IPv4 address in CIDR format.',
851 format_description
=> 'GatewayIPv4',
852 description
=> 'Default gateway for IPv4 traffic.',
858 format
=> 'pve-ipv6-config',
859 format_description
=> 'IPv6Format/CIDR',
860 description
=> 'IPv6 address in CIDR format.',
867 format_description
=> 'GatewayIPv6',
868 description
=> 'Default gateway for IPv6 traffic.',
873 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
876 type
=> 'string', format
=> 'pve-qm-ipconfig',
877 description
=> <<'EODESCR',
878 cloud-init: Specify IP addresses and gateways for the corresponding interface.
880 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
882 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
883 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
885 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
888 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
890 for (my $i = 0; $i < $MAX_NETS; $i++) {
891 $confdesc->{"net$i"} = $netdesc;
892 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
895 foreach my $key (keys %$confdesc_cloudinit) {
896 $confdesc->{$key} = $confdesc_cloudinit->{$key};
899 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
900 sub verify_volume_id_or_qm_path
{
901 my ($volid, $noerr) = @_;
903 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
907 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
908 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
910 return undef if $noerr;
918 my %drivedesc_base = (
919 volume
=> { alias
=> 'file' },
922 format
=> 'pve-volume-id-or-qm-path',
924 format_description
=> 'volume',
925 description
=> "The drive's backing volume.",
929 enum
=> [qw(cdrom disk)],
930 description
=> "The drive's media type.",
936 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
941 description
=> "Force the drive's physical geometry to have a specific head count.",
946 description
=> "Force the drive's physical geometry to have a specific sector count.",
951 enum
=> [qw(none lba auto)],
952 description
=> "Force disk geometry bios translation mode.",
957 description
=> "Controls qemu's snapshot mode feature."
958 . " If activated, changes made to the disk are temporary and will"
959 . " be discarded when the VM is shutdown.",
964 enum
=> [qw(none writethrough writeback unsafe directsync)],
965 description
=> "The drive's cache mode",
968 format
=> get_standard_option
('pve-qm-image-format'),
971 format
=> 'disk-size',
972 format_description
=> 'DiskSize',
973 description
=> "Disk size. This is purely informational and has no effect.",
978 description
=> "Whether the drive should be included when making backups.",
983 description
=> 'Whether the drive should considered for replication jobs.',
989 enum
=> [qw(ignore report stop)],
990 description
=> 'Read error action.',
995 enum
=> [qw(enospc ignore report stop)],
996 description
=> 'Write error action.',
1001 enum
=> [qw(native threads)],
1002 description
=> 'AIO type to use.',
1007 enum
=> [qw(ignore on)],
1008 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
1013 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
1018 format
=> 'urlencoded',
1019 format_description
=> 'serial',
1020 maxLength
=> 20*3, # *3 since it's %xx url enoded
1021 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
1026 description
=> 'Mark this locally-managed volume as available on all nodes',
1027 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!",
1033 my %iothread_fmt = ( iothread
=> {
1035 description
=> "Whether to use iothreads for this drive",
1042 format
=> 'urlencoded',
1043 format_description
=> 'model',
1044 maxLength
=> 40*3, # *3 since it's %xx url enoded
1045 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1053 description
=> "Number of queues.",
1059 my %scsiblock_fmt = (
1062 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",
1071 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1079 pattern
=> qr/^(0x)[0-9a-fA-F]{16}/,
1080 format_description
=> 'wwn',
1081 description
=> "The drive's worldwide name, encoded as 16 bytes hex string, prefixed by '0x'.",
1086 my $add_throttle_desc = sub {
1087 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1090 format_description
=> $unit,
1091 description
=> "Maximum $what in $longunit.",
1094 $d->{minimum
} = $minimum if defined($minimum);
1095 $drivedesc_base{$key} = $d;
1097 # throughput: (leaky bucket)
1098 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1099 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1100 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1101 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1102 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1103 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1104 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1105 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1106 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1108 # pools: (pool of IO before throttling starts taking effect)
1109 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1110 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1111 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1112 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1113 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1114 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1117 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1118 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1119 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1120 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1121 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1122 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1125 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1126 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1127 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1128 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1136 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1140 type
=> 'string', format
=> $ide_fmt,
1141 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1143 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1155 type
=> 'string', format
=> $scsi_fmt,
1156 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1158 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1167 type
=> 'string', format
=> $sata_fmt,
1168 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1170 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1178 type
=> 'string', format
=> $virtio_fmt,
1179 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1181 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1183 my $alldrive_fmt = {
1194 volume
=> { alias
=> 'file' },
1197 format
=> 'pve-volume-id-or-qm-path',
1199 format_description
=> 'volume',
1200 description
=> "The drive's backing volume.",
1202 format
=> get_standard_option
('pve-qm-image-format'),
1205 format
=> 'disk-size',
1206 format_description
=> 'DiskSize',
1207 description
=> "Disk size. This is purely informational and has no effect.",
1212 my $efidisk_desc = {
1214 type
=> 'string', format
=> $efidisk_fmt,
1215 description
=> "Configure a Disk for storing EFI vars",
1218 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1223 type
=> 'string', format
=> 'pve-qm-usb-device',
1224 format_description
=> 'HOSTUSBDEVICE|spice',
1225 description
=> <<EODESCR,
1226 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1228 'bus-port(.port)*' (decimal numbers) or
1229 'vendor_id:product_id' (hexadeciaml numbers) or
1232 You can use the 'lsusb -t' command to list existing usb devices.
1234 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1236 The value 'spice' can be used to add a usb redirection devices for spice.
1242 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).",
1249 type
=> 'string', format
=> $usb_fmt,
1250 description
=> "Configure an USB device (n is 0 to 4).",
1252 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1254 my $PCIRE = qr/[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1259 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1260 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1261 description
=> <<EODESCR,
1262 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1263 of PCI virtual functions of the host. HOSTPCIID syntax is:
1265 'bus:dev.func' (hexadecimal numbers)
1267 You can us the 'lspci' command to list existing PCI devices.
1272 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1278 pattern
=> '[^,;]+',
1279 format_description
=> 'string',
1280 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1285 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1291 description
=> "Enable vfio-vga device support.",
1297 format_description
=> 'string',
1298 pattern
=> '[^/\.:]+',
1300 description
=> <<EODESCR
1301 The type of mediated device to use.
1302 An instance of this type will be created on startup of the VM and
1303 will be cleaned up when the VM stops.
1307 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1311 type
=> 'string', format
=> 'pve-qm-hostpci',
1312 description
=> "Map host PCI devices into guest.",
1313 verbose_description
=> <<EODESCR,
1314 Map host PCI devices into guest.
1316 NOTE: This option allows direct access to host hardware. So it is no longer
1317 possible to migrate such machines - use with special care.
1319 CAUTION: Experimental! User reported problems with this option.
1322 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1327 pattern
=> '(/dev/.+|socket)',
1328 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1329 verbose_description
=> <<EODESCR,
1330 Create a serial device inside the VM (n is 0 to 3), and pass through a
1331 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1332 host side (use 'qm terminal' to open a terminal connection).
1334 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1336 CAUTION: Experimental! User reported problems with this option.
1343 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1344 description
=> "Map host parallel devices (n is 0 to 2).",
1345 verbose_description
=> <<EODESCR,
1346 Map host parallel devices (n is 0 to 2).
1348 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1350 CAUTION: Experimental! User reported problems with this option.
1354 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1355 $confdesc->{"parallel$i"} = $paralleldesc;
1358 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1359 $confdesc->{"serial$i"} = $serialdesc;
1362 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1363 $confdesc->{"hostpci$i"} = $hostpcidesc;
1366 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1367 $drivename_hash->{"ide$i"} = 1;
1368 $confdesc->{"ide$i"} = $idedesc;
1371 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1372 $drivename_hash->{"sata$i"} = 1;
1373 $confdesc->{"sata$i"} = $satadesc;
1376 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1377 $drivename_hash->{"scsi$i"} = 1;
1378 $confdesc->{"scsi$i"} = $scsidesc ;
1381 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1382 $drivename_hash->{"virtio$i"} = 1;
1383 $confdesc->{"virtio$i"} = $virtiodesc;
1386 $drivename_hash->{efidisk0
} = 1;
1387 $confdesc->{efidisk0
} = $efidisk_desc;
1389 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1390 $confdesc->{"usb$i"} = $usbdesc;
1395 type
=> 'string', format
=> 'pve-volume-id',
1396 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1399 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1400 $confdesc->{"unused$i"} = $unuseddesc;
1403 my $kvm_api_version = 0;
1406 return $kvm_api_version if $kvm_api_version;
1408 open my $fh, '<', '/dev/kvm'
1411 # 0xae00 => KVM_GET_API_VERSION
1412 $kvm_api_version = ioctl($fh, 0xae00, 0);
1414 return $kvm_api_version;
1417 my $kvm_user_version;
1419 sub kvm_user_version
{
1421 return $kvm_user_version if $kvm_user_version;
1423 $kvm_user_version = 'unknown';
1427 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1428 $kvm_user_version = $2;
1432 eval { run_command
("kvm -version", outfunc
=> $code); };
1435 return $kvm_user_version;
1439 sub kernel_has_vhost_net
{
1440 return -c
'/dev/vhost-net';
1443 sub valid_drive_names
{
1444 # order is important - used to autoselect boot disk
1445 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1446 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1447 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1448 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1452 sub is_valid_drivename
{
1455 return defined($drivename_hash->{$dev});
1460 return defined($confdesc->{$key});
1464 return $nic_model_list;
1467 sub os_list_description
{
1471 wxp
=> 'Windows XP',
1472 w2k
=> 'Windows 2000',
1473 w2k3
=>, 'Windows 2003',
1474 w2k8
=> 'Windows 2008',
1475 wvista
=> 'Windows Vista',
1476 win7
=> 'Windows 7',
1477 win8
=> 'Windows 8/2012',
1478 win10
=> 'Windows 10/2016',
1486 sub get_cdrom_path
{
1488 return $cdrom_path if $cdrom_path;
1490 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1491 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1492 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1496 my ($storecfg, $vmid, $cdrom) = @_;
1498 if ($cdrom eq 'cdrom') {
1499 return get_cdrom_path
();
1500 } elsif ($cdrom eq 'none') {
1502 } elsif ($cdrom =~ m
|^/|) {
1505 return PVE
::Storage
::path
($storecfg, $cdrom);
1509 # try to convert old style file names to volume IDs
1510 sub filename_to_volume_id
{
1511 my ($vmid, $file, $media) = @_;
1513 if (!($file eq 'none' || $file eq 'cdrom' ||
1514 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1516 return undef if $file =~ m
|/|;
1518 if ($media && $media eq 'cdrom') {
1519 $file = "local:iso/$file";
1521 $file = "local:$vmid/$file";
1528 sub verify_media_type
{
1529 my ($opt, $vtype, $media) = @_;
1534 if ($media eq 'disk') {
1536 } elsif ($media eq 'cdrom') {
1539 die "internal error";
1542 return if ($vtype eq $etype);
1544 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1547 sub cleanup_drive_path
{
1548 my ($opt, $storecfg, $drive) = @_;
1550 # try to convert filesystem paths to volume IDs
1552 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1553 ($drive->{file
} !~ m
|^/dev/.+|) &&
1554 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1555 ($drive->{file
} !~ m/^\d+$/)) {
1556 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1557 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1558 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1559 verify_media_type
($opt, $vtype, $drive->{media
});
1560 $drive->{file
} = $volid;
1563 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1566 sub parse_hotplug_features
{
1571 return $res if $data eq '0';
1573 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1575 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1576 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1579 die "invalid hotplug feature '$feature'\n";
1585 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1586 sub pve_verify_hotplug_features
{
1587 my ($value, $noerr) = @_;
1589 return $value if parse_hotplug_features
($value);
1591 return undef if $noerr;
1593 die "unable to parse hotplug option\n";
1596 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1597 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1598 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1599 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1600 # [,iothread=on][,serial=serial][,model=model]
1603 my ($key, $data) = @_;
1605 my ($interface, $index);
1607 if ($key =~ m/^([^\d]+)(\d+)$/) {
1614 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1615 : $confdesc->{$key}->{format
};
1617 warn "invalid drive key: $key\n";
1620 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1621 return undef if !$res;
1622 $res->{interface
} = $interface;
1623 $res->{index} = $index;
1626 foreach my $opt (qw(bps bps_rd bps_wr)) {
1627 if (my $bps = defined(delete $res->{$opt})) {
1628 if (defined($res->{"m$opt"})) {
1629 warn "both $opt and m$opt specified\n";
1633 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1637 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1638 for my $requirement (
1639 [mbps_max
=> 'mbps'],
1640 [mbps_rd_max
=> 'mbps_rd'],
1641 [mbps_wr_max
=> 'mbps_wr'],
1642 [miops_max
=> 'miops'],
1643 [miops_rd_max
=> 'miops_rd'],
1644 [miops_wr_max
=> 'miops_wr'],
1645 [bps_max_length
=> 'mbps_max'],
1646 [bps_rd_max_length
=> 'mbps_rd_max'],
1647 [bps_wr_max_length
=> 'mbps_wr_max'],
1648 [iops_max_length
=> 'iops_max'],
1649 [iops_rd_max_length
=> 'iops_rd_max'],
1650 [iops_wr_max_length
=> 'iops_wr_max']) {
1651 my ($option, $requires) = @$requirement;
1652 if ($res->{$option} && !$res->{$requires}) {
1653 warn "$option requires $requires\n";
1658 return undef if $error;
1660 return undef if $res->{mbps_rd
} && $res->{mbps
};
1661 return undef if $res->{mbps_wr
} && $res->{mbps
};
1662 return undef if $res->{iops_rd
} && $res->{iops
};
1663 return undef if $res->{iops_wr
} && $res->{iops
};
1665 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1666 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1667 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1668 return undef if $res->{interface
} eq 'virtio';
1671 if (my $size = $res->{size
}) {
1672 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1679 my ($vmid, $drive) = @_;
1680 my $data = { %$drive };
1681 delete $data->{$_} for qw(index interface);
1682 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1686 my($fh, $noerr) = @_;
1689 my $SG_GET_VERSION_NUM = 0x2282;
1691 my $versionbuf = "\x00" x
8;
1692 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1694 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1697 my $version = unpack("I", $versionbuf);
1698 if ($version < 30000) {
1699 die "scsi generic interface too old\n" if !$noerr;
1703 my $buf = "\x00" x
36;
1704 my $sensebuf = "\x00" x
8;
1705 my $cmd = pack("C x3 C x1", 0x12, 36);
1707 # see /usr/include/scsi/sg.h
1708 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";
1710 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1711 length($sensebuf), 0, length($buf), $buf,
1712 $cmd, $sensebuf, 6000);
1714 $ret = ioctl($fh, $SG_IO, $packet);
1716 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1720 my @res = unpack($sg_io_hdr_t, $packet);
1721 if ($res[17] || $res[18]) {
1722 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1727 (my $byte0, my $byte1, $res->{vendor
},
1728 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1730 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1731 $res->{type
} = $byte0 & 31;
1739 my $fh = IO
::File-
>new("+<$path") || return undef;
1740 my $res = scsi_inquiry
($fh, 1);
1746 sub machine_type_is_q35
{
1749 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1752 sub print_tabletdevice_full
{
1753 my ($conf, $arch) = @_;
1755 my $q35 = machine_type_is_q35
($conf);
1757 # we use uhci for old VMs because tablet driver was buggy in older qemu
1759 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1765 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1768 sub print_keyboarddevice_full
{
1769 my ($conf, $arch, $machine) = @_;
1771 return undef if $arch ne 'aarch64';
1773 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1776 sub print_drivedevice_full
{
1777 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1782 if ($drive->{interface
} eq 'virtio') {
1783 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1784 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1785 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1786 } elsif ($drive->{interface
} eq 'scsi') {
1788 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1789 my $unit = $drive->{index} % $maxdev;
1790 my $devicetype = 'hd';
1792 if (drive_is_cdrom
($drive)) {
1795 if ($drive->{file
} =~ m
|^/|) {
1796 $path = $drive->{file
};
1797 if (my $info = path_is_scsi
($path)) {
1798 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1799 $devicetype = 'block';
1800 } elsif ($info->{type
} == 1) { # tape
1801 $devicetype = 'generic';
1805 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1808 if($path =~ m/^iscsi\:\/\
//){
1809 $devicetype = 'generic';
1813 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1814 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1816 $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}";
1819 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1820 $device .= ",rotation_rate=1";
1822 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1824 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1825 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1826 my $controller = int($drive->{index} / $maxdev);
1827 my $unit = $drive->{index} % $maxdev;
1828 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1830 $device = "ide-$devicetype";
1831 if ($drive->{interface
} eq 'ide') {
1832 $device .= ",bus=ide.$controller,unit=$unit";
1834 $device .= ",bus=ahci$controller.$unit";
1836 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1838 if ($devicetype eq 'hd') {
1839 if (my $model = $drive->{model
}) {
1840 $model = URI
::Escape
::uri_unescape
($model);
1841 $device .= ",model=$model";
1843 if ($drive->{ssd
}) {
1844 $device .= ",rotation_rate=1";
1847 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn
};
1848 } elsif ($drive->{interface
} eq 'usb') {
1850 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1852 die "unsupported interface type";
1855 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1857 if (my $serial = $drive->{serial
}) {
1858 $serial = URI
::Escape
::uri_unescape
($serial);
1859 $device .= ",serial=$serial";
1866 sub get_initiator_name
{
1869 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1870 while (defined(my $line = <$fh>)) {
1871 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1880 sub print_drive_full
{
1881 my ($storecfg, $vmid, $drive) = @_;
1884 my $volid = $drive->{file
};
1887 if (drive_is_cdrom
($drive)) {
1888 $path = get_iso_path
($storecfg, $vmid, $volid);
1890 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1892 $path = PVE
::Storage
::path
($storecfg, $volid);
1893 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1894 $format = qemu_img_format
($scfg, $volname);
1902 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1903 foreach my $o (@qemu_drive_options) {
1904 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1907 # snapshot only accepts on|off
1908 if (defined($drive->{snapshot
})) {
1909 my $v = $drive->{snapshot
} ?
'on' : 'off';
1910 $opts .= ",snapshot=$v";
1913 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1914 my ($dir, $qmpname) = @$type;
1915 if (my $v = $drive->{"mbps$dir"}) {
1916 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1918 if (my $v = $drive->{"mbps${dir}_max"}) {
1919 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1921 if (my $v = $drive->{"bps${dir}_max_length"}) {
1922 $opts .= ",throttling.bps$qmpname-max-length=$v";
1924 if (my $v = $drive->{"iops${dir}"}) {
1925 $opts .= ",throttling.iops$qmpname=$v";
1927 if (my $v = $drive->{"iops${dir}_max"}) {
1928 $opts .= ",throttling.iops$qmpname-max=$v";
1930 if (my $v = $drive->{"iops${dir}_max_length"}) {
1931 $opts .= ",throttling.iops$qmpname-max-length=$v";
1935 $opts .= ",format=$format" if $format && !$drive->{format
};
1937 my $cache_direct = 0;
1939 if (my $cache = $drive->{cache
}) {
1940 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1941 } elsif (!drive_is_cdrom
($drive)) {
1942 $opts .= ",cache=none";
1946 # aio native works only with O_DIRECT
1947 if (!$drive->{aio
}) {
1949 $opts .= ",aio=native";
1951 $opts .= ",aio=threads";
1955 if (!drive_is_cdrom
($drive)) {
1957 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1958 $detectzeroes = 'off';
1959 } elsif ($drive->{discard
}) {
1960 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1962 # This used to be our default with discard not being specified:
1963 $detectzeroes = 'on';
1965 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1968 my $pathinfo = $path ?
"file=$path," : '';
1970 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1973 sub print_netdevice_full
{
1974 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1976 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1978 my $device = $net->{model
};
1979 if ($net->{model
} eq 'virtio') {
1980 $device = 'virtio-net-pci';
1983 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1984 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1985 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1986 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1987 my $vectors = $net->{queues
} * 2 + 2;
1988 $tmpstr .= ",vectors=$vectors,mq=on";
1990 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1992 if ($use_old_bios_files) {
1994 if ($device eq 'virtio-net-pci') {
1995 $romfile = 'pxe-virtio.rom';
1996 } elsif ($device eq 'e1000') {
1997 $romfile = 'pxe-e1000.rom';
1998 } elsif ($device eq 'ne2k') {
1999 $romfile = 'pxe-ne2k_pci.rom';
2000 } elsif ($device eq 'pcnet') {
2001 $romfile = 'pxe-pcnet.rom';
2002 } elsif ($device eq 'rtl8139') {
2003 $romfile = 'pxe-rtl8139.rom';
2005 $tmpstr .= ",romfile=$romfile" if $romfile;
2011 sub print_netdev_full
{
2012 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
2015 if ($netid =~ m/^net(\d+)$/) {
2019 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
2021 my $ifname = "tap${vmid}i$i";
2023 # kvm uses TUNSETIFF ioctl, and that limits ifname length
2024 die "interface name '$ifname' is too long (max 15 character)\n"
2025 if length($ifname) >= 16;
2027 my $vhostparam = '';
2028 if (is_native
($arch)) {
2029 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
2032 my $vmname = $conf->{name
} || "vm$vmid";
2035 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
2037 if ($net->{bridge
}) {
2038 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
2040 $netdev = "type=user,id=$netid,hostname=$vmname";
2043 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
2049 sub print_cpu_device
{
2050 my ($conf, $id) = @_;
2052 my $kvm = $conf->{kvm
} // 1;
2053 my $cpu = $kvm ?
"kvm64" : "qemu64";
2054 if (my $cputype = $conf->{cpu
}) {
2055 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
2056 or die "Cannot parse cpu description: $cputype\n";
2057 $cpu = $cpuconf->{cputype
};
2060 my $cores = $conf->{cores
} || 1;
2062 my $current_core = ($id - 1) % $cores;
2063 my $current_socket = int(($id - 1 - $current_core)/$cores);
2065 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2069 'cirrus' => 'cirrus-vga',
2071 'vmware' => 'vmware-svga',
2072 'virtio' => 'virtio-vga',
2075 sub print_vga_device
{
2076 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2078 my $type = $vga_map->{$vga->{type
}};
2079 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
2080 $type = 'virtio-gpu';
2082 my $vgamem_mb = $vga->{memory
};
2084 $type = $id ?
'qxl' : 'qxl-vga';
2086 die "no devicetype for $vga->{type}\n" if !$type;
2090 if ($vga->{type
} eq 'virtio') {
2091 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2092 $memory = ",max_hostmem=$bytes";
2094 # from https://www.spice-space.org/multiple-monitors.html
2095 $memory = ",vgamem_mb=$vga->{memory}";
2096 my $ram = $vgamem_mb * 4;
2097 my $vram = $vgamem_mb * 2;
2098 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2100 $memory = ",vgamem_mb=$vga->{memory}";
2102 } elsif ($qxlnum && $id) {
2103 $memory = ",ram_size=67108864,vram_size=33554432";
2106 my $q35 = machine_type_is_q35
($conf);
2107 my $vgaid = "vga" . ($id // '');
2110 if ($q35 && $vgaid eq 'vga') {
2111 # the first display uses pcie.0 bus on q35 machines
2112 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2114 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2117 return "$type,id=${vgaid}${memory}${pciaddr}";
2120 sub drive_is_cloudinit
{
2122 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2125 sub drive_is_cdrom
{
2126 my ($drive, $exclude_cloudinit) = @_;
2128 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2130 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2134 sub parse_number_sets
{
2137 foreach my $part (split(/;/, $set)) {
2138 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2139 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2140 push @$res, [ $1, $2 ];
2142 die "invalid range: $part\n";
2151 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2152 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2153 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2160 return undef if !$value;
2162 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2164 my @idlist = split(/;/, $res->{host
});
2165 delete $res->{host
};
2166 foreach my $id (@idlist) {
2167 if ($id =~ m/\./) { # full id 00:00.1
2168 push @{$res->{pciid
}}, {
2171 } else { # partial id 00:00
2172 $res->{pciid
} = PVE
::SysFSTools
::lspci
($id);
2178 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2182 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2187 if (!defined($res->{macaddr
})) {
2188 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2189 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2194 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2195 sub parse_ipconfig
{
2198 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2204 if ($res->{gw
} && !$res->{ip
}) {
2205 warn 'gateway specified without specifying an IP address';
2208 if ($res->{gw6
} && !$res->{ip6
}) {
2209 warn 'IPv6 gateway specified without specifying an IPv6 address';
2212 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2213 warn 'gateway specified together with DHCP';
2216 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2218 warn "IPv6 gateway specified together with $res->{ip6} address";
2222 if (!$res->{ip
} && !$res->{ip6
}) {
2223 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2232 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2235 sub add_random_macs
{
2236 my ($settings) = @_;
2238 foreach my $opt (keys %$settings) {
2239 next if $opt !~ m/^net(\d+)$/;
2240 my $net = parse_net
($settings->{$opt});
2242 $settings->{$opt} = print_net
($net);
2246 sub vm_is_volid_owner
{
2247 my ($storecfg, $vmid, $volid) = @_;
2249 if ($volid !~ m
|^/|) {
2251 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2252 if ($owner && ($owner == $vmid)) {
2260 sub split_flagged_list
{
2261 my $text = shift || '';
2262 $text =~ s/[,;]/ /g;
2264 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2267 sub join_flagged_list
{
2268 my ($how, $lst) = @_;
2269 join $how, map { $lst->{$_} . $_ } keys %$lst;
2272 sub vmconfig_delete_pending_option
{
2273 my ($conf, $key, $force) = @_;
2275 delete $conf->{pending
}->{$key};
2276 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2277 $pending_delete_hash->{$key} = $force ?
'!' : '';
2278 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2281 sub vmconfig_undelete_pending_option
{
2282 my ($conf, $key) = @_;
2284 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2285 delete $pending_delete_hash->{$key};
2287 if (%$pending_delete_hash) {
2288 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2290 delete $conf->{pending
}->{delete};
2294 sub vmconfig_register_unused_drive
{
2295 my ($storecfg, $vmid, $conf, $drive) = @_;
2297 if (drive_is_cloudinit
($drive)) {
2298 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2300 } elsif (!drive_is_cdrom
($drive)) {
2301 my $volid = $drive->{file
};
2302 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2303 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2308 sub vmconfig_cleanup_pending
{
2311 # remove pending changes when nothing changed
2313 foreach my $opt (keys %{$conf->{pending
}}) {
2314 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2316 delete $conf->{pending
}->{$opt};
2320 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2321 my $pending_delete_hash = {};
2322 while (my ($opt, $force) = each %$current_delete_hash) {
2323 if (defined($conf->{$opt})) {
2324 $pending_delete_hash->{$opt} = $force;
2330 if (%$pending_delete_hash) {
2331 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2333 delete $conf->{pending
}->{delete};
2339 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2343 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2344 format_description
=> 'UUID',
2345 description
=> "Set SMBIOS1 UUID.",
2351 format_description
=> 'string',
2352 description
=> "Set SMBIOS1 version.",
2358 format_description
=> 'string',
2359 description
=> "Set SMBIOS1 serial number.",
2365 format_description
=> 'string',
2366 description
=> "Set SMBIOS1 manufacturer.",
2372 format_description
=> 'string',
2373 description
=> "Set SMBIOS1 product ID.",
2379 format_description
=> 'string',
2380 description
=> "Set SMBIOS1 SKU string.",
2386 format_description
=> 'string',
2387 description
=> "Set SMBIOS1 family string.",
2395 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2402 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2405 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2407 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2408 sub verify_bootdisk
{
2409 my ($value, $noerr) = @_;
2411 return $value if is_valid_drivename
($value);
2413 return undef if $noerr;
2415 die "invalid boot disk '$value'\n";
2418 sub parse_watchdog
{
2421 return undef if !$value;
2423 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2428 sub parse_guest_agent
{
2431 return {} if !defined($value->{agent
});
2433 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2436 # if the agent is disabled ignore the other potentially set properties
2437 return {} if !$res->{enabled
};
2444 return {} if !$value;
2445 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2450 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2451 sub verify_usb_device
{
2452 my ($value, $noerr) = @_;
2454 return $value if parse_usb_device
($value);
2456 return undef if $noerr;
2458 die "unable to parse usb device\n";
2461 # add JSON properties for create and set function
2462 sub json_config_properties
{
2465 foreach my $opt (keys %$confdesc) {
2466 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2467 $prop->{$opt} = $confdesc->{$opt};
2473 # return copy of $confdesc_cloudinit to generate documentation
2474 sub cloudinit_config_properties
{
2476 return dclone
($confdesc_cloudinit);
2480 my ($key, $value) = @_;
2482 die "unknown setting '$key'\n" if !$confdesc->{$key};
2484 my $type = $confdesc->{$key}->{type
};
2486 if (!defined($value)) {
2487 die "got undefined value\n";
2490 if ($value =~ m/[\n\r]/) {
2491 die "property contains a line feed\n";
2494 if ($type eq 'boolean') {
2495 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2496 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2497 die "type check ('boolean') failed - got '$value'\n";
2498 } elsif ($type eq 'integer') {
2499 return int($1) if $value =~ m/^(\d+)$/;
2500 die "type check ('integer') failed - got '$value'\n";
2501 } elsif ($type eq 'number') {
2502 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2503 die "type check ('number') failed - got '$value'\n";
2504 } elsif ($type eq 'string') {
2505 if (my $fmt = $confdesc->{$key}->{format
}) {
2506 PVE
::JSONSchema
::check_format
($fmt, $value);
2509 $value =~ s/^\"(.*)\"$/$1/;
2512 die "internal error"
2519 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2520 utime undef, undef, $conf;
2524 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2526 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2528 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2530 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2532 if ($conf->{template
}) {
2533 # check if any base image is still used by a linked clone
2534 foreach_drive
($conf, sub {
2535 my ($ds, $drive) = @_;
2537 return if drive_is_cdrom
($drive);
2539 my $volid = $drive->{file
};
2541 return if !$volid || $volid =~ m
|^/|;
2543 die "base volume '$volid' is still in use by linked cloned\n"
2544 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2549 # only remove disks owned by this VM
2550 foreach_drive
($conf, sub {
2551 my ($ds, $drive) = @_;
2553 return if drive_is_cdrom
($drive, 1);
2555 my $volid = $drive->{file
};
2557 return if !$volid || $volid =~ m
|^/|;
2559 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2560 return if !$path || !$owner || ($owner != $vmid);
2563 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2565 warn "Could not remove disk '$volid', check manually: $@" if $@;
2569 if ($keep_empty_config) {
2570 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2575 # also remove unused disk
2577 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2580 PVE
::Storage
::foreach_volid
($dl, sub {
2581 my ($volid, $sid, $volname, $d) = @_;
2582 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2591 sub parse_vm_config
{
2592 my ($filename, $raw) = @_;
2594 return undef if !defined($raw);
2597 digest
=> Digest
::SHA
::sha1_hex
($raw),
2602 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2603 || die "got strange filename '$filename'";
2611 my @lines = split(/\n/, $raw);
2612 foreach my $line (@lines) {
2613 next if $line =~ m/^\s*$/;
2615 if ($line =~ m/^\[PENDING\]\s*$/i) {
2616 $section = 'pending';
2617 if (defined($descr)) {
2619 $conf->{description
} = $descr;
2622 $conf = $res->{$section} = {};
2625 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2627 if (defined($descr)) {
2629 $conf->{description
} = $descr;
2632 $conf = $res->{snapshots
}->{$section} = {};
2636 if ($line =~ m/^\#(.*)\s*$/) {
2637 $descr = '' if !defined($descr);
2638 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2642 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2643 $descr = '' if !defined($descr);
2644 $descr .= PVE
::Tools
::decode_text
($2);
2645 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2646 $conf->{snapstate
} = $1;
2647 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2650 $conf->{$key} = $value;
2651 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2653 if ($section eq 'pending') {
2654 $conf->{delete} = $value; # we parse this later
2656 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2658 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2661 eval { $value = check_type
($key, $value); };
2663 warn "vm $vmid - unable to parse value of '$key' - $@";
2665 $key = 'ide2' if $key eq 'cdrom';
2666 my $fmt = $confdesc->{$key}->{format
};
2667 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2668 my $v = parse_drive
($key, $value);
2669 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2670 $v->{file
} = $volid;
2671 $value = print_drive
($vmid, $v);
2673 warn "vm $vmid - unable to parse value of '$key'\n";
2678 $conf->{$key} = $value;
2683 if (defined($descr)) {
2685 $conf->{description
} = $descr;
2687 delete $res->{snapstate
}; # just to be sure
2692 sub write_vm_config
{
2693 my ($filename, $conf) = @_;
2695 delete $conf->{snapstate
}; # just to be sure
2697 if ($conf->{cdrom
}) {
2698 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2699 $conf->{ide2
} = $conf->{cdrom
};
2700 delete $conf->{cdrom
};
2703 # we do not use 'smp' any longer
2704 if ($conf->{sockets
}) {
2705 delete $conf->{smp
};
2706 } elsif ($conf->{smp
}) {
2707 $conf->{sockets
} = $conf->{smp
};
2708 delete $conf->{cores
};
2709 delete $conf->{smp
};
2712 my $used_volids = {};
2714 my $cleanup_config = sub {
2715 my ($cref, $pending, $snapname) = @_;
2717 foreach my $key (keys %$cref) {
2718 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2719 $key eq 'snapstate' || $key eq 'pending';
2720 my $value = $cref->{$key};
2721 if ($key eq 'delete') {
2722 die "propertry 'delete' is only allowed in [PENDING]\n"
2724 # fixme: check syntax?
2727 eval { $value = check_type
($key, $value); };
2728 die "unable to parse value of '$key' - $@" if $@;
2730 $cref->{$key} = $value;
2732 if (!$snapname && is_valid_drivename
($key)) {
2733 my $drive = parse_drive
($key, $value);
2734 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2739 &$cleanup_config($conf);
2741 &$cleanup_config($conf->{pending
}, 1);
2743 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2744 die "internal error" if $snapname eq 'pending';
2745 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2748 # remove 'unusedX' settings if we re-add a volume
2749 foreach my $key (keys %$conf) {
2750 my $value = $conf->{$key};
2751 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2752 delete $conf->{$key};
2756 my $generate_raw_config = sub {
2757 my ($conf, $pending) = @_;
2761 # add description as comment to top of file
2762 if (defined(my $descr = $conf->{description
})) {
2764 foreach my $cl (split(/\n/, $descr)) {
2765 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2768 $raw .= "#\n" if $pending;
2772 foreach my $key (sort keys %$conf) {
2773 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2774 $raw .= "$key: $conf->{$key}\n";
2779 my $raw = &$generate_raw_config($conf);
2781 if (scalar(keys %{$conf->{pending
}})){
2782 $raw .= "\n[PENDING]\n";
2783 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2786 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2787 $raw .= "\n[$snapname]\n";
2788 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2798 # we use static defaults from our JSON schema configuration
2799 foreach my $key (keys %$confdesc) {
2800 if (defined(my $default = $confdesc->{$key}->{default})) {
2801 $res->{$key} = $default;
2809 my $vmlist = PVE
::Cluster
::get_vmlist
();
2811 return $res if !$vmlist || !$vmlist->{ids
};
2812 my $ids = $vmlist->{ids
};
2814 foreach my $vmid (keys %$ids) {
2815 my $d = $ids->{$vmid};
2816 next if !$d->{node
} || $d->{node
} ne $nodename;
2817 next if !$d->{type
} || $d->{type
} ne 'qemu';
2818 $res->{$vmid}->{exists} = 1;
2823 # test if VM uses local resources (to prevent migration)
2824 sub check_local_resources
{
2825 my ($conf, $noerr) = @_;
2829 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2830 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2832 $loc_res = 1 if $conf->{ivshmem
};
2834 foreach my $k (keys %$conf) {
2835 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2836 # sockets are safe: they will recreated be on the target side post-migrate
2837 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2838 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2841 die "VM uses local resources\n" if $loc_res && !$noerr;
2846 # check if used storages are available on all nodes (use by migrate)
2847 sub check_storage_availability
{
2848 my ($storecfg, $conf, $node) = @_;
2850 foreach_drive
($conf, sub {
2851 my ($ds, $drive) = @_;
2853 my $volid = $drive->{file
};
2856 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2859 # check if storage is available on both nodes
2860 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2861 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2865 # list nodes where all VM images are available (used by has_feature API)
2867 my ($conf, $storecfg) = @_;
2869 my $nodelist = PVE
::Cluster
::get_nodelist
();
2870 my $nodehash = { map { $_ => 1 } @$nodelist };
2871 my $nodename = PVE
::INotify
::nodename
();
2873 foreach_drive
($conf, sub {
2874 my ($ds, $drive) = @_;
2876 my $volid = $drive->{file
};
2879 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2881 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2882 if ($scfg->{disable
}) {
2884 } elsif (my $avail = $scfg->{nodes
}) {
2885 foreach my $node (keys %$nodehash) {
2886 delete $nodehash->{$node} if !$avail->{$node};
2888 } elsif (!$scfg->{shared
}) {
2889 foreach my $node (keys %$nodehash) {
2890 delete $nodehash->{$node} if $node ne $nodename
2900 my ($pidfile, $pid) = @_;
2902 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2906 return undef if !$line;
2907 my @param = split(/\0/, $line);
2909 my $cmd = $param[0];
2910 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2912 for (my $i = 0; $i < scalar (@param); $i++) {
2915 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2916 my $p = $param[$i+1];
2917 return 1 if $p && ($p eq $pidfile);
2926 my ($vmid, $nocheck, $node) = @_;
2928 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2930 die "unable to find configuration file for VM $vmid - no such machine\n"
2931 if !$nocheck && ! -f
$filename;
2933 my $pidfile = pidfile_name
($vmid);
2935 if (my $fd = IO
::File-
>new("<$pidfile")) {
2940 my $mtime = $st->mtime;
2941 if ($mtime > time()) {
2942 warn "file '$filename' modified in future\n";
2945 if ($line =~ m/^(\d+)$/) {
2947 if (check_cmdline
($pidfile, $pid)) {
2948 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2960 my $vzlist = config_list
();
2962 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2964 while (defined(my $de = $fd->read)) {
2965 next if $de !~ m/^(\d+)\.pid$/;
2967 next if !defined($vzlist->{$vmid});
2968 if (my $pid = check_running
($vmid)) {
2969 $vzlist->{$vmid}->{pid
} = $pid;
2977 my ($storecfg, $conf) = @_;
2979 my $bootdisk = $conf->{bootdisk
};
2980 return undef if !$bootdisk;
2981 return undef if !is_valid_drivename
($bootdisk);
2983 return undef if !$conf->{$bootdisk};
2985 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2986 return undef if !defined($drive);
2988 return undef if drive_is_cdrom
($drive);
2990 my $volid = $drive->{file
};
2991 return undef if !$volid;
2993 return $drive->{size
};
2996 our $vmstatus_return_properties = {
2997 vmid
=> get_standard_option
('pve-vmid'),
2999 description
=> "Qemu process status.",
3001 enum
=> ['stopped', 'running'],
3004 description
=> "Maximum memory in bytes.",
3007 renderer
=> 'bytes',
3010 description
=> "Root disk size in bytes.",
3013 renderer
=> 'bytes',
3016 description
=> "VM name.",
3021 description
=> "Qemu QMP agent status.",
3026 description
=> "PID of running qemu process.",
3031 description
=> "Uptime.",
3034 renderer
=> 'duration',
3037 description
=> "Maximum usable CPUs.",
3043 my $last_proc_pid_stat;
3045 # get VM status information
3046 # This must be fast and should not block ($full == false)
3047 # We only query KVM using QMP if $full == true (this can be slow)
3049 my ($opt_vmid, $full) = @_;
3053 my $storecfg = PVE
::Storage
::config
();
3055 my $list = vzlist
();
3056 my $defaults = load_defaults
();
3058 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3060 my $cpucount = $cpuinfo->{cpus
} || 1;
3062 foreach my $vmid (keys %$list) {
3063 next if $opt_vmid && ($vmid ne $opt_vmid);
3065 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3066 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3068 my $d = { vmid
=> $vmid };
3069 $d->{pid
} = $list->{$vmid}->{pid
};
3071 # fixme: better status?
3072 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3074 my $size = disksize
($storecfg, $conf);
3075 if (defined($size)) {
3076 $d->{disk
} = 0; # no info available
3077 $d->{maxdisk
} = $size;
3083 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3084 * ($conf->{cores
} || $defaults->{cores
});
3085 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3086 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3088 $d->{name
} = $conf->{name
} || "VM $vmid";
3089 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3090 : $defaults->{memory
}*(1024*1024);
3092 if ($conf->{balloon
}) {
3093 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3094 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3095 : $defaults->{shares
};
3106 $d->{diskwrite
} = 0;
3108 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3110 $d->{serial
} = 1 if conf_has_serial
($conf);
3115 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3116 foreach my $dev (keys %$netdev) {
3117 next if $dev !~ m/^tap([1-9]\d*)i/;
3119 my $d = $res->{$vmid};
3122 $d->{netout
} += $netdev->{$dev}->{receive
};
3123 $d->{netin
} += $netdev->{$dev}->{transmit
};
3126 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3127 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3132 my $ctime = gettimeofday
;
3134 foreach my $vmid (keys %$list) {
3136 my $d = $res->{$vmid};
3137 my $pid = $d->{pid
};
3140 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3141 next if !$pstat; # not running
3143 my $used = $pstat->{utime} + $pstat->{stime
};
3145 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3147 if ($pstat->{vsize
}) {
3148 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3151 my $old = $last_proc_pid_stat->{$pid};
3153 $last_proc_pid_stat->{$pid} = {
3161 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3163 if ($dtime > 1000) {
3164 my $dutime = $used - $old->{used
};
3166 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3167 $last_proc_pid_stat->{$pid} = {
3173 $d->{cpu
} = $old->{cpu
};
3177 return $res if !$full;
3179 my $qmpclient = PVE
::QMPClient-
>new();
3181 my $ballooncb = sub {
3182 my ($vmid, $resp) = @_;
3184 my $info = $resp->{'return'};
3185 return if !$info->{max_mem
};
3187 my $d = $res->{$vmid};
3189 # use memory assigned to VM
3190 $d->{maxmem
} = $info->{max_mem
};
3191 $d->{balloon
} = $info->{actual
};
3193 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3194 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3195 $d->{freemem
} = $info->{free_mem
};
3198 $d->{ballooninfo
} = $info;
3201 my $blockstatscb = sub {
3202 my ($vmid, $resp) = @_;
3203 my $data = $resp->{'return'} || [];
3204 my $totalrdbytes = 0;
3205 my $totalwrbytes = 0;
3207 for my $blockstat (@$data) {
3208 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3209 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3211 $blockstat->{device
} =~ s/drive-//;
3212 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3214 $res->{$vmid}->{diskread
} = $totalrdbytes;
3215 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3218 my $statuscb = sub {
3219 my ($vmid, $resp) = @_;
3221 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3222 # this fails if ballon driver is not loaded, so this must be
3223 # the last commnand (following command are aborted if this fails).
3224 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3226 my $status = 'unknown';
3227 if (!defined($status = $resp->{'return'}->{status
})) {
3228 warn "unable to get VM status\n";
3232 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3235 foreach my $vmid (keys %$list) {
3236 next if $opt_vmid && ($vmid ne $opt_vmid);
3237 next if !$res->{$vmid}->{pid
}; # not running
3238 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3241 $qmpclient->queue_execute(undef, 2);
3243 foreach my $vmid (keys %$list) {
3244 next if $opt_vmid && ($vmid ne $opt_vmid);
3245 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3252 my ($conf, $func, @param) = @_;
3254 foreach my $ds (valid_drive_names
()) {
3255 next if !defined($conf->{$ds});
3257 my $drive = parse_drive
($ds, $conf->{$ds});
3260 &$func($ds, $drive, @param);
3265 my ($conf, $func, @param) = @_;
3269 my $test_volid = sub {
3270 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3274 $volhash->{$volid}->{cdrom
} //= 1;
3275 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3277 $volhash->{$volid}->{replicate
} //= 0;
3278 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3280 $volhash->{$volid}->{shared
} //= 0;
3281 $volhash->{$volid}->{shared
} = 1 if $shared;
3283 $volhash->{$volid}->{referenced_in_config
} //= 0;
3284 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3286 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3287 if defined($snapname);
3290 foreach_drive
($conf, sub {
3291 my ($ds, $drive) = @_;
3292 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3295 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3296 my $snap = $conf->{snapshots
}->{$snapname};
3297 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3298 foreach_drive
($snap, sub {
3299 my ($ds, $drive) = @_;
3300 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3304 foreach my $volid (keys %$volhash) {
3305 &$func($volid, $volhash->{$volid}, @param);
3309 sub conf_has_serial
{
3312 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3313 if ($conf->{"serial$i"}) {
3321 sub vga_conf_has_spice
{
3324 my $vgaconf = parse_vga
($vga);
3325 my $vgatype = $vgaconf->{type
};
3326 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3331 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3332 sub get_host_arch
() {
3333 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3339 return get_host_arch
() eq $arch;
3342 my $default_machines = {
3347 sub get_basic_machine_info
{
3348 my ($conf, $forcemachine) = @_;
3350 my $arch = $conf->{arch
} // get_host_arch
();
3351 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3352 return ($arch, $machine);
3355 sub get_ovmf_files
($) {
3358 my $ovmf = $OVMF->{$arch}
3359 or die "no OVMF images known for architecture '$arch'\n";
3365 aarch64
=> '/usr/bin/qemu-system-aarch64',
3366 x86_64
=> '/usr/bin/qemu-system-x86_64',
3368 sub get_command_for_arch
($) {
3370 return '/usr/bin/kvm' if is_native
($arch);
3372 my $cmd = $Arch2Qemu->{$arch}
3373 or die "don't know how to emulate architecture '$arch'\n";
3377 sub get_cpu_options
{
3378 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3381 my $ostype = $conf->{ostype
};
3383 my $cpu = $kvm ?
"kvm64" : "qemu64";
3384 if ($arch eq 'aarch64') {
3385 $cpu = 'cortex-a57';
3388 if (my $cputype = $conf->{cpu
}) {
3389 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3390 or die "Cannot parse cpu description: $cputype\n";
3391 $cpu = $cpuconf->{cputype
};
3392 $kvm_off = 1 if $cpuconf->{hidden
};
3393 $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
3395 if (defined(my $flags = $cpuconf->{flags
})) {
3396 push @$cpuFlags, split(";", $flags);
3400 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3402 push @$cpuFlags , '-x2apic'
3403 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3405 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3407 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3409 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3411 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3412 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3415 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough, $hv_vendor_id) if $kvm;
3417 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3419 push @$cpuFlags, 'kvm=off' if $kvm_off;
3421 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3422 push @$cpuFlags, "vendor=${cpu_vendor}"
3423 if $cpu_vendor ne 'default';
3424 } elsif ($arch ne 'aarch64') {
3425 die "internal error"; # should not happen
3428 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3430 return ('-cpu', $cpu);
3433 sub config_to_command
{
3434 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3437 my $globalFlags = [];
3438 my $machineFlags = [];
3443 my $kvmver = kvm_user_version
();
3444 my $vernum = 0; # unknown
3445 my $ostype = $conf->{ostype
};
3446 my $winversion = windows_version
($ostype);
3447 my $kvm = $conf->{kvm
};
3449 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3450 $kvm //= 1 if is_native
($arch);
3453 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3454 if !defined kvm_version
();
3457 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3458 $vernum = $1*1000000+$2*1000;
3459 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3460 $vernum = $1*1000000+$2*1000+$3;
3463 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3465 my $have_ovz = -f
'/proc/vz/vestat';
3467 my $q35 = machine_type_is_q35
($conf);
3468 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3469 my $use_old_bios_files = undef;
3470 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3472 my $cpuunits = defined($conf->{cpuunits
}) ?
3473 $conf->{cpuunits
} : $defaults->{cpuunits
};
3475 push @$cmd, get_command_for_arch
($arch);
3477 push @$cmd, '-id', $vmid;
3479 my $vmname = $conf->{name
} || "vm$vmid";
3481 push @$cmd, '-name', $vmname;
3485 my $qmpsocket = qmp_socket
($vmid);
3486 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3487 push @$cmd, '-mon', "chardev=qmp,mode=control";
3489 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3490 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3491 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3494 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3496 push @$cmd, '-daemonize';
3498 if ($conf->{smbios1
}) {
3499 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3502 if ($conf->{vmgenid
}) {
3503 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3506 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3507 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3508 die "uefi base image not found\n" if ! -f
$ovmf_code;
3512 if (my $efidisk = $conf->{efidisk0
}) {
3513 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3514 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3515 $format = $d->{format
};
3517 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3518 if (!defined($format)) {
3519 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3520 $format = qemu_img_format
($scfg, $volname);
3524 die "efidisk format must be specified\n"
3525 if !defined($format);
3528 warn "no efidisk configured! Using temporary efivars disk.\n";
3529 $path = "/tmp/$vmid-ovmf.fd";
3530 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3534 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3535 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3539 # add usb controllers
3540 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3541 push @$devices, @usbcontrollers if @usbcontrollers;
3542 my $vga = parse_vga
($conf->{vga
});
3544 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3545 $vga->{type
} = 'qxl' if $qxlnum;
3547 if (!$vga->{type
}) {
3548 if ($arch eq 'aarch64') {
3549 $vga->{type
} = 'virtio';
3550 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3551 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3553 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3557 # enable absolute mouse coordinates (needed by vnc)
3559 if (defined($conf->{tablet
})) {
3560 $tablet = $conf->{tablet
};
3562 $tablet = $defaults->{tablet
};
3563 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3564 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3568 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3569 my $kbd = print_keyboarddevice_full
($conf, $arch);
3570 push @$devices, '-device', $kbd if defined($kbd);
3574 my $gpu_passthrough;
3577 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3578 my $d = parse_hostpci
($conf->{"hostpci$i"});
3581 my $pcie = $d->{pcie
};
3583 die "q35 machine model is not enabled" if !$q35;
3584 # win7 wants to have the pcie devices directly on the pcie bus
3585 # instead of in the root port
3586 if ($winversion == 7) {
3587 $pciaddr = print_pcie_addr
("hostpci${i}bus0");
3589 $pciaddr = print_pcie_addr
("hostpci$i");
3592 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3595 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3596 my $romfile = $d->{romfile
};
3599 if ($d->{'x-vga'}) {
3600 $xvga = ',x-vga=on';
3602 $vga->{type
} = 'none' if !defined($conf->{vga
});
3603 $gpu_passthrough = 1;
3605 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3609 my $pcidevices = $d->{pciid
};
3610 my $multifunction = 1 if @$pcidevices > 1;
3612 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3613 my $id = $pcidevices->[0]->{id
};
3614 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3615 $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3616 } elsif ($d->{mdev
}) {
3617 warn "ignoring mediated device with multifunction device\n";
3621 foreach my $pcidevice (@$pcidevices) {
3623 my $id = "hostpci$i";
3624 $id .= ".$j" if $multifunction;
3625 my $addr = $pciaddr;
3626 $addr .= ".$j" if $multifunction;
3627 my $devicestr = "vfio-pci";
3629 $devicestr .= ",sysfsdev=$sysfspath";
3631 $devicestr .= ",host=$pcidevice->{id}";
3633 $devicestr .= ",id=$id$addr";
3636 $devicestr .= "$rombar$xvga";
3637 $devicestr .= ",multifunction=on" if $multifunction;
3638 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3641 push @$devices, '-device', $devicestr;
3647 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3648 push @$devices, @usbdevices if @usbdevices;
3650 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3651 if (my $path = $conf->{"serial$i"}) {
3652 if ($path eq 'socket') {
3653 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3654 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3655 # On aarch64, serial0 is the UART device. Qemu only allows
3656 # connecting UART devices via the '-serial' command line, as
3657 # the device has a fixed slot on the hardware...
3658 if ($arch eq 'aarch64' && $i == 0) {
3659 push @$devices, '-serial', "chardev:serial$i";
3661 push @$devices, '-device', "isa-serial,chardev=serial$i";
3664 die "no such serial device\n" if ! -c
$path;
3665 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3666 push @$devices, '-device', "isa-serial,chardev=serial$i";
3672 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3673 if (my $path = $conf->{"parallel$i"}) {
3674 die "no such parallel device\n" if ! -c
$path;
3675 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3676 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3677 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3683 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3684 $sockets = $conf->{sockets
} if $conf->{sockets
};
3686 my $cores = $conf->{cores
} || 1;
3688 my $maxcpus = $sockets * $cores;
3690 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3692 my $allowed_vcpus = $cpuinfo->{cpus
};
3694 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3695 if ($allowed_vcpus < $maxcpus);
3697 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3699 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3700 for (my $i = 2; $i <= $vcpus; $i++) {
3701 my $cpustr = print_cpu_device
($conf,$i);
3702 push @$cmd, '-device', $cpustr;
3707 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3709 push @$cmd, '-nodefaults';
3711 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3713 my $bootindex_hash = {};
3715 foreach my $o (split(//, $bootorder)) {
3716 $bootindex_hash->{$o} = $i*100;
3720 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3722 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3724 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3726 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3727 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3728 my $socket = vnc_socket
($vmid);
3729 push @$cmd, '-vnc', "unix:$socket,x509,password";
3731 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3732 push @$cmd, '-nographic';
3736 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3738 my $useLocaltime = $conf->{localtime};
3740 if ($winversion >= 5) { # windows
3741 $useLocaltime = 1 if !defined($conf->{localtime});
3743 # use time drift fix when acpi is enabled
3744 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3745 $tdf = 1 if !defined($conf->{tdf
});
3749 if ($winversion >= 6) {
3750 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3751 push @$cmd, '-no-hpet';
3754 push @$rtcFlags, 'driftfix=slew' if $tdf;
3757 push @$machineFlags, 'accel=tcg';
3760 if ($machine_type) {
3761 push @$machineFlags, "type=${machine_type}";
3764 if ($conf->{startdate
}) {
3765 push @$rtcFlags, "base=$conf->{startdate}";
3766 } elsif ($useLocaltime) {
3767 push @$rtcFlags, 'base=localtime';
3770 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3772 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3774 push @$cmd, '-S' if $conf->{freeze
};
3776 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3779 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3780 #push @$cmd, '-soundhw', 'es1370';
3781 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3783 if (parse_guest_agent
($conf)->{enabled
}) {
3784 my $qgasocket = qmp_socket
($vmid, 1);
3785 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3786 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3787 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3788 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3796 for(my $i = 1; $i < $qxlnum; $i++){
3797 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3800 # assume other OS works like Linux
3801 my ($ram, $vram) = ("134217728", "67108864");
3802 if ($vga->{memory
}) {
3803 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3804 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3806 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3807 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3811 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3813 my $nodename = PVE
::INotify
::nodename
();
3814 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3815 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3816 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3817 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3818 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3820 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3822 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3823 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3824 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3827 # enable balloon by default, unless explicitly disabled
3828 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3829 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3830 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3833 if ($conf->{watchdog
}) {
3834 my $wdopts = parse_watchdog
($conf->{watchdog
});
3835 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3836 my $watchdog = $wdopts->{model
} || 'i6300esb';
3837 push @$devices, '-device', "$watchdog$pciaddr";
3838 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3842 my $scsicontroller = {};
3843 my $ahcicontroller = {};
3844 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3846 # Add iscsi initiator name if available
3847 if (my $initiator = get_initiator_name
()) {
3848 push @$devices, '-iscsi', "initiator-name=$initiator";
3851 foreach_drive
($conf, sub {
3852 my ($ds, $drive) = @_;
3854 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3855 push @$vollist, $drive->{file
};
3858 # ignore efidisk here, already added in bios/fw handling code above
3859 return if $drive->{interface
} eq 'efidisk';
3861 $use_virtio = 1 if $ds =~ m/^virtio/;
3863 if (drive_is_cdrom
($drive)) {
3864 if ($bootindex_hash->{d
}) {
3865 $drive->{bootindex
} = $bootindex_hash->{d
};
3866 $bootindex_hash->{d
} += 1;
3869 if ($bootindex_hash->{c
}) {
3870 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3871 $bootindex_hash->{c
} += 1;
3875 if($drive->{interface
} eq 'virtio'){
3876 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3879 if ($drive->{interface
} eq 'scsi') {
3881 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3883 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3884 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3887 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3888 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3889 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3890 } elsif ($drive->{iothread
}) {
3891 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3895 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3896 $queues = ",num_queues=$drive->{queues}";
3899 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3900 $scsicontroller->{$controller}=1;
3903 if ($drive->{interface
} eq 'sata') {
3904 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3905 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3906 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3907 $ahcicontroller->{$controller}=1;
3910 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3911 push @$devices, '-drive',$drive_cmd;
3912 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3915 for (my $i = 0; $i < $MAX_NETS; $i++) {
3916 next if !$conf->{"net$i"};
3917 my $d = parse_net
($conf->{"net$i"});
3920 $use_virtio = 1 if $d->{model
} eq 'virtio';
3922 if ($bootindex_hash->{n
}) {
3923 $d->{bootindex
} = $bootindex_hash->{n
};
3924 $bootindex_hash->{n
} += 1;
3927 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3928 push @$devices, '-netdev', $netdevfull;
3930 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3931 push @$devices, '-device', $netdevicefull;
3934 if ($conf->{ivshmem
}) {
3935 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
3939 $bus = print_pcie_addr
("ivshmem");
3941 $bus = print_pci_addr
("ivshmem", $bridges, $arch, $machine_type);
3944 my $ivshmem_name = $ivshmem->{name
} // $vmid;
3945 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
3947 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
3948 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
3953 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3958 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3960 while (my ($k, $v) = each %$bridges) {
3961 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3962 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3966 push @$cmd, @$devices;
3967 push @$cmd, '-rtc', join(',', @$rtcFlags)
3968 if scalar(@$rtcFlags);
3969 push @$cmd, '-machine', join(',', @$machineFlags)
3970 if scalar(@$machineFlags);
3971 push @$cmd, '-global', join(',', @$globalFlags)
3972 if scalar(@$globalFlags);
3975 if ($conf->{args
}) {
3976 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3980 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3985 return "${var_run_tmpdir}/$vmid.vnc";
3991 my $res = vm_mon_cmd
($vmid, 'query-spice');
3993 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3997 my ($vmid, $qga, $name) = @_;
3998 my $sockettype = $qga ?
'qga' : 'qmp';
3999 my $ext = $name ?
'-'.$name : '';
4000 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
4005 return "${var_run_tmpdir}/$vmid.pid";
4008 sub vm_devices_list
{
4011 my $res = vm_mon_cmd
($vmid, 'query-pci');
4012 my $devices_to_check = [];
4014 foreach my $pcibus (@$res) {
4015 push @$devices_to_check, @{$pcibus->{devices
}},
4018 while (@$devices_to_check) {
4020 for my $d (@$devices_to_check) {
4021 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4022 next if !$d->{'pci_bridge'};
4024 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
4025 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
4027 $devices_to_check = $to_check;
4030 my $resblock = vm_mon_cmd
($vmid, 'query-block');
4031 foreach my $block (@$resblock) {
4032 if($block->{device
} =~ m/^drive-(\S+)/){
4037 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
4038 foreach my $mice (@$resmice) {
4039 if ($mice->{name
} eq 'QEMU HID Tablet') {
4040 $devices->{tablet
} = 1;
4045 # for usb devices there is no query-usb
4046 # but we can iterate over the entries in
4047 # qom-list path=/machine/peripheral
4048 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
4049 foreach my $per (@$resperipheral) {
4050 if ($per->{name
} =~ m/^usb\d+$/) {
4051 $devices->{$per->{name
}} = 1;
4059 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4061 my $q35 = machine_type_is_q35
($conf);
4063 my $devices_list = vm_devices_list
($vmid);
4064 return 1 if defined($devices_list->{$deviceid});
4066 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
4068 if ($deviceid eq 'tablet') {
4070 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4072 } elsif ($deviceid eq 'keyboard') {
4074 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4076 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4078 die "usb hotplug currently not reliable\n";
4079 # since we can't reliably hot unplug all added usb devices
4080 # and usb passthrough disables live migration
4081 # we disable usb hotplugging for now
4082 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
4084 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4086 qemu_iothread_add
($vmid, $deviceid, $device);
4088 qemu_driveadd
($storecfg, $vmid, $device);
4089 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4091 qemu_deviceadd
($vmid, $devicefull);
4092 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4094 eval { qemu_drivedel
($vmid, $deviceid); };
4099 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4102 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4103 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4104 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4106 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4108 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4109 qemu_iothread_add
($vmid, $deviceid, $device);
4110 $devicefull .= ",iothread=iothread-$deviceid";
4113 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4114 $devicefull .= ",num_queues=$device->{queues}";
4117 qemu_deviceadd
($vmid, $devicefull);
4118 qemu_deviceaddverify
($vmid, $deviceid);
4120 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4122 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4123 qemu_driveadd
($storecfg, $vmid, $device);
4125 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4126 eval { qemu_deviceadd
($vmid, $devicefull); };
4128 eval { qemu_drivedel
($vmid, $deviceid); };
4133 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4135 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4137 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4138 my $use_old_bios_files = undef;
4139 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4141 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4142 qemu_deviceadd
($vmid, $netdevicefull);
4144 qemu_deviceaddverify
($vmid, $deviceid);
4145 qemu_set_link_status
($vmid, $deviceid, !$device->{link_down
});
4148 eval { qemu_netdevdel
($vmid, $deviceid); };
4153 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4156 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4157 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4159 qemu_deviceadd
($vmid, $devicefull);
4160 qemu_deviceaddverify
($vmid, $deviceid);
4163 die "can't hotplug device '$deviceid'\n";
4169 # fixme: this should raise exceptions on error!
4170 sub vm_deviceunplug
{
4171 my ($vmid, $conf, $deviceid) = @_;
4173 my $devices_list = vm_devices_list
($vmid);
4174 return 1 if !defined($devices_list->{$deviceid});
4176 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4178 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4180 qemu_devicedel
($vmid, $deviceid);
4182 } elsif ($deviceid =~ m/^usb\d+$/) {
4184 die "usb hotplug currently not reliable\n";
4185 # when unplugging usb devices this way,
4186 # there may be remaining usb controllers/hubs
4187 # so we disable it for now
4188 qemu_devicedel
($vmid, $deviceid);
4189 qemu_devicedelverify
($vmid, $deviceid);
4191 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4193 qemu_devicedel
($vmid, $deviceid);
4194 qemu_devicedelverify
($vmid, $deviceid);
4195 qemu_drivedel
($vmid, $deviceid);
4196 qemu_iothread_del
($conf, $vmid, $deviceid);
4198 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4200 qemu_devicedel
($vmid, $deviceid);
4201 qemu_devicedelverify
($vmid, $deviceid);
4202 qemu_iothread_del
($conf, $vmid, $deviceid);
4204 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4206 qemu_devicedel
($vmid, $deviceid);
4207 qemu_drivedel
($vmid, $deviceid);
4208 qemu_deletescsihw
($conf, $vmid, $deviceid);
4210 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4212 qemu_devicedel
($vmid, $deviceid);
4213 qemu_devicedelverify
($vmid, $deviceid);
4214 qemu_netdevdel
($vmid, $deviceid);
4217 die "can't unplug device '$deviceid'\n";
4223 sub qemu_deviceadd
{
4224 my ($vmid, $devicefull) = @_;
4226 $devicefull = "driver=".$devicefull;
4227 my %options = split(/[=,]/, $devicefull);
4229 vm_mon_cmd
($vmid, "device_add" , %options);
4232 sub qemu_devicedel
{
4233 my ($vmid, $deviceid) = @_;
4235 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4238 sub qemu_iothread_add
{
4239 my($vmid, $deviceid, $device) = @_;
4241 if ($device->{iothread
}) {
4242 my $iothreads = vm_iothreads_list
($vmid);
4243 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4247 sub qemu_iothread_del
{
4248 my($conf, $vmid, $deviceid) = @_;
4250 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4251 if ($device->{iothread
}) {
4252 my $iothreads = vm_iothreads_list
($vmid);
4253 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4257 sub qemu_objectadd
{
4258 my($vmid, $objectid, $qomtype) = @_;
4260 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4265 sub qemu_objectdel
{
4266 my($vmid, $objectid) = @_;
4268 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4274 my ($storecfg, $vmid, $device) = @_;
4276 my $drive = print_drive_full
($storecfg, $vmid, $device);
4277 $drive =~ s/\\/\\\\/g;
4278 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4280 # If the command succeeds qemu prints: "OK
"
4281 return 1 if $ret =~ m/OK/s;
4283 die "adding drive failed
: $ret\n";
4287 my($vmid, $deviceid) = @_;
4289 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4292 return 1 if $ret eq "";
4294 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4295 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4297 die "deleting drive
$deviceid failed
: $ret\n";
4300 sub qemu_deviceaddverify {
4301 my ($vmid, $deviceid) = @_;
4303 for (my $i = 0; $i <= 5; $i++) {
4304 my $devices_list = vm_devices_list($vmid);
4305 return 1 if defined($devices_list->{$deviceid});
4309 die "error on hotplug device
'$deviceid'\n";
4313 sub qemu_devicedelverify {
4314 my ($vmid, $deviceid) = @_;
4316 # need to verify that the device is correctly removed as device_del
4317 # is async and empty return is not reliable
4319 for (my $i = 0; $i <= 5; $i++) {
4320 my $devices_list = vm_devices_list($vmid);
4321 return 1 if !defined($devices_list->{$deviceid});
4325 die "error on hot-unplugging device
'$deviceid'\n";
4328 sub qemu_findorcreatescsihw {
4329 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4331 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4333 my $scsihwid="$controller_prefix$controller";
4334 my $devices_list = vm_devices_list($vmid);
4336 if(!defined($devices_list->{$scsihwid})) {
4337 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4343 sub qemu_deletescsihw {
4344 my ($conf, $vmid, $opt) = @_;
4346 my $device = parse_drive($opt, $conf->{$opt});
4348 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4349 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4353 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4355 my $devices_list = vm_devices_list($vmid);
4356 foreach my $opt (keys %{$devices_list}) {
4357 if (PVE::QemuServer::is_valid_drivename($opt)) {
4358 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4359 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4365 my $scsihwid="scsihw
$controller";
4367 vm_deviceunplug($vmid, $conf, $scsihwid);
4372 sub qemu_add_pci_bridge {
4373 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4379 print_pci_addr($device, $bridges, $arch, $machine_type);
4381 while (my ($k, $v) = each %$bridges) {
4384 return 1 if !defined($bridgeid) || $bridgeid < 1;
4386 my $bridge = "pci
.$bridgeid";
4387 my $devices_list = vm_devices_list($vmid);
4389 if (!defined($devices_list->{$bridge})) {
4390 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4396 sub qemu_set_link_status {
4397 my ($vmid, $device, $up) = @_;
4399 vm_mon_cmd($vmid, "set_link
", name => $device,
4400 up => $up ? JSON::true : JSON::false);
4403 sub qemu_netdevadd {
4404 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4406 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4407 my %options = split(/[=,]/, $netdev);
4409 vm_mon_cmd($vmid, "netdev_add
", %options);
4413 sub qemu_netdevdel {
4414 my ($vmid, $deviceid) = @_;
4416 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4419 sub qemu_usb_hotplug {
4420 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4424 # remove the old one first
4425 vm_deviceunplug($vmid, $conf, $deviceid);
4427 # check if xhci controller is necessary and available
4428 if ($device->{usb3}) {
4430 my $devicelist = vm_devices_list($vmid);
4432 if (!$devicelist->{xhci}) {
4433 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4434 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4437 my $d = parse_usb_device($device->{host});
4438 $d->{usb3} = $device->{usb3};
4441 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4444 sub qemu_cpu_hotplug {
4445 my ($vmid, $conf, $vcpus) = @_;
4447 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4450 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4451 $sockets = $conf->{sockets} if $conf->{sockets};
4452 my $cores = $conf->{cores} || 1;
4453 my $maxcpus = $sockets * $cores;
4455 $vcpus = $maxcpus if !$vcpus;
4457 die "you can
't add more vcpus than maxcpus\n"
4458 if $vcpus > $maxcpus;
4460 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4462 if ($vcpus < $currentvcpus) {
4464 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4466 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4467 qemu_devicedel($vmid, "cpu$i");
4469 my $currentrunningvcpus = undef;
4471 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4472 last if scalar(@{$currentrunningvcpus}) == $i-1;
4473 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4477 #update conf after each succesfull cpu unplug
4478 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4479 PVE::QemuConfig->write_config($vmid, $conf);
4482 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4488 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4489 die "vcpus in running vm does not match its configuration\n"
4490 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4492 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4494 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4495 my $cpustr = print_cpu_device($conf, $i);
4496 qemu_deviceadd($vmid, $cpustr);
4499 my $currentrunningvcpus = undef;
4501 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4502 last if scalar(@{$currentrunningvcpus}) == $i;
4503 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4507 #update conf after each succesfull cpu hotplug
4508 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4509 PVE::QemuConfig->write_config($vmid, $conf);
4513 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4514 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4519 sub qemu_block_set_io_throttle {
4520 my ($vmid, $deviceid,
4521 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4522 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4523 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4524 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4526 return if !check_running($vmid) ;
4528 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4530 bps_rd => int($bps_rd),
4531 bps_wr => int($bps_wr),
4533 iops_rd => int($iops_rd),
4534 iops_wr => int($iops_wr),
4535 bps_max => int($bps_max),
4536 bps_rd_max => int($bps_rd_max),
4537 bps_wr_max => int($bps_wr_max),
4538 iops_max => int($iops_max),
4539 iops_rd_max => int($iops_rd_max),
4540 iops_wr_max => int($iops_wr_max),
4541 bps_max_length => int($bps_max_length),
4542 bps_rd_max_length => int($bps_rd_max_length),
4543 bps_wr_max_length => int($bps_wr_max_length),
4544 iops_max_length => int($iops_max_length),
4545 iops_rd_max_length => int($iops_rd_max_length),
4546 iops_wr_max_length => int($iops_wr_max_length),
4551 # old code, only used to shutdown old VM after update
4553 my ($fh, $timeout) = @_;
4555 my $sel = new IO::Select;
4562 while (scalar (@ready = $sel->can_read($timeout))) {
4564 if ($count = $fh->sysread($buf, 8192)) {
4565 if ($buf =~ /^(.*)\(qemu\) $/s) {
4572 if (!defined($count)) {
4579 die "monitor read timeout\n" if !scalar(@ready);
4584 sub qemu_block_resize {
4585 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4587 my $running = check_running($vmid);
4589 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4591 return if !$running;
4593 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4597 sub qemu_volume_snapshot {
4598 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4600 my $running = check_running($vmid);
4602 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4603 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4605 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4609 sub qemu_volume_snapshot_delete {
4610 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4612 my $running = check_running($vmid);
4617 my $conf = PVE::QemuConfig->load_config($vmid);
4618 foreach_drive($conf, sub {
4619 my ($ds, $drive) = @_;
4620 $running = 1 if $drive->{file} eq $volid;
4624 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4625 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4627 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4631 sub set_migration_caps {
4637 "auto-converge" => 1,
4639 "x-rdma-pin-all" => 0,
4644 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4646 for my $supported_capability (@$supported_capabilities) {
4648 capability => $supported_capability->{capability},
4649 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4653 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4656 my $fast_plug_option = {
4664 'vmstatestorage
' => 1,
4668 # hotplug changes in [PENDING]
4669 # $selection hash can be used to only apply specified options, for
4670 # example: { cores => 1 } (only apply changed 'cores
')
4671 # $errors ref is used to return error messages
4672 sub vmconfig_hotplug_pending {
4673 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4675 my $defaults = load_defaults();
4676 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4678 # commit values which do not have any impact on running VM first
4679 # Note: those option cannot raise errors, we we do not care about
4680 # $selection and always apply them.
4682 my $add_error = sub {
4683 my ($opt, $msg) = @_;
4684 $errors->{$opt} = "hotplug problem - $msg";
4688 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4689 if ($fast_plug_option->{$opt}) {
4690 $conf->{$opt} = $conf->{pending}->{$opt};
4691 delete $conf->{pending}->{$opt};
4697 PVE::QemuConfig->write_config($vmid, $conf);
4698 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4701 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4703 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4704 while (my ($opt, $force) = each %$pending_delete_hash) {
4705 next if $selection && !$selection->{$opt};
4707 if ($opt eq 'hotplug
') {
4708 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4709 } elsif ($opt eq 'tablet
') {
4710 die "skip\n" if !$hotplug_features->{usb};
4711 if ($defaults->{tablet}) {
4712 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4713 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4714 if $arch eq 'aarch64
';
4716 vm_deviceunplug($vmid, $conf, 'tablet
');
4717 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4719 } elsif ($opt =~ m/^usb\d+/) {
4721 # since we cannot reliably hot unplug usb devices
4722 # we are disabling it
4723 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4724 vm_deviceunplug($vmid, $conf, $opt);
4725 } elsif ($opt eq 'vcpus
') {
4726 die "skip\n" if !$hotplug_features->{cpu};
4727 qemu_cpu_hotplug($vmid, $conf, undef);
4728 } elsif ($opt eq 'balloon
') {
4729 # enable balloon device is not hotpluggable
4730 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4731 # here we reset the ballooning value to memory
4732 my $balloon = $conf->{memory} || $defaults->{memory};
4733 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4734 } elsif ($fast_plug_option->{$opt}) {
4736 } elsif ($opt =~ m/^net(\d+)$/) {
4737 die "skip\n" if !$hotplug_features->{network};
4738 vm_deviceunplug($vmid, $conf, $opt);
4739 } elsif (is_valid_drivename($opt)) {
4740 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4741 vm_deviceunplug($vmid, $conf, $opt);
4742 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4743 } elsif ($opt =~ m/^memory$/) {
4744 die "skip\n" if !$hotplug_features->{memory};
4745 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4746 } elsif ($opt eq 'cpuunits
') {
4747 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4748 } elsif ($opt eq 'cpulimit
') {
4749 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4755 &$add_error($opt, $err) if $err ne "skip\n";
4757 # save new config if hotplug was successful
4758 delete $conf->{$opt};
4759 vmconfig_undelete_pending_option($conf, $opt);
4760 PVE::QemuConfig->write_config($vmid, $conf);
4761 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4765 my $apply_pending_cloudinit;
4766 $apply_pending_cloudinit = sub {
4767 my ($key, $value) = @_;
4768 $apply_pending_cloudinit = sub {}; # once is enough
4770 my @cloudinit_opts = keys %$confdesc_cloudinit;
4771 foreach my $opt (keys %{$conf->{pending}}) {
4772 next if !grep { $_ eq $opt } @cloudinit_opts;
4773 $conf->{$opt} = delete $conf->{pending}->{$opt};
4776 my $new_conf = { %$conf };
4777 $new_conf->{$key} = $value;
4778 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4781 foreach my $opt (keys %{$conf->{pending}}) {
4782 next if $selection && !$selection->{$opt};
4783 my $value = $conf->{pending}->{$opt};
4785 if ($opt eq 'hotplug
') {
4786 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4787 } elsif ($opt eq 'tablet
') {
4788 die "skip\n" if !$hotplug_features->{usb};
4790 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4791 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4792 if $arch eq 'aarch64
';
4793 } elsif ($value == 0) {
4794 vm_deviceunplug($vmid, $conf, 'tablet
');
4795 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4797 } elsif ($opt =~ m/^usb\d+$/) {
4799 # since we cannot reliably hot unplug usb devices
4800 # we are disabling it
4801 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4802 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4803 die "skip\n" if !$d;
4804 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4805 } elsif ($opt eq 'vcpus
') {
4806 die "skip\n" if !$hotplug_features->{cpu};
4807 qemu_cpu_hotplug($vmid, $conf, $value);
4808 } elsif ($opt eq 'balloon
') {
4809 # enable/disable balloning device is not hotpluggable
4810 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4811 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4812 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4814 # allow manual ballooning if shares is set to zero
4815 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4816 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4817 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4819 } elsif ($opt =~ m/^net(\d+)$/) {
4820 # some changes can be done without hotplug
4821 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4822 $vmid, $opt, $value, $arch, $machine_type);
4823 } elsif (is_valid_drivename($opt)) {
4824 # some changes can be done without hotplug
4825 my $drive = parse_drive($opt, $value);
4826 if (drive_is_cloudinit($drive)) {
4827 &$apply_pending_cloudinit($opt, $value);
4829 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4830 $vmid, $opt, $value, 1, $arch, $machine_type);
4831 } elsif ($opt =~ m/^memory$/) { #dimms
4832 die "skip\n" if !$hotplug_features->{memory};
4833 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4834 } elsif ($opt eq 'cpuunits
') {
4835 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4836 } elsif ($opt eq 'cpulimit
') {
4837 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4838 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4840 die "skip\n"; # skip non-hot-pluggable options
4844 &$add_error($opt, $err) if $err ne "skip\n";
4846 # save new config if hotplug was successful
4847 $conf->{$opt} = $value;
4848 delete $conf->{pending}->{$opt};
4849 PVE::QemuConfig->write_config($vmid, $conf);
4850 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4855 sub try_deallocate_drive {
4856 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4858 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4859 my $volid = $drive->{file};
4860 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4861 my $sid = PVE::Storage::parse_volume_id($volid);
4862 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4864 # check if the disk is really unused
4865 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4866 if is_volume_in_use($storecfg, $conf, $key, $volid);
4867 PVE::Storage::vdisk_free($storecfg, $volid);
4870 # If vm is not owner of this disk remove from config
4878 sub vmconfig_delete_or_detach_drive {
4879 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4881 my $drive = parse_drive($opt, $conf->{$opt});
4883 my $rpcenv = PVE::RPCEnvironment::get();
4884 my $authuser = $rpcenv->get_user();
4887 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4888 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4890 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4894 sub vmconfig_apply_pending {
4895 my ($vmid, $conf, $storecfg) = @_;
4899 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4900 while (my ($opt, $force) = each %$pending_delete_hash) {
4901 die "internal error" if $opt =~ m/^unused/;
4902 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4903 if (!defined($conf->{$opt})) {
4904 vmconfig_undelete_pending_option($conf, $opt);
4905 PVE::QemuConfig->write_config($vmid, $conf);
4906 } elsif (is_valid_drivename($opt)) {
4907 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4908 vmconfig_undelete_pending_option($conf, $opt);
4909 delete $conf->{$opt};
4910 PVE::QemuConfig->write_config($vmid, $conf);
4912 vmconfig_undelete_pending_option($conf, $opt);
4913 delete $conf->{$opt};
4914 PVE::QemuConfig->write_config($vmid, $conf);
4918 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4920 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4921 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4923 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4924 # skip if nothing changed
4925 } elsif (is_valid_drivename($opt)) {
4926 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4927 if defined($conf->{$opt});
4928 $conf->{$opt} = $conf->{pending}->{$opt};
4930 $conf->{$opt} = $conf->{pending}->{$opt};
4933 delete $conf->{pending}->{$opt};
4934 PVE::QemuConfig->write_config($vmid, $conf);
4938 my $safe_num_ne = sub {
4941 return 0 if !defined($a) && !defined($b);
4942 return 1 if !defined($a);
4943 return 1 if !defined($b);
4948 my $safe_string_ne = sub {
4951 return 0 if !defined($a) && !defined($b);
4952 return 1 if !defined($a);
4953 return 1 if !defined($b);
4958 sub vmconfig_update_net {
4959 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4961 my $newnet = parse_net($value);
4963 if ($conf->{$opt}) {
4964 my $oldnet = parse_net($conf->{$opt});
4966 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4967 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4968 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4969 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4971 # for non online change, we try to hot-unplug
4972 die "skip\n" if !$hotplug;
4973 vm_deviceunplug($vmid, $conf, $opt);
4976 die "internal error" if $opt !~ m/net(\d+)/;
4977 my $iface = "tap${vmid}i$1";
4979 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4980 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4981 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4982 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4983 PVE::Network::tap_unplug($iface);
4984 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4985 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4986 # Rate can be applied on its own but any change above needs to
4987 # include the rate in tap_plug since OVS resets everything.
4988 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4991 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4992 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5000 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5006 sub vmconfig_update_disk {
5007 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
5009 # fixme: do we need force?
5011 my $drive = parse_drive($opt, $value);
5013 if ($conf->{$opt}) {
5015 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5017 my $media = $drive->{media} || 'disk
';
5018 my $oldmedia = $old_drive->{media} || 'disk
';
5019 die "unable to change media type\n" if $media ne $oldmedia;
5021 if (!drive_is_cdrom($old_drive)) {
5023 if ($drive->{file} ne $old_drive->{file}) {
5025 die "skip\n" if !$hotplug;
5027 # unplug and register as unused
5028 vm_deviceunplug($vmid, $conf, $opt);
5029 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5032 # update existing disk
5034 # skip non hotpluggable value
5035 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5036 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5037 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5038 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5043 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5044 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5045 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5046 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5047 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5048 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5049 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5050 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5051 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5052 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5053 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5054 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5055 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5056 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5057 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5058 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5059 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5060 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5062 qemu_block_set_io_throttle($vmid,"drive-$opt",
5063 ($drive->{mbps} || 0)*1024*1024,
5064 ($drive->{mbps_rd} || 0)*1024*1024,
5065 ($drive->{mbps_wr} || 0)*1024*1024,
5066 $drive->{iops} || 0,
5067 $drive->{iops_rd} || 0,
5068 $drive->{iops_wr} || 0,
5069 ($drive->{mbps_max} || 0)*1024*1024,
5070 ($drive->{mbps_rd_max} || 0)*1024*1024,
5071 ($drive->{mbps_wr_max} || 0)*1024*1024,
5072 $drive->{iops_max} || 0,
5073 $drive->{iops_rd_max} || 0,
5074 $drive->{iops_wr_max} || 0,
5075 $drive->{bps_max_length} || 1,
5076 $drive->{bps_rd_max_length} || 1,
5077 $drive->{bps_wr_max_length} || 1,
5078 $drive->{iops_max_length} || 1,
5079 $drive->{iops_rd_max_length} || 1,
5080 $drive->{iops_wr_max_length} || 1);
5089 if ($drive->{file} eq 'none
') {
5090 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5091 if (drive_is_cloudinit($old_drive)) {
5092 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5095 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5096 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5097 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5105 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5107 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5108 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5112 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5113 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5115 PVE::QemuConfig->lock_config($vmid, sub {
5116 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5118 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5120 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5122 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5124 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5125 vmconfig_apply_pending($vmid, $conf, $storecfg);
5126 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5129 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5131 my $defaults = load_defaults();
5133 # set environment variable useful inside network script
5134 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5136 my $local_volumes = {};
5138 if ($targetstorage) {
5139 foreach_drive($conf, sub {
5140 my ($ds, $drive) = @_;
5142 return if drive_is_cdrom($drive);
5144 my $volid = $drive->{file};
5148 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5150 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5151 return if $scfg->{shared};
5152 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5157 foreach my $opt (sort keys %$local_volumes) {
5159 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5160 my $drive = parse_drive($opt, $conf->{$opt});
5162 #if remote storage is specified, use default format
5163 if ($targetstorage && $targetstorage ne "1") {
5164 $storeid = $targetstorage;
5165 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5166 $format = $defFormat;
5168 #else we use same format than original
5169 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5170 $format = qemu_img_format($scfg, $volid);
5173 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5174 my $newdrive = $drive;
5175 $newdrive->{format} = $format;
5176 $newdrive->{file} = $newvolid;
5177 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5178 $local_volumes->{$opt} = $drivestr;
5179 #pass drive to conf for command line
5180 $conf->{$opt} = $drivestr;
5184 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
5186 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5188 my $migrate_port = 0;
5191 if ($statefile eq 'tcp
') {
5192 my $localip = "localhost";
5193 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5194 my $nodename = PVE::INotify::nodename();
5196 if (!defined($migration_type)) {
5197 if (defined($datacenterconf->{migration}->{type})) {
5198 $migration_type = $datacenterconf->{migration}->{type};
5200 $migration_type = 'secure
';
5204 if ($migration_type eq 'insecure
') {
5205 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5206 if ($migrate_network_addr) {
5207 $localip = $migrate_network_addr;
5209 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5212 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5215 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5216 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5217 $migrate_uri = "tcp:${localip}:${migrate_port}";
5218 push @$cmd, '-incoming
', $migrate_uri;
5221 } elsif ($statefile eq 'unix
') {
5222 # should be default for secure migrations as a ssh TCP forward
5223 # tunnel is not deterministic reliable ready and fails regurarly
5224 # to set up in time, so use UNIX socket forwards
5225 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5226 unlink $socket_addr;
5228 $migrate_uri = "unix:$socket_addr";
5230 push @$cmd, '-incoming
', $migrate_uri;
5234 push @$cmd, '-loadstate
', $statefile;
5241 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5242 my $d = parse_hostpci($conf->{"hostpci$i"});
5244 my $pcidevices = $d->{pciid};
5245 foreach my $pcidevice (@$pcidevices) {
5246 my $pciid = $pcidevice->{id};
5248 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5249 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5250 die "no pci device info for device '$pciid'\n" if !$info;
5253 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5254 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5256 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5257 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5258 die "can
't reset pci device '$pciid'\n"
5259 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5264 PVE::Storage::activate_volumes($storecfg, $vollist);
5266 if (-d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
5268 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5269 outfunc => sub {}, errfunc => sub {});
5273 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5274 : $defaults->{cpuunits};
5276 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5277 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5280 Slice => 'qemu
.slice
',
5282 CPUShares => $cpuunits
5285 if (my $cpulimit = $conf->{cpulimit}) {
5286 $properties{CPUQuota} = int($cpulimit * 100);
5288 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5290 my $run_qemu = sub {
5291 PVE::Tools::run_fork sub {
5292 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5293 run_command($cmd, %run_params);
5297 if ($conf->{hugepages}) {
5300 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5301 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5303 PVE::QemuServer::Memory::hugepages_mount();
5304 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5306 eval { $run_qemu->() };
5308 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5312 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5314 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5317 eval { $run_qemu->() };
5321 # deactivate volumes if start fails
5322 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5323 die "start failed: $err";
5326 print "migration listens on $migrate_uri\n" if $migrate_uri;
5328 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5329 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5333 #start nbd server for storage migration
5334 if ($targetstorage) {
5335 my $nodename = PVE::INotify::nodename();
5336 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5337 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5338 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5339 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5341 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5343 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5345 foreach my $opt (sort keys %$local_volumes) {
5346 my $volid = $local_volumes->{$opt};
5347 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5348 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5349 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5353 if ($migratedfrom) {
5355 set_migration_caps($vmid);
5360 print "spice listens on port $spice_port\n";
5361 if ($spice_ticket) {
5362 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5363 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5368 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5369 if !$statefile && $conf->{balloon};
5371 foreach my $opt (keys %$conf) {
5372 next if $opt !~ m/^net\d+$/;
5373 my $nicconf = parse_net($conf->{$opt});
5374 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5378 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5379 path => "machine/peripheral/balloon0",
5380 property => "guest-stats-polling-interval",
5381 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5383 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start
');
5388 my ($vmid, $execute, %params) = @_;
5390 my $cmd = { execute => $execute, arguments => \%params };
5391 vm_qmp_command($vmid, $cmd);
5394 sub vm_mon_cmd_nocheck {
5395 my ($vmid, $execute, %params) = @_;
5397 my $cmd = { execute => $execute, arguments => \%params };
5398 vm_qmp_command($vmid, $cmd, 1);
5401 sub vm_qmp_command {
5402 my ($vmid, $cmd, $nocheck) = @_;
5407 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5408 $timeout = $cmd->{arguments}->{timeout};
5409 delete $cmd->{arguments}->{timeout};
5413 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5414 my $sname = qmp_socket($vmid);
5415 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5416 my $qmpclient = PVE::QMPClient->new();
5418 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5420 die "unable to open monitor socket\n";
5424 syslog("err", "VM $vmid qmp command failed - $err");
5431 sub vm_human_monitor_command {
5432 my ($vmid, $cmdline) = @_;
5437 execute => 'human-monitor-command
',
5438 arguments => { 'command-line
' => $cmdline},
5441 return vm_qmp_command($vmid, $cmd);
5444 sub vm_commandline {
5445 my ($storecfg, $vmid, $snapname) = @_;
5447 my $conf = PVE::QemuConfig->load_config($vmid);
5450 my $snapshot = $conf->{snapshots}->{$snapname};
5451 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5453 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
5458 my $defaults = load_defaults();
5460 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5462 return PVE::Tools::cmd2string($cmd);
5466 my ($vmid, $skiplock) = @_;
5468 PVE::QemuConfig->lock_config($vmid, sub {
5470 my $conf = PVE::QemuConfig->load_config($vmid);
5472 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5474 vm_mon_cmd($vmid, "system_reset");
5478 sub get_vm_volumes {
5482 foreach_volid($conf, sub {
5483 my ($volid, $attr) = @_;
5485 return if $volid =~ m|^/|;
5487 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5490 push @$vollist, $volid;
5496 sub vm_stop_cleanup {
5497 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5502 my $vollist = get_vm_volumes($conf);
5503 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5506 foreach my $ext (qw(mon qmp pid vnc qga)) {
5507 unlink "/var/run/qemu-server/${vmid}.$ext";
5510 if ($conf->{ivshmem
}) {
5511 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5512 # just delete it for now, VMs which have this already open do not
5513 # are affected, but new VMs will get a separated one. If this
5514 # becomes an issue we either add some sort of ref-counting or just
5515 # add a "don't delete on stop" flag to the ivshmem format.
5516 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5519 foreach my $key (keys %$conf) {
5520 next if $key !~ m/^hostpci(\d+)$/;
5521 my $hostpciindex = $1;
5522 my $d = parse_hostpci
($conf->{$key});
5523 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5525 foreach my $pci (@{$d->{pciid
}}) {
5526 my $pciid = $pci->{id
};
5527 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5531 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5533 warn $@ if $@; # avoid errors - just warn
5536 # Note: use $nockeck to skip tests if VM configuration file exists.
5537 # We need that when migration VMs to other nodes (files already moved)
5538 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5540 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5542 $force = 1 if !defined($force) && !$shutdown;
5545 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5546 kill 15, $pid if $pid;
5547 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5548 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5552 PVE
::QemuConfig-
>lock_config($vmid, sub {
5554 my $pid = check_running
($vmid, $nocheck);
5559 $conf = PVE
::QemuConfig-
>load_config($vmid);
5560 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5561 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5562 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5563 $timeout = $opts->{down
} if $opts->{down
};
5565 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5568 $timeout = 60 if !defined($timeout);
5572 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5573 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5575 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5578 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5585 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5590 if ($count >= $timeout) {
5592 warn "VM still running - terminating now with SIGTERM\n";
5595 die "VM quit/powerdown failed - got timeout\n";
5598 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5603 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5606 die "VM quit/powerdown failed\n";
5614 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5619 if ($count >= $timeout) {
5620 warn "VM still running - terminating now with SIGKILL\n";
5625 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5630 my ($vmid, $skiplock) = @_;
5632 PVE
::QemuConfig-
>lock_config($vmid, sub {
5634 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5636 PVE
::QemuConfig-
>check_lock($conf)
5637 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5639 vm_mon_cmd
($vmid, "stop");
5644 my ($vmid, $skiplock, $nocheck) = @_;
5646 PVE
::QemuConfig-
>lock_config($vmid, sub {
5648 my $res = vm_mon_cmd
($vmid, 'query-status');
5649 my $resume_cmd = 'cont';
5651 if ($res->{status
} && $res->{status
} eq 'suspended') {
5652 $resume_cmd = 'system_wakeup';
5657 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5659 PVE
::QemuConfig-
>check_lock($conf)
5660 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5662 vm_mon_cmd
($vmid, $resume_cmd);
5665 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5671 my ($vmid, $skiplock, $key) = @_;
5673 PVE
::QemuConfig-
>lock_config($vmid, sub {
5675 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5677 # there is no qmp command, so we use the human monitor command
5678 vm_human_monitor_command
($vmid, "sendkey $key");
5683 my ($storecfg, $vmid, $skiplock) = @_;
5685 PVE
::QemuConfig-
>lock_config($vmid, sub {
5687 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5689 if (!check_running
($vmid)) {
5690 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5692 die "VM $vmid is running - destroy failed\n";
5697 # vzdump restore implementaion
5699 sub tar_archive_read_firstfile
{
5700 my $archive = shift;
5702 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5704 # try to detect archive type first
5705 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5706 die "unable to open file '$archive'\n";
5707 my $firstfile = <$fh>;
5711 die "ERROR: archive contaions no data\n" if !$firstfile;
5717 sub tar_restore_cleanup
{
5718 my ($storecfg, $statfile) = @_;
5720 print STDERR
"starting cleanup\n";
5722 if (my $fd = IO
::File-
>new($statfile, "r")) {
5723 while (defined(my $line = <$fd>)) {
5724 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5727 if ($volid =~ m
|^/|) {
5728 unlink $volid || die 'unlink failed\n';
5730 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5732 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5734 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5736 print STDERR
"unable to parse line in statfile - $line";
5743 sub restore_archive
{
5744 my ($archive, $vmid, $user, $opts) = @_;
5746 my $format = $opts->{format
};
5749 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5750 $format = 'tar' if !$format;
5752 } elsif ($archive =~ m/\.tar$/) {
5753 $format = 'tar' if !$format;
5754 } elsif ($archive =~ m/.tar.lzo$/) {
5755 $format = 'tar' if !$format;
5757 } elsif ($archive =~ m/\.vma$/) {
5758 $format = 'vma' if !$format;
5759 } elsif ($archive =~ m/\.vma\.gz$/) {
5760 $format = 'vma' if !$format;
5762 } elsif ($archive =~ m/\.vma\.lzo$/) {
5763 $format = 'vma' if !$format;
5766 $format = 'vma' if !$format; # default
5769 # try to detect archive format
5770 if ($format eq 'tar') {
5771 return restore_tar_archive
($archive, $vmid, $user, $opts);
5773 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5777 sub restore_update_config_line
{
5778 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5780 return if $line =~ m/^\#qmdump\#/;
5781 return if $line =~ m/^\#vzdump\#/;
5782 return if $line =~ m/^lock:/;
5783 return if $line =~ m/^unused\d+:/;
5784 return if $line =~ m/^parent:/;
5785 return if $line =~ m/^template:/; # restored VM is never a template
5787 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5788 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5789 # try to convert old 1.X settings
5790 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5791 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5792 my ($model, $macaddr) = split(/\=/, $devconfig);
5793 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5796 bridge
=> "vmbr$ind",
5797 macaddr
=> $macaddr,
5799 my $netstr = print_net
($net);
5801 print $outfd "net$cookie->{netcount}: $netstr\n";
5802 $cookie->{netcount
}++;
5804 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5805 my ($id, $netstr) = ($1, $2);
5806 my $net = parse_net
($netstr);
5807 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5808 $netstr = print_net
($net);
5809 print $outfd "$id: $netstr\n";
5810 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5813 my $di = parse_drive
($virtdev, $value);
5814 if (defined($di->{backup
}) && !$di->{backup
}) {
5815 print $outfd "#$line";
5816 } elsif ($map->{$virtdev}) {
5817 delete $di->{format
}; # format can change on restore
5818 $di->{file
} = $map->{$virtdev};
5819 $value = print_drive
($vmid, $di);
5820 print $outfd "$virtdev: $value\n";
5824 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5826 if ($vmgenid ne '0') {
5827 # always generate a new vmgenid if there was a valid one setup
5828 $vmgenid = generate_uuid
();
5830 print $outfd "vmgenid: $vmgenid\n";
5831 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5832 my ($uuid, $uuid_str);
5833 UUID
::generate
($uuid);
5834 UUID
::unparse
($uuid, $uuid_str);
5835 my $smbios1 = parse_smbios1
($2);
5836 $smbios1->{uuid
} = $uuid_str;
5837 print $outfd $1.print_smbios1
($smbios1)."\n";
5844 my ($cfg, $vmid) = @_;
5846 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5848 my $volid_hash = {};
5849 foreach my $storeid (keys %$info) {
5850 foreach my $item (@{$info->{$storeid}}) {
5851 next if !($item->{volid
} && $item->{size
});
5852 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5853 $volid_hash->{$item->{volid
}} = $item;
5860 sub is_volume_in_use
{
5861 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5863 my $path = PVE
::Storage
::path
($storecfg, $volid);
5865 my $scan_config = sub {
5866 my ($cref, $snapname) = @_;
5868 foreach my $key (keys %$cref) {
5869 my $value = $cref->{$key};
5870 if (is_valid_drivename
($key)) {
5871 next if $skip_drive && $key eq $skip_drive;
5872 my $drive = parse_drive
($key, $value);
5873 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5874 return 1 if $volid eq $drive->{file
};
5875 if ($drive->{file
} =~ m!^/!) {
5876 return 1 if $drive->{file
} eq $path;
5878 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5880 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5882 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5890 return 1 if &$scan_config($conf);
5894 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5895 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5901 sub update_disksize
{
5902 my ($vmid, $conf, $volid_hash) = @_;
5905 my $prefix = "VM $vmid:";
5907 # used and unused disks
5908 my $referenced = {};
5910 # Note: it is allowed to define multiple storages with same path (alias), so
5911 # we need to check both 'volid' and real 'path' (two different volid can point
5912 # to the same path).
5914 my $referencedpath = {};
5917 foreach my $opt (keys %$conf) {
5918 if (is_valid_drivename
($opt)) {
5919 my $drive = parse_drive
($opt, $conf->{$opt});
5920 my $volid = $drive->{file
};
5923 $referenced->{$volid} = 1;
5924 if ($volid_hash->{$volid} &&
5925 (my $path = $volid_hash->{$volid}->{path
})) {
5926 $referencedpath->{$path} = 1;
5929 next if drive_is_cdrom
($drive);
5930 next if !$volid_hash->{$volid};
5932 $drive->{size
} = $volid_hash->{$volid}->{size
};
5933 my $new = print_drive
($vmid, $drive);
5934 if ($new ne $conf->{$opt}) {
5936 $conf->{$opt} = $new;
5937 print "$prefix update disk '$opt' information.\n";
5942 # remove 'unusedX' entry if volume is used
5943 foreach my $opt (keys %$conf) {
5944 next if $opt !~ m/^unused\d+$/;
5945 my $volid = $conf->{$opt};
5946 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5947 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5948 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5950 delete $conf->{$opt};
5953 $referenced->{$volid} = 1;
5954 $referencedpath->{$path} = 1 if $path;
5957 foreach my $volid (sort keys %$volid_hash) {
5958 next if $volid =~ m/vm-$vmid-state-/;
5959 next if $referenced->{$volid};
5960 my $path = $volid_hash->{$volid}->{path
};
5961 next if !$path; # just to be sure
5962 next if $referencedpath->{$path};
5964 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5965 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5966 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5973 my ($vmid, $nolock, $dryrun) = @_;
5975 my $cfg = PVE
::Storage
::config
();
5977 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5978 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5979 foreach my $stor (keys %{$cfg->{ids
}}) {
5980 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5983 print "rescan volumes...\n";
5984 my $volid_hash = scan_volids
($cfg, $vmid);
5986 my $updatefn = sub {
5989 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5991 PVE
::QemuConfig-
>check_lock($conf);
5994 foreach my $volid (keys %$volid_hash) {
5995 my $info = $volid_hash->{$volid};
5996 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5999 my $changes = update_disksize
($vmid, $conf, $vm_volids);
6001 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
6004 if (defined($vmid)) {
6008 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6011 my $vmlist = config_list
();
6012 foreach my $vmid (keys %$vmlist) {
6016 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6022 sub restore_vma_archive
{
6023 my ($archive, $vmid, $user, $opts, $comp) = @_;
6025 my $readfrom = $archive;
6027 my $cfg = PVE
::Storage
::config
();
6029 my $bwlimit = $opts->{bwlimit
};
6031 my $dbg_cmdstring = '';
6032 my $add_pipe = sub {
6034 push @$commands, $cmd;
6035 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6036 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6041 if ($archive eq '-') {
6044 # If we use a backup from a PVE defined storage we also consider that
6045 # storage's rate limit:
6046 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6047 if (defined($volid)) {
6048 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6049 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6051 print STDERR
"applying read rate limit: $readlimit\n";
6052 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6053 $add_pipe->($cstream);
6060 if ($comp eq 'gzip') {
6061 $cmd = ['zcat', $readfrom];
6062 } elsif ($comp eq 'lzop') {
6063 $cmd = ['lzop', '-d', '-c', $readfrom];
6065 die "unknown compression method '$comp'\n";
6070 my $tmpdir = "/var/tmp/vzdumptmp$$";
6073 # disable interrupts (always do cleanups)
6077 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6079 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6080 POSIX
::mkfifo
($mapfifo, 0600);
6083 my $openfifo = sub {
6084 open($fifofh, '>', $mapfifo) || die $!;
6087 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6094 my $rpcenv = PVE
::RPCEnvironment
::get
();
6096 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6097 my $tmpfn = "$conffile.$$.tmp";
6099 # Note: $oldconf is undef if VM does not exists
6100 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6101 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6105 my $print_devmap = sub {
6106 my $virtdev_hash = {};
6108 my $cfgfn = "$tmpdir/qemu-server.conf";
6110 # we can read the config - that is already extracted
6111 my $fh = IO
::File-
>new($cfgfn, "r") ||
6112 "unable to read qemu-server.conf - $!\n";
6114 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6116 my $pve_firewall_dir = '/etc/pve/firewall';
6117 mkdir $pve_firewall_dir; # make sure the dir exists
6118 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6121 while (defined(my $line = <$fh>)) {
6122 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6123 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6124 die "archive does not contain data for drive '$virtdev'\n"
6125 if !$devinfo->{$devname};
6126 if (defined($opts->{storage
})) {
6127 $storeid = $opts->{storage
} || 'local';
6128 } elsif (!$storeid) {
6131 $format = 'raw' if !$format;
6132 $devinfo->{$devname}->{devname
} = $devname;
6133 $devinfo->{$devname}->{virtdev
} = $virtdev;
6134 $devinfo->{$devname}->{format
} = $format;
6135 $devinfo->{$devname}->{storeid
} = $storeid;
6137 # check permission on storage
6138 my $pool = $opts->{pool
}; # todo: do we need that?
6139 if ($user ne 'root@pam') {
6140 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6143 $storage_limits{$storeid} = $bwlimit;
6145 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6149 foreach my $key (keys %storage_limits) {
6150 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6152 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6153 $storage_limits{$key} = $limit * 1024;
6156 foreach my $devname (keys %$devinfo) {
6157 die "found no device mapping information for device '$devname'\n"
6158 if !$devinfo->{$devname}->{virtdev
};
6161 # create empty/temp config
6163 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6164 foreach_drive
($oldconf, sub {
6165 my ($ds, $drive) = @_;
6167 return if drive_is_cdrom
($drive);
6169 my $volid = $drive->{file
};
6171 return if !$volid || $volid =~ m
|^/|;
6173 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6174 return if !$path || !$owner || ($owner != $vmid);
6176 # Note: only delete disk we want to restore
6177 # other volumes will become unused
6178 if ($virtdev_hash->{$ds}) {
6179 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6186 # delete vmstate files
6187 # since after the restore we have no snapshots anymore
6188 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6189 my $snap = $oldconf->{snapshots
}->{$snapname};
6190 if ($snap->{vmstate
}) {
6191 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6200 foreach my $virtdev (sort keys %$virtdev_hash) {
6201 my $d = $virtdev_hash->{$virtdev};
6202 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6203 my $storeid = $d->{storeid
};
6204 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6207 if (my $limit = $storage_limits{$storeid}) {
6208 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6211 # test if requested format is supported
6212 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6213 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6214 $d->{format
} = $defFormat if !$supported;
6216 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6217 $d->{format
}, undef, $alloc_size);
6218 print STDERR
"new volume ID is '$volid'\n";
6219 $d->{volid
} = $volid;
6220 my $path = PVE
::Storage
::path
($cfg, $volid);
6222 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6224 my $write_zeros = 1;
6225 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6229 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6231 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6232 $map->{$virtdev} = $volid;
6235 $fh->seek(0, 0) || die "seek failed - $!\n";
6237 my $outfd = new IO
::File
($tmpfn, "w") ||
6238 die "unable to write config for VM $vmid\n";
6240 my $cookie = { netcount
=> 0 };
6241 while (defined(my $line = <$fh>)) {
6242 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6255 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6256 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6258 $oldtimeout = alarm($timeout);
6265 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6266 my ($dev_id, $size, $devname) = ($1, $2, $3);
6267 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6268 } elsif ($line =~ m/^CTIME: /) {
6269 # we correctly received the vma config, so we can disable
6270 # the timeout now for disk allocation (set to 10 minutes, so
6271 # that we always timeout if something goes wrong)
6274 print $fifofh "done\n";
6275 my $tmp = $oldtimeout || 0;
6276 $oldtimeout = undef;
6282 print "restore vma archive: $dbg_cmdstring\n";
6283 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6287 alarm($oldtimeout) if $oldtimeout;
6290 foreach my $devname (keys %$devinfo) {
6291 my $volid = $devinfo->{$devname}->{volid
};
6292 push @$vollist, $volid if $volid;
6295 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6303 foreach my $devname (keys %$devinfo) {
6304 my $volid = $devinfo->{$devname}->{volid
};
6307 if ($volid =~ m
|^/|) {
6308 unlink $volid || die 'unlink failed\n';
6310 PVE
::Storage
::vdisk_free
($cfg, $volid);
6312 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6314 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6321 rename($tmpfn, $conffile) ||
6322 die "unable to commit configuration file '$conffile'\n";
6324 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6326 eval { rescan
($vmid, 1); };
6330 sub restore_tar_archive
{
6331 my ($archive, $vmid, $user, $opts) = @_;
6333 if ($archive ne '-') {
6334 my $firstfile = tar_archive_read_firstfile
($archive);
6335 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6336 if $firstfile ne 'qemu-server.conf';
6339 my $storecfg = PVE
::Storage
::config
();
6341 # destroy existing data - keep empty config
6342 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6343 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6345 my $tocmd = "/usr/lib/qemu-server/qmextract";
6347 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6348 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6349 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6350 $tocmd .= ' --info' if $opts->{info
};
6352 # tar option "xf" does not autodetect compression when read from STDIN,
6353 # so we pipe to zcat
6354 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6355 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6357 my $tmpdir = "/var/tmp/vzdumptmp$$";
6360 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6361 local $ENV{VZDUMP_VMID
} = $vmid;
6362 local $ENV{VZDUMP_USER
} = $user;
6364 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6365 my $tmpfn = "$conffile.$$.tmp";
6367 # disable interrupts (always do cleanups)
6371 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6379 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6381 if ($archive eq '-') {
6382 print "extracting archive from STDIN\n";
6383 run_command
($cmd, input
=> "<&STDIN");
6385 print "extracting archive '$archive'\n";
6389 return if $opts->{info
};
6393 my $statfile = "$tmpdir/qmrestore.stat";
6394 if (my $fd = IO
::File-
>new($statfile, "r")) {
6395 while (defined (my $line = <$fd>)) {
6396 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6397 $map->{$1} = $2 if $1;
6399 print STDERR
"unable to parse line in statfile - $line\n";
6405 my $confsrc = "$tmpdir/qemu-server.conf";
6407 my $srcfd = new IO
::File
($confsrc, "r") ||
6408 die "unable to open file '$confsrc'\n";
6410 my $outfd = new IO
::File
($tmpfn, "w") ||
6411 die "unable to write config for VM $vmid\n";
6413 my $cookie = { netcount
=> 0 };
6414 while (defined (my $line = <$srcfd>)) {
6415 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6427 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6434 rename $tmpfn, $conffile ||
6435 die "unable to commit configuration file '$conffile'\n";
6437 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6439 eval { rescan
($vmid, 1); };
6443 sub foreach_storage_used_by_vm
{
6444 my ($conf, $func) = @_;
6448 foreach_drive
($conf, sub {
6449 my ($ds, $drive) = @_;
6450 return if drive_is_cdrom
($drive);
6452 my $volid = $drive->{file
};
6454 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6455 $sidhash->{$sid} = $sid if $sid;
6458 foreach my $sid (sort keys %$sidhash) {
6463 sub do_snapshots_with_qemu
{
6464 my ($storecfg, $volid) = @_;
6466 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6468 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6469 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6473 if ($volid =~ m/\.(qcow2|qed)$/){
6480 sub qga_check_running
{
6481 my ($vmid, $nowarn) = @_;
6483 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6485 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6491 sub template_create
{
6492 my ($vmid, $conf, $disk) = @_;
6494 my $storecfg = PVE
::Storage
::config
();
6496 foreach_drive
($conf, sub {
6497 my ($ds, $drive) = @_;
6499 return if drive_is_cdrom
($drive);
6500 return if $disk && $ds ne $disk;
6502 my $volid = $drive->{file
};
6503 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6505 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6506 $drive->{file
} = $voliddst;
6507 $conf->{$ds} = print_drive
($vmid, $drive);
6508 PVE
::QemuConfig-
>write_config($vmid, $conf);
6512 sub qemu_img_convert
{
6513 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6515 my $storecfg = PVE
::Storage
::config
();
6516 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6517 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6519 if ($src_storeid && $dst_storeid) {
6521 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6523 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6524 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6526 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6527 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6529 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6530 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6533 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6534 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6535 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6536 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6537 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6538 if ($is_zero_initialized) {
6539 push @$cmd, "zeroinit:$dst_path";
6541 push @$cmd, $dst_path;
6546 if($line =~ m/\((\S+)\/100\
%\)/){
6548 my $transferred = int($size * $percent / 100);
6549 my $remaining = $size - $transferred;
6551 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6556 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6558 die "copy failed: $err" if $err;
6562 sub qemu_img_format
{
6563 my ($scfg, $volname) = @_;
6565 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6572 sub qemu_drive_mirror
{
6573 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6575 $jobs = {} if !$jobs;
6579 $jobs->{"drive-$drive"} = {};
6581 if ($dst_volid =~ /^nbd:/) {
6582 $qemu_target = $dst_volid;
6585 my $storecfg = PVE
::Storage
::config
();
6586 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6588 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6590 $format = qemu_img_format
($dst_scfg, $dst_volname);
6592 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6594 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6597 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6598 $opts->{format
} = $format if $format;
6600 print "drive mirror is starting for drive-$drive\n";
6602 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6605 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6606 die "mirroring error: $err";
6609 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6612 sub qemu_drive_mirror_monitor
{
6613 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6616 my $err_complete = 0;
6619 die "storage migration timed out\n" if $err_complete > 300;
6621 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6623 my $running_mirror_jobs = {};
6624 foreach my $stat (@$stats) {
6625 next if $stat->{type
} ne 'mirror';
6626 $running_mirror_jobs->{$stat->{device
}} = $stat;
6629 my $readycounter = 0;
6631 foreach my $job (keys %$jobs) {
6633 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6634 print "$job : finished\n";
6635 delete $jobs->{$job};
6639 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6641 my $busy = $running_mirror_jobs->{$job}->{busy
};
6642 my $ready = $running_mirror_jobs->{$job}->{ready
};
6643 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6644 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6645 my $remaining = $total - $transferred;
6646 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6648 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6651 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6654 last if scalar(keys %$jobs) == 0;
6656 if ($readycounter == scalar(keys %$jobs)) {
6657 print "all mirroring jobs are ready \n";
6658 last if $skipcomplete; #do the complete later
6660 if ($vmiddst && $vmiddst != $vmid) {
6661 my $agent_running = $qga && qga_check_running
($vmid);
6662 if ($agent_running) {
6663 print "freeze filesystem\n";
6664 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6666 print "suspend vm\n";
6667 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6670 # if we clone a disk for a new target vm, we don't switch the disk
6671 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6673 if ($agent_running) {
6674 print "unfreeze filesystem\n";
6675 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6677 print "resume vm\n";
6678 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6684 foreach my $job (keys %$jobs) {
6685 # try to switch the disk if source and destination are on the same guest
6686 print "$job: Completing block job...\n";
6688 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6689 if ($@ =~ m/cannot be completed/) {
6690 print "$job: Block job cannot be completed, try again.\n";
6693 print "$job: Completed successfully.\n";
6694 $jobs->{$job}->{complete
} = 1;
6705 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6706 die "mirroring error: $err";
6711 sub qemu_blockjobs_cancel
{
6712 my ($vmid, $jobs) = @_;
6714 foreach my $job (keys %$jobs) {
6715 print "$job: Cancelling block job\n";
6716 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6717 $jobs->{$job}->{cancel
} = 1;
6721 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6723 my $running_jobs = {};
6724 foreach my $stat (@$stats) {
6725 $running_jobs->{$stat->{device
}} = $stat;
6728 foreach my $job (keys %$jobs) {
6730 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6731 print "$job: Done.\n";
6732 delete $jobs->{$job};
6736 last if scalar(keys %$jobs) == 0;
6743 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6744 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6749 print "create linked clone of drive $drivename ($drive->{file})\n";
6750 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6751 push @$newvollist, $newvolid;
6754 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6755 $storeid = $storage if $storage;
6757 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6758 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6760 print "create full clone of drive $drivename ($drive->{file})\n";
6762 if (drive_is_cloudinit
($drive)) {
6763 $name = "vm-$newvmid-cloudinit";
6765 # cloudinit only supports raw and qcow2 atm:
6766 if ($dst_format eq 'qcow2') {
6768 } elsif ($dst_format ne 'raw') {
6769 die "clone: unhandled format for cloudinit image\n";
6772 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6773 push @$newvollist, $newvolid;
6775 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6777 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6778 if (!$running || $snapname) {
6779 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6782 my $kvmver = get_running_qemu_version
($vmid);
6783 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6784 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6785 if $drive->{iothread
};
6788 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6792 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6795 $disk->{format
} = undef;
6796 $disk->{file
} = $newvolid;
6797 $disk->{size
} = $size;
6802 # this only works if VM is running
6803 sub get_current_qemu_machine
{
6806 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6807 my $res = vm_qmp_command
($vmid, $cmd);
6809 my ($current, $default);
6810 foreach my $e (@$res) {
6811 $default = $e->{name
} if $e->{'is-default'};
6812 $current = $e->{name
} if $e->{'is-current'};
6815 # fallback to the default machine if current is not supported by qemu
6816 return $current || $default || 'pc';
6819 sub get_running_qemu_version
{
6821 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6822 my $res = vm_qmp_command
($vmid, $cmd);
6823 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6826 sub qemu_machine_feature_enabled
{
6827 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6832 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6834 $current_major = $3;
6835 $current_minor = $4;
6837 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6839 $current_major = $1;
6840 $current_minor = $2;
6843 return 1 if $current_major > $version_major ||
6844 ($current_major == $version_major &&
6845 $current_minor >= $version_minor);
6848 sub qemu_machine_pxe
{
6849 my ($vmid, $conf, $machine) = @_;
6851 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6853 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6860 sub qemu_use_old_bios_files
{
6861 my ($machine_type) = @_;
6863 return if !$machine_type;
6865 my $use_old_bios_files = undef;
6867 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6869 $use_old_bios_files = 1;
6871 my $kvmver = kvm_user_version
();
6872 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6873 # load new efi bios files on migration. So this hack is required to allow
6874 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6875 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6876 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6879 return ($use_old_bios_files, $machine_type);
6882 sub create_efidisk
($$$$$) {
6883 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6885 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6886 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6888 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6889 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6890 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6892 my $path = PVE
::Storage
::path
($storecfg, $volid);
6894 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6896 die "Copying EFI vars image failed: $@" if $@;
6898 return ($volid, $vars_size);
6901 sub vm_iothreads_list
{
6904 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6907 foreach my $iothread (@$res) {
6908 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6915 my ($conf, $drive) = @_;
6919 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6921 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6927 my $controller = int($drive->{index} / $maxdev);
6928 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6930 return ($maxdev, $controller, $controller_prefix);
6933 sub add_hyperv_enlightenments
{
6934 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
6936 return if $winversion < 6;
6937 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6939 if ($gpu_passthrough || defined($hv_vendor_id)) {
6940 $hv_vendor_id //= 'proxmox';
6941 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
6944 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6945 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6946 push @$cpuFlags , 'hv_vapic';
6947 push @$cpuFlags , 'hv_time';
6949 push @$cpuFlags , 'hv_spinlocks=0xffff';
6952 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6953 push @$cpuFlags , 'hv_reset';
6954 push @$cpuFlags , 'hv_vpindex';
6955 push @$cpuFlags , 'hv_runtime';
6958 if ($winversion >= 7) {
6959 push @$cpuFlags , 'hv_relaxed';
6961 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6962 push @$cpuFlags , 'hv_synic';
6963 push @$cpuFlags , 'hv_stimer';
6968 sub windows_version
{
6971 return 0 if !$ostype;
6975 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6977 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6979 } elsif ($ostype =~ m/^win(\d+)$/) {
6986 sub resolve_dst_disk_format
{
6987 my ($storecfg, $storeid, $src_volname, $format) = @_;
6988 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6991 # if no target format is specified, use the source disk format as hint
6993 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6994 $format = qemu_img_format
($scfg, $src_volname);
7000 # test if requested format is supported - else use default
7001 my $supported = grep { $_ eq $format } @$validFormats;
7002 $format = $defFormat if !$supported;
7006 sub resolve_first_disk
{
7008 my @disks = PVE
::QemuServer
::valid_drive_names
();
7010 foreach my $ds (reverse @disks) {
7011 next if !$conf->{$ds};
7012 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
7013 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
7020 my ($uuid, $uuid_str);
7021 UUID
::generate
($uuid);
7022 UUID
::unparse
($uuid, $uuid_str);
7026 sub generate_smbios1_uuid
{
7027 return "uuid=".generate_uuid
();
7033 vm_mon_cmd
($vmid, 'nbd-server-stop');
7036 # bash completion helper
7038 sub complete_backup_archives
{
7039 my ($cmdname, $pname, $cvalue) = @_;
7041 my $cfg = PVE
::Storage
::config
();
7045 if ($cvalue =~ m/^([^:]+):/) {
7049 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7052 foreach my $id (keys %$data) {
7053 foreach my $item (@{$data->{$id}}) {
7054 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7055 push @$res, $item->{volid
} if defined($item->{volid
});
7062 my $complete_vmid_full = sub {
7065 my $idlist = vmstatus
();
7069 foreach my $id (keys %$idlist) {
7070 my $d = $idlist->{$id};
7071 if (defined($running)) {
7072 next if $d->{template
};
7073 next if $running && $d->{status
} ne 'running';
7074 next if !$running && $d->{status
} eq 'running';
7083 return &$complete_vmid_full();
7086 sub complete_vmid_stopped
{
7087 return &$complete_vmid_full(0);
7090 sub complete_vmid_running
{
7091 return &$complete_vmid_full(1);
7094 sub complete_storage
{
7096 my $cfg = PVE
::Storage
::config
();
7097 my $ids = $cfg->{ids
};
7100 foreach my $sid (keys %$ids) {
7101 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7102 next if !$ids->{$sid}->{content
}->{images
};