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);
4143 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4145 eval { qemu_netdevdel
($vmid, $deviceid); };
4150 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4153 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4154 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4156 qemu_deviceadd
($vmid, $devicefull);
4157 qemu_deviceaddverify
($vmid, $deviceid);
4160 die "can't hotplug device '$deviceid'\n";
4166 # fixme: this should raise exceptions on error!
4167 sub vm_deviceunplug
{
4168 my ($vmid, $conf, $deviceid) = @_;
4170 my $devices_list = vm_devices_list
($vmid);
4171 return 1 if !defined($devices_list->{$deviceid});
4173 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4175 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4177 qemu_devicedel
($vmid, $deviceid);
4179 } elsif ($deviceid =~ m/^usb\d+$/) {
4181 die "usb hotplug currently not reliable\n";
4182 # when unplugging usb devices this way,
4183 # there may be remaining usb controllers/hubs
4184 # so we disable it for now
4185 qemu_devicedel
($vmid, $deviceid);
4186 qemu_devicedelverify
($vmid, $deviceid);
4188 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4190 qemu_devicedel
($vmid, $deviceid);
4191 qemu_devicedelverify
($vmid, $deviceid);
4192 qemu_drivedel
($vmid, $deviceid);
4193 qemu_iothread_del
($conf, $vmid, $deviceid);
4195 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4197 qemu_devicedel
($vmid, $deviceid);
4198 qemu_devicedelverify
($vmid, $deviceid);
4199 qemu_iothread_del
($conf, $vmid, $deviceid);
4201 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4203 qemu_devicedel
($vmid, $deviceid);
4204 qemu_drivedel
($vmid, $deviceid);
4205 qemu_deletescsihw
($conf, $vmid, $deviceid);
4207 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4209 qemu_devicedel
($vmid, $deviceid);
4210 qemu_devicedelverify
($vmid, $deviceid);
4211 qemu_netdevdel
($vmid, $deviceid);
4214 die "can't unplug device '$deviceid'\n";
4220 sub qemu_deviceadd
{
4221 my ($vmid, $devicefull) = @_;
4223 $devicefull = "driver=".$devicefull;
4224 my %options = split(/[=,]/, $devicefull);
4226 vm_mon_cmd
($vmid, "device_add" , %options);
4229 sub qemu_devicedel
{
4230 my ($vmid, $deviceid) = @_;
4232 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4235 sub qemu_iothread_add
{
4236 my($vmid, $deviceid, $device) = @_;
4238 if ($device->{iothread
}) {
4239 my $iothreads = vm_iothreads_list
($vmid);
4240 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4244 sub qemu_iothread_del
{
4245 my($conf, $vmid, $deviceid) = @_;
4247 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4248 if ($device->{iothread
}) {
4249 my $iothreads = vm_iothreads_list
($vmid);
4250 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4254 sub qemu_objectadd
{
4255 my($vmid, $objectid, $qomtype) = @_;
4257 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4262 sub qemu_objectdel
{
4263 my($vmid, $objectid) = @_;
4265 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4271 my ($storecfg, $vmid, $device) = @_;
4273 my $drive = print_drive_full
($storecfg, $vmid, $device);
4274 $drive =~ s/\\/\\\\/g;
4275 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4277 # If the command succeeds qemu prints: "OK
"
4278 return 1 if $ret =~ m/OK/s;
4280 die "adding drive failed
: $ret\n";
4284 my($vmid, $deviceid) = @_;
4286 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4289 return 1 if $ret eq "";
4291 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4292 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4294 die "deleting drive
$deviceid failed
: $ret\n";
4297 sub qemu_deviceaddverify {
4298 my ($vmid, $deviceid) = @_;
4300 for (my $i = 0; $i <= 5; $i++) {
4301 my $devices_list = vm_devices_list($vmid);
4302 return 1 if defined($devices_list->{$deviceid});
4306 die "error on hotplug device
'$deviceid'\n";
4310 sub qemu_devicedelverify {
4311 my ($vmid, $deviceid) = @_;
4313 # need to verify that the device is correctly removed as device_del
4314 # is async and empty return is not reliable
4316 for (my $i = 0; $i <= 5; $i++) {
4317 my $devices_list = vm_devices_list($vmid);
4318 return 1 if !defined($devices_list->{$deviceid});
4322 die "error on hot-unplugging device
'$deviceid'\n";
4325 sub qemu_findorcreatescsihw {
4326 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4328 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4330 my $scsihwid="$controller_prefix$controller";
4331 my $devices_list = vm_devices_list($vmid);
4333 if(!defined($devices_list->{$scsihwid})) {
4334 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4340 sub qemu_deletescsihw {
4341 my ($conf, $vmid, $opt) = @_;
4343 my $device = parse_drive($opt, $conf->{$opt});
4345 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4346 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4350 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4352 my $devices_list = vm_devices_list($vmid);
4353 foreach my $opt (keys %{$devices_list}) {
4354 if (PVE::QemuServer::is_valid_drivename($opt)) {
4355 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4356 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4362 my $scsihwid="scsihw
$controller";
4364 vm_deviceunplug($vmid, $conf, $scsihwid);
4369 sub qemu_add_pci_bridge {
4370 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4376 print_pci_addr($device, $bridges, $arch, $machine_type);
4378 while (my ($k, $v) = each %$bridges) {
4381 return 1 if !defined($bridgeid) || $bridgeid < 1;
4383 my $bridge = "pci
.$bridgeid";
4384 my $devices_list = vm_devices_list($vmid);
4386 if (!defined($devices_list->{$bridge})) {
4387 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4393 sub qemu_set_link_status {
4394 my ($vmid, $device, $up) = @_;
4396 vm_mon_cmd($vmid, "set_link
", name => $device,
4397 up => $up ? JSON::true : JSON::false);
4400 sub qemu_netdevadd {
4401 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4403 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4404 my %options = split(/[=,]/, $netdev);
4406 vm_mon_cmd($vmid, "netdev_add
", %options);
4410 sub qemu_netdevdel {
4411 my ($vmid, $deviceid) = @_;
4413 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4416 sub qemu_usb_hotplug {
4417 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4421 # remove the old one first
4422 vm_deviceunplug($vmid, $conf, $deviceid);
4424 # check if xhci controller is necessary and available
4425 if ($device->{usb3}) {
4427 my $devicelist = vm_devices_list($vmid);
4429 if (!$devicelist->{xhci}) {
4430 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4431 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4434 my $d = parse_usb_device($device->{host});
4435 $d->{usb3} = $device->{usb3};
4438 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4441 sub qemu_cpu_hotplug {
4442 my ($vmid, $conf, $vcpus) = @_;
4444 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4447 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4448 $sockets = $conf->{sockets} if $conf->{sockets};
4449 my $cores = $conf->{cores} || 1;
4450 my $maxcpus = $sockets * $cores;
4452 $vcpus = $maxcpus if !$vcpus;
4454 die "you can
't add more vcpus than maxcpus\n"
4455 if $vcpus > $maxcpus;
4457 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4459 if ($vcpus < $currentvcpus) {
4461 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4463 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4464 qemu_devicedel($vmid, "cpu$i");
4466 my $currentrunningvcpus = undef;
4468 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4469 last if scalar(@{$currentrunningvcpus}) == $i-1;
4470 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4474 #update conf after each succesfull cpu unplug
4475 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4476 PVE::QemuConfig->write_config($vmid, $conf);
4479 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4485 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4486 die "vcpus in running vm does not match its configuration\n"
4487 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4489 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4491 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4492 my $cpustr = print_cpu_device($conf, $i);
4493 qemu_deviceadd($vmid, $cpustr);
4496 my $currentrunningvcpus = undef;
4498 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4499 last if scalar(@{$currentrunningvcpus}) == $i;
4500 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4504 #update conf after each succesfull cpu hotplug
4505 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4506 PVE::QemuConfig->write_config($vmid, $conf);
4510 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4511 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4516 sub qemu_block_set_io_throttle {
4517 my ($vmid, $deviceid,
4518 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4519 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4520 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4521 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4523 return if !check_running($vmid) ;
4525 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4527 bps_rd => int($bps_rd),
4528 bps_wr => int($bps_wr),
4530 iops_rd => int($iops_rd),
4531 iops_wr => int($iops_wr),
4532 bps_max => int($bps_max),
4533 bps_rd_max => int($bps_rd_max),
4534 bps_wr_max => int($bps_wr_max),
4535 iops_max => int($iops_max),
4536 iops_rd_max => int($iops_rd_max),
4537 iops_wr_max => int($iops_wr_max),
4538 bps_max_length => int($bps_max_length),
4539 bps_rd_max_length => int($bps_rd_max_length),
4540 bps_wr_max_length => int($bps_wr_max_length),
4541 iops_max_length => int($iops_max_length),
4542 iops_rd_max_length => int($iops_rd_max_length),
4543 iops_wr_max_length => int($iops_wr_max_length),
4548 # old code, only used to shutdown old VM after update
4550 my ($fh, $timeout) = @_;
4552 my $sel = new IO::Select;
4559 while (scalar (@ready = $sel->can_read($timeout))) {
4561 if ($count = $fh->sysread($buf, 8192)) {
4562 if ($buf =~ /^(.*)\(qemu\) $/s) {
4569 if (!defined($count)) {
4576 die "monitor read timeout\n" if !scalar(@ready);
4581 sub qemu_block_resize {
4582 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4584 my $running = check_running($vmid);
4586 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4588 return if !$running;
4590 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4594 sub qemu_volume_snapshot {
4595 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4597 my $running = check_running($vmid);
4599 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4600 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4602 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4606 sub qemu_volume_snapshot_delete {
4607 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4609 my $running = check_running($vmid);
4614 my $conf = PVE::QemuConfig->load_config($vmid);
4615 foreach_drive($conf, sub {
4616 my ($ds, $drive) = @_;
4617 $running = 1 if $drive->{file} eq $volid;
4621 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4622 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4624 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4628 sub set_migration_caps {
4634 "auto-converge" => 1,
4636 "x-rdma-pin-all" => 0,
4641 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4643 for my $supported_capability (@$supported_capabilities) {
4645 capability => $supported_capability->{capability},
4646 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4650 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4653 my $fast_plug_option = {
4661 'vmstatestorage
' => 1,
4665 # hotplug changes in [PENDING]
4666 # $selection hash can be used to only apply specified options, for
4667 # example: { cores => 1 } (only apply changed 'cores
')
4668 # $errors ref is used to return error messages
4669 sub vmconfig_hotplug_pending {
4670 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4672 my $defaults = load_defaults();
4673 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4675 # commit values which do not have any impact on running VM first
4676 # Note: those option cannot raise errors, we we do not care about
4677 # $selection and always apply them.
4679 my $add_error = sub {
4680 my ($opt, $msg) = @_;
4681 $errors->{$opt} = "hotplug problem - $msg";
4685 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4686 if ($fast_plug_option->{$opt}) {
4687 $conf->{$opt} = $conf->{pending}->{$opt};
4688 delete $conf->{pending}->{$opt};
4694 PVE::QemuConfig->write_config($vmid, $conf);
4695 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4698 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4700 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4701 while (my ($opt, $force) = each %$pending_delete_hash) {
4702 next if $selection && !$selection->{$opt};
4704 if ($opt eq 'hotplug
') {
4705 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4706 } elsif ($opt eq 'tablet
') {
4707 die "skip\n" if !$hotplug_features->{usb};
4708 if ($defaults->{tablet}) {
4709 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4710 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4711 if $arch eq 'aarch64
';
4713 vm_deviceunplug($vmid, $conf, 'tablet
');
4714 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4716 } elsif ($opt =~ m/^usb\d+/) {
4718 # since we cannot reliably hot unplug usb devices
4719 # we are disabling it
4720 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4721 vm_deviceunplug($vmid, $conf, $opt);
4722 } elsif ($opt eq 'vcpus
') {
4723 die "skip\n" if !$hotplug_features->{cpu};
4724 qemu_cpu_hotplug($vmid, $conf, undef);
4725 } elsif ($opt eq 'balloon
') {
4726 # enable balloon device is not hotpluggable
4727 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4728 # here we reset the ballooning value to memory
4729 my $balloon = $conf->{memory} || $defaults->{memory};
4730 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4731 } elsif ($fast_plug_option->{$opt}) {
4733 } elsif ($opt =~ m/^net(\d+)$/) {
4734 die "skip\n" if !$hotplug_features->{network};
4735 vm_deviceunplug($vmid, $conf, $opt);
4736 } elsif (is_valid_drivename($opt)) {
4737 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4738 vm_deviceunplug($vmid, $conf, $opt);
4739 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4740 } elsif ($opt =~ m/^memory$/) {
4741 die "skip\n" if !$hotplug_features->{memory};
4742 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4743 } elsif ($opt eq 'cpuunits
') {
4744 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4745 } elsif ($opt eq 'cpulimit
') {
4746 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4752 &$add_error($opt, $err) if $err ne "skip\n";
4754 # save new config if hotplug was successful
4755 delete $conf->{$opt};
4756 vmconfig_undelete_pending_option($conf, $opt);
4757 PVE::QemuConfig->write_config($vmid, $conf);
4758 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4762 my $apply_pending_cloudinit;
4763 $apply_pending_cloudinit = sub {
4764 my ($key, $value) = @_;
4765 $apply_pending_cloudinit = sub {}; # once is enough
4767 my @cloudinit_opts = keys %$confdesc_cloudinit;
4768 foreach my $opt (keys %{$conf->{pending}}) {
4769 next if !grep { $_ eq $opt } @cloudinit_opts;
4770 $conf->{$opt} = delete $conf->{pending}->{$opt};
4773 my $new_conf = { %$conf };
4774 $new_conf->{$key} = $value;
4775 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4778 foreach my $opt (keys %{$conf->{pending}}) {
4779 next if $selection && !$selection->{$opt};
4780 my $value = $conf->{pending}->{$opt};
4782 if ($opt eq 'hotplug
') {
4783 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4784 } elsif ($opt eq 'tablet
') {
4785 die "skip\n" if !$hotplug_features->{usb};
4787 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4788 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4789 if $arch eq 'aarch64
';
4790 } elsif ($value == 0) {
4791 vm_deviceunplug($vmid, $conf, 'tablet
');
4792 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4794 } elsif ($opt =~ m/^usb\d+$/) {
4796 # since we cannot reliably hot unplug usb devices
4797 # we are disabling it
4798 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4799 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4800 die "skip\n" if !$d;
4801 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4802 } elsif ($opt eq 'vcpus
') {
4803 die "skip\n" if !$hotplug_features->{cpu};
4804 qemu_cpu_hotplug($vmid, $conf, $value);
4805 } elsif ($opt eq 'balloon
') {
4806 # enable/disable balloning device is not hotpluggable
4807 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4808 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4809 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4811 # allow manual ballooning if shares is set to zero
4812 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4813 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4814 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4816 } elsif ($opt =~ m/^net(\d+)$/) {
4817 # some changes can be done without hotplug
4818 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4819 $vmid, $opt, $value, $arch, $machine_type);
4820 } elsif (is_valid_drivename($opt)) {
4821 # some changes can be done without hotplug
4822 my $drive = parse_drive($opt, $value);
4823 if (drive_is_cloudinit($drive)) {
4824 &$apply_pending_cloudinit($opt, $value);
4826 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4827 $vmid, $opt, $value, 1, $arch, $machine_type);
4828 } elsif ($opt =~ m/^memory$/) { #dimms
4829 die "skip\n" if !$hotplug_features->{memory};
4830 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4831 } elsif ($opt eq 'cpuunits
') {
4832 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4833 } elsif ($opt eq 'cpulimit
') {
4834 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4835 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4837 die "skip\n"; # skip non-hot-pluggable options
4841 &$add_error($opt, $err) if $err ne "skip\n";
4843 # save new config if hotplug was successful
4844 $conf->{$opt} = $value;
4845 delete $conf->{pending}->{$opt};
4846 PVE::QemuConfig->write_config($vmid, $conf);
4847 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4852 sub try_deallocate_drive {
4853 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4855 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4856 my $volid = $drive->{file};
4857 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4858 my $sid = PVE::Storage::parse_volume_id($volid);
4859 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4861 # check if the disk is really unused
4862 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4863 if is_volume_in_use($storecfg, $conf, $key, $volid);
4864 PVE::Storage::vdisk_free($storecfg, $volid);
4867 # If vm is not owner of this disk remove from config
4875 sub vmconfig_delete_or_detach_drive {
4876 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4878 my $drive = parse_drive($opt, $conf->{$opt});
4880 my $rpcenv = PVE::RPCEnvironment::get();
4881 my $authuser = $rpcenv->get_user();
4884 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4885 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4887 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4891 sub vmconfig_apply_pending {
4892 my ($vmid, $conf, $storecfg) = @_;
4896 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4897 while (my ($opt, $force) = each %$pending_delete_hash) {
4898 die "internal error" if $opt =~ m/^unused/;
4899 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4900 if (!defined($conf->{$opt})) {
4901 vmconfig_undelete_pending_option($conf, $opt);
4902 PVE::QemuConfig->write_config($vmid, $conf);
4903 } elsif (is_valid_drivename($opt)) {
4904 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4905 vmconfig_undelete_pending_option($conf, $opt);
4906 delete $conf->{$opt};
4907 PVE::QemuConfig->write_config($vmid, $conf);
4909 vmconfig_undelete_pending_option($conf, $opt);
4910 delete $conf->{$opt};
4911 PVE::QemuConfig->write_config($vmid, $conf);
4915 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4917 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4918 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4920 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4921 # skip if nothing changed
4922 } elsif (is_valid_drivename($opt)) {
4923 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4924 if defined($conf->{$opt});
4925 $conf->{$opt} = $conf->{pending}->{$opt};
4927 $conf->{$opt} = $conf->{pending}->{$opt};
4930 delete $conf->{pending}->{$opt};
4931 PVE::QemuConfig->write_config($vmid, $conf);
4935 my $safe_num_ne = sub {
4938 return 0 if !defined($a) && !defined($b);
4939 return 1 if !defined($a);
4940 return 1 if !defined($b);
4945 my $safe_string_ne = sub {
4948 return 0 if !defined($a) && !defined($b);
4949 return 1 if !defined($a);
4950 return 1 if !defined($b);
4955 sub vmconfig_update_net {
4956 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4958 my $newnet = parse_net($value);
4960 if ($conf->{$opt}) {
4961 my $oldnet = parse_net($conf->{$opt});
4963 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4964 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4965 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4966 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4968 # for non online change, we try to hot-unplug
4969 die "skip\n" if !$hotplug;
4970 vm_deviceunplug($vmid, $conf, $opt);
4973 die "internal error" if $opt !~ m/net(\d+)/;
4974 my $iface = "tap${vmid}i$1";
4976 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4977 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4978 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4979 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4980 PVE::Network::tap_unplug($iface);
4981 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4982 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4983 # Rate can be applied on its own but any change above needs to
4984 # include the rate in tap_plug since OVS resets everything.
4985 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4988 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4989 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4997 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
5003 sub vmconfig_update_disk {
5004 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
5006 # fixme: do we need force?
5008 my $drive = parse_drive($opt, $value);
5010 if ($conf->{$opt}) {
5012 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5014 my $media = $drive->{media} || 'disk
';
5015 my $oldmedia = $old_drive->{media} || 'disk
';
5016 die "unable to change media type\n" if $media ne $oldmedia;
5018 if (!drive_is_cdrom($old_drive)) {
5020 if ($drive->{file} ne $old_drive->{file}) {
5022 die "skip\n" if !$hotplug;
5024 # unplug and register as unused
5025 vm_deviceunplug($vmid, $conf, $opt);
5026 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
5029 # update existing disk
5031 # skip non hotpluggable value
5032 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5033 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5034 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5035 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5040 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5041 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5042 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5043 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5044 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5045 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5046 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5047 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5048 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5049 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5050 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5051 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5052 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5053 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5054 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5055 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5056 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5057 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5059 qemu_block_set_io_throttle($vmid,"drive-$opt",
5060 ($drive->{mbps} || 0)*1024*1024,
5061 ($drive->{mbps_rd} || 0)*1024*1024,
5062 ($drive->{mbps_wr} || 0)*1024*1024,
5063 $drive->{iops} || 0,
5064 $drive->{iops_rd} || 0,
5065 $drive->{iops_wr} || 0,
5066 ($drive->{mbps_max} || 0)*1024*1024,
5067 ($drive->{mbps_rd_max} || 0)*1024*1024,
5068 ($drive->{mbps_wr_max} || 0)*1024*1024,
5069 $drive->{iops_max} || 0,
5070 $drive->{iops_rd_max} || 0,
5071 $drive->{iops_wr_max} || 0,
5072 $drive->{bps_max_length} || 1,
5073 $drive->{bps_rd_max_length} || 1,
5074 $drive->{bps_wr_max_length} || 1,
5075 $drive->{iops_max_length} || 1,
5076 $drive->{iops_rd_max_length} || 1,
5077 $drive->{iops_wr_max_length} || 1);
5086 if ($drive->{file} eq 'none
') {
5087 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5088 if (drive_is_cloudinit($old_drive)) {
5089 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5092 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5093 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5094 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5102 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5104 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5105 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5109 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5110 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5112 PVE::QemuConfig->lock_config($vmid, sub {
5113 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5115 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5117 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5119 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5121 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5122 vmconfig_apply_pending($vmid, $conf, $storecfg);
5123 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5126 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5128 my $defaults = load_defaults();
5130 # set environment variable useful inside network script
5131 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5133 my $local_volumes = {};
5135 if ($targetstorage) {
5136 foreach_drive($conf, sub {
5137 my ($ds, $drive) = @_;
5139 return if drive_is_cdrom($drive);
5141 my $volid = $drive->{file};
5145 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5147 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5148 return if $scfg->{shared};
5149 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5154 foreach my $opt (sort keys %$local_volumes) {
5156 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5157 my $drive = parse_drive($opt, $conf->{$opt});
5159 #if remote storage is specified, use default format
5160 if ($targetstorage && $targetstorage ne "1") {
5161 $storeid = $targetstorage;
5162 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5163 $format = $defFormat;
5165 #else we use same format than original
5166 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5167 $format = qemu_img_format($scfg, $volid);
5170 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5171 my $newdrive = $drive;
5172 $newdrive->{format} = $format;
5173 $newdrive->{file} = $newvolid;
5174 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5175 $local_volumes->{$opt} = $drivestr;
5176 #pass drive to conf for command line
5177 $conf->{$opt} = $drivestr;
5181 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start
', 1);
5183 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5185 my $migrate_port = 0;
5188 if ($statefile eq 'tcp
') {
5189 my $localip = "localhost";
5190 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5191 my $nodename = PVE::INotify::nodename();
5193 if (!defined($migration_type)) {
5194 if (defined($datacenterconf->{migration}->{type})) {
5195 $migration_type = $datacenterconf->{migration}->{type};
5197 $migration_type = 'secure
';
5201 if ($migration_type eq 'insecure
') {
5202 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5203 if ($migrate_network_addr) {
5204 $localip = $migrate_network_addr;
5206 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5209 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5212 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5213 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5214 $migrate_uri = "tcp:${localip}:${migrate_port}";
5215 push @$cmd, '-incoming
', $migrate_uri;
5218 } elsif ($statefile eq 'unix
') {
5219 # should be default for secure migrations as a ssh TCP forward
5220 # tunnel is not deterministic reliable ready and fails regurarly
5221 # to set up in time, so use UNIX socket forwards
5222 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5223 unlink $socket_addr;
5225 $migrate_uri = "unix:$socket_addr";
5227 push @$cmd, '-incoming
', $migrate_uri;
5231 push @$cmd, '-loadstate
', $statefile;
5238 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5239 my $d = parse_hostpci($conf->{"hostpci$i"});
5241 my $pcidevices = $d->{pciid};
5242 foreach my $pcidevice (@$pcidevices) {
5243 my $pciid = $pcidevice->{id};
5245 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5246 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5247 die "no pci device info for device '$pciid'\n" if !$info;
5250 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5251 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5253 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5254 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5255 die "can
't reset pci device '$pciid'\n"
5256 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5261 PVE::Storage::activate_volumes($storecfg, $vollist);
5263 if (-d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
5265 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5266 outfunc => sub {}, errfunc => sub {});
5270 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5271 : $defaults->{cpuunits};
5273 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5274 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5277 Slice => 'qemu
.slice
',
5279 CPUShares => $cpuunits
5282 if (my $cpulimit = $conf->{cpulimit}) {
5283 $properties{CPUQuota} = int($cpulimit * 100);
5285 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5287 my $run_qemu = sub {
5288 PVE::Tools::run_fork sub {
5289 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5290 run_command($cmd, %run_params);
5294 if ($conf->{hugepages}) {
5297 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5298 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5300 PVE::QemuServer::Memory::hugepages_mount();
5301 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5303 eval { $run_qemu->() };
5305 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5309 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5311 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5314 eval { $run_qemu->() };
5318 # deactivate volumes if start fails
5319 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5320 die "start failed: $err";
5323 print "migration listens on $migrate_uri\n" if $migrate_uri;
5325 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5326 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5330 #start nbd server for storage migration
5331 if ($targetstorage) {
5332 my $nodename = PVE::INotify::nodename();
5333 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5334 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5335 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5336 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5338 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5340 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5342 foreach my $opt (sort keys %$local_volumes) {
5343 my $volid = $local_volumes->{$opt};
5344 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5345 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5346 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5350 if ($migratedfrom) {
5352 set_migration_caps($vmid);
5357 print "spice listens on port $spice_port\n";
5358 if ($spice_ticket) {
5359 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5360 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5365 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5366 if !$statefile && $conf->{balloon};
5368 foreach my $opt (keys %$conf) {
5369 next if $opt !~ m/^net\d+$/;
5370 my $nicconf = parse_net($conf->{$opt});
5371 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5375 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5376 path => "machine/peripheral/balloon0",
5377 property => "guest-stats-polling-interval",
5378 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5380 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start
');
5385 my ($vmid, $execute, %params) = @_;
5387 my $cmd = { execute => $execute, arguments => \%params };
5388 vm_qmp_command($vmid, $cmd);
5391 sub vm_mon_cmd_nocheck {
5392 my ($vmid, $execute, %params) = @_;
5394 my $cmd = { execute => $execute, arguments => \%params };
5395 vm_qmp_command($vmid, $cmd, 1);
5398 sub vm_qmp_command {
5399 my ($vmid, $cmd, $nocheck) = @_;
5404 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5405 $timeout = $cmd->{arguments}->{timeout};
5406 delete $cmd->{arguments}->{timeout};
5410 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5411 my $sname = qmp_socket($vmid);
5412 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5413 my $qmpclient = PVE::QMPClient->new();
5415 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5417 die "unable to open monitor socket\n";
5421 syslog("err", "VM $vmid qmp command failed - $err");
5428 sub vm_human_monitor_command {
5429 my ($vmid, $cmdline) = @_;
5434 execute => 'human-monitor-command
',
5435 arguments => { 'command-line
' => $cmdline},
5438 return vm_qmp_command($vmid, $cmd);
5441 sub vm_commandline {
5442 my ($storecfg, $vmid, $snapname) = @_;
5444 my $conf = PVE::QemuConfig->load_config($vmid);
5447 my $snapshot = $conf->{snapshots}->{$snapname};
5448 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5450 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
5455 my $defaults = load_defaults();
5457 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5459 return PVE::Tools::cmd2string($cmd);
5463 my ($vmid, $skiplock) = @_;
5465 PVE::QemuConfig->lock_config($vmid, sub {
5467 my $conf = PVE::QemuConfig->load_config($vmid);
5469 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5471 vm_mon_cmd($vmid, "system_reset");
5475 sub get_vm_volumes {
5479 foreach_volid($conf, sub {
5480 my ($volid, $attr) = @_;
5482 return if $volid =~ m|^/|;
5484 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5487 push @$vollist, $volid;
5493 sub vm_stop_cleanup {
5494 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5499 my $vollist = get_vm_volumes($conf);
5500 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5503 foreach my $ext (qw(mon qmp pid vnc qga)) {
5504 unlink "/var/run/qemu-server/${vmid}.$ext";
5507 if ($conf->{ivshmem
}) {
5508 my $ivshmem = PVE
::JSONSchema
::parse_property_string
($ivshmem_fmt, $conf->{ivshmem
});
5509 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name
} // $vmid);
5512 foreach my $key (keys %$conf) {
5513 next if $key !~ m/^hostpci(\d+)$/;
5514 my $hostpciindex = $1;
5515 my $d = parse_hostpci
($conf->{$key});
5516 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5518 foreach my $pci (@{$d->{pciid
}}) {
5519 my $pciid = $pci->{id
};
5520 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5524 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5526 warn $@ if $@; # avoid errors - just warn
5529 # Note: use $nockeck to skip tests if VM configuration file exists.
5530 # We need that when migration VMs to other nodes (files already moved)
5531 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5533 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5535 $force = 1 if !defined($force) && !$shutdown;
5538 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5539 kill 15, $pid if $pid;
5540 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5541 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5545 PVE
::QemuConfig-
>lock_config($vmid, sub {
5547 my $pid = check_running
($vmid, $nocheck);
5552 $conf = PVE
::QemuConfig-
>load_config($vmid);
5553 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5554 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5555 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5556 $timeout = $opts->{down
} if $opts->{down
};
5558 PVE
::GuestHelpers
::exec_hookscript
($conf, $vmid, 'pre-stop');
5561 $timeout = 60 if !defined($timeout);
5565 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5566 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5568 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5571 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5578 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5583 if ($count >= $timeout) {
5585 warn "VM still running - terminating now with SIGTERM\n";
5588 die "VM quit/powerdown failed - got timeout\n";
5591 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5596 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5599 die "VM quit/powerdown failed\n";
5607 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5612 if ($count >= $timeout) {
5613 warn "VM still running - terminating now with SIGKILL\n";
5618 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5623 my ($vmid, $skiplock) = @_;
5625 PVE
::QemuConfig-
>lock_config($vmid, sub {
5627 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5629 PVE
::QemuConfig-
>check_lock($conf)
5630 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5632 vm_mon_cmd
($vmid, "stop");
5637 my ($vmid, $skiplock, $nocheck) = @_;
5639 PVE
::QemuConfig-
>lock_config($vmid, sub {
5641 my $res = vm_mon_cmd
($vmid, 'query-status');
5642 my $resume_cmd = 'cont';
5644 if ($res->{status
} && $res->{status
} eq 'suspended') {
5645 $resume_cmd = 'system_wakeup';
5650 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5652 PVE
::QemuConfig-
>check_lock($conf)
5653 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5655 vm_mon_cmd
($vmid, $resume_cmd);
5658 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5664 my ($vmid, $skiplock, $key) = @_;
5666 PVE
::QemuConfig-
>lock_config($vmid, sub {
5668 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5670 # there is no qmp command, so we use the human monitor command
5671 vm_human_monitor_command
($vmid, "sendkey $key");
5676 my ($storecfg, $vmid, $skiplock) = @_;
5678 PVE
::QemuConfig-
>lock_config($vmid, sub {
5680 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5682 if (!check_running
($vmid)) {
5683 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5685 die "VM $vmid is running - destroy failed\n";
5690 # vzdump restore implementaion
5692 sub tar_archive_read_firstfile
{
5693 my $archive = shift;
5695 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5697 # try to detect archive type first
5698 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5699 die "unable to open file '$archive'\n";
5700 my $firstfile = <$fh>;
5704 die "ERROR: archive contaions no data\n" if !$firstfile;
5710 sub tar_restore_cleanup
{
5711 my ($storecfg, $statfile) = @_;
5713 print STDERR
"starting cleanup\n";
5715 if (my $fd = IO
::File-
>new($statfile, "r")) {
5716 while (defined(my $line = <$fd>)) {
5717 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5720 if ($volid =~ m
|^/|) {
5721 unlink $volid || die 'unlink failed\n';
5723 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5725 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5727 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5729 print STDERR
"unable to parse line in statfile - $line";
5736 sub restore_archive
{
5737 my ($archive, $vmid, $user, $opts) = @_;
5739 my $format = $opts->{format
};
5742 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5743 $format = 'tar' if !$format;
5745 } elsif ($archive =~ m/\.tar$/) {
5746 $format = 'tar' if !$format;
5747 } elsif ($archive =~ m/.tar.lzo$/) {
5748 $format = 'tar' if !$format;
5750 } elsif ($archive =~ m/\.vma$/) {
5751 $format = 'vma' if !$format;
5752 } elsif ($archive =~ m/\.vma\.gz$/) {
5753 $format = 'vma' if !$format;
5755 } elsif ($archive =~ m/\.vma\.lzo$/) {
5756 $format = 'vma' if !$format;
5759 $format = 'vma' if !$format; # default
5762 # try to detect archive format
5763 if ($format eq 'tar') {
5764 return restore_tar_archive
($archive, $vmid, $user, $opts);
5766 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5770 sub restore_update_config_line
{
5771 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5773 return if $line =~ m/^\#qmdump\#/;
5774 return if $line =~ m/^\#vzdump\#/;
5775 return if $line =~ m/^lock:/;
5776 return if $line =~ m/^unused\d+:/;
5777 return if $line =~ m/^parent:/;
5778 return if $line =~ m/^template:/; # restored VM is never a template
5780 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5781 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5782 # try to convert old 1.X settings
5783 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5784 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5785 my ($model, $macaddr) = split(/\=/, $devconfig);
5786 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5789 bridge
=> "vmbr$ind",
5790 macaddr
=> $macaddr,
5792 my $netstr = print_net
($net);
5794 print $outfd "net$cookie->{netcount}: $netstr\n";
5795 $cookie->{netcount
}++;
5797 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5798 my ($id, $netstr) = ($1, $2);
5799 my $net = parse_net
($netstr);
5800 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5801 $netstr = print_net
($net);
5802 print $outfd "$id: $netstr\n";
5803 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5806 my $di = parse_drive
($virtdev, $value);
5807 if (defined($di->{backup
}) && !$di->{backup
}) {
5808 print $outfd "#$line";
5809 } elsif ($map->{$virtdev}) {
5810 delete $di->{format
}; # format can change on restore
5811 $di->{file
} = $map->{$virtdev};
5812 $value = print_drive
($vmid, $di);
5813 print $outfd "$virtdev: $value\n";
5817 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5819 if ($vmgenid ne '0') {
5820 # always generate a new vmgenid if there was a valid one setup
5821 $vmgenid = generate_uuid
();
5823 print $outfd "vmgenid: $vmgenid\n";
5824 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5825 my ($uuid, $uuid_str);
5826 UUID
::generate
($uuid);
5827 UUID
::unparse
($uuid, $uuid_str);
5828 my $smbios1 = parse_smbios1
($2);
5829 $smbios1->{uuid
} = $uuid_str;
5830 print $outfd $1.print_smbios1
($smbios1)."\n";
5837 my ($cfg, $vmid) = @_;
5839 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5841 my $volid_hash = {};
5842 foreach my $storeid (keys %$info) {
5843 foreach my $item (@{$info->{$storeid}}) {
5844 next if !($item->{volid
} && $item->{size
});
5845 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5846 $volid_hash->{$item->{volid
}} = $item;
5853 sub is_volume_in_use
{
5854 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5856 my $path = PVE
::Storage
::path
($storecfg, $volid);
5858 my $scan_config = sub {
5859 my ($cref, $snapname) = @_;
5861 foreach my $key (keys %$cref) {
5862 my $value = $cref->{$key};
5863 if (is_valid_drivename
($key)) {
5864 next if $skip_drive && $key eq $skip_drive;
5865 my $drive = parse_drive
($key, $value);
5866 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5867 return 1 if $volid eq $drive->{file
};
5868 if ($drive->{file
} =~ m!^/!) {
5869 return 1 if $drive->{file
} eq $path;
5871 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5873 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5875 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5883 return 1 if &$scan_config($conf);
5887 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5888 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5894 sub update_disksize
{
5895 my ($vmid, $conf, $volid_hash) = @_;
5898 my $prefix = "VM $vmid:";
5900 # used and unused disks
5901 my $referenced = {};
5903 # Note: it is allowed to define multiple storages with same path (alias), so
5904 # we need to check both 'volid' and real 'path' (two different volid can point
5905 # to the same path).
5907 my $referencedpath = {};
5910 foreach my $opt (keys %$conf) {
5911 if (is_valid_drivename
($opt)) {
5912 my $drive = parse_drive
($opt, $conf->{$opt});
5913 my $volid = $drive->{file
};
5916 $referenced->{$volid} = 1;
5917 if ($volid_hash->{$volid} &&
5918 (my $path = $volid_hash->{$volid}->{path
})) {
5919 $referencedpath->{$path} = 1;
5922 next if drive_is_cdrom
($drive);
5923 next if !$volid_hash->{$volid};
5925 $drive->{size
} = $volid_hash->{$volid}->{size
};
5926 my $new = print_drive
($vmid, $drive);
5927 if ($new ne $conf->{$opt}) {
5929 $conf->{$opt} = $new;
5930 print "$prefix update disk '$opt' information.\n";
5935 # remove 'unusedX' entry if volume is used
5936 foreach my $opt (keys %$conf) {
5937 next if $opt !~ m/^unused\d+$/;
5938 my $volid = $conf->{$opt};
5939 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5940 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5941 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5943 delete $conf->{$opt};
5946 $referenced->{$volid} = 1;
5947 $referencedpath->{$path} = 1 if $path;
5950 foreach my $volid (sort keys %$volid_hash) {
5951 next if $volid =~ m/vm-$vmid-state-/;
5952 next if $referenced->{$volid};
5953 my $path = $volid_hash->{$volid}->{path
};
5954 next if !$path; # just to be sure
5955 next if $referencedpath->{$path};
5957 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5958 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5959 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5966 my ($vmid, $nolock, $dryrun) = @_;
5968 my $cfg = PVE
::Storage
::config
();
5970 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5971 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5972 foreach my $stor (keys %{$cfg->{ids
}}) {
5973 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5976 print "rescan volumes...\n";
5977 my $volid_hash = scan_volids
($cfg, $vmid);
5979 my $updatefn = sub {
5982 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5984 PVE
::QemuConfig-
>check_lock($conf);
5987 foreach my $volid (keys %$volid_hash) {
5988 my $info = $volid_hash->{$volid};
5989 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5992 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5994 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5997 if (defined($vmid)) {
6001 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6004 my $vmlist = config_list
();
6005 foreach my $vmid (keys %$vmlist) {
6009 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
6015 sub restore_vma_archive
{
6016 my ($archive, $vmid, $user, $opts, $comp) = @_;
6018 my $readfrom = $archive;
6020 my $cfg = PVE
::Storage
::config
();
6022 my $bwlimit = $opts->{bwlimit
};
6024 my $dbg_cmdstring = '';
6025 my $add_pipe = sub {
6027 push @$commands, $cmd;
6028 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6029 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
6034 if ($archive eq '-') {
6037 # If we use a backup from a PVE defined storage we also consider that
6038 # storage's rate limit:
6039 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
6040 if (defined($volid)) {
6041 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
6042 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
6044 print STDERR
"applying read rate limit: $readlimit\n";
6045 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
6046 $add_pipe->($cstream);
6053 if ($comp eq 'gzip') {
6054 $cmd = ['zcat', $readfrom];
6055 } elsif ($comp eq 'lzop') {
6056 $cmd = ['lzop', '-d', '-c', $readfrom];
6058 die "unknown compression method '$comp'\n";
6063 my $tmpdir = "/var/tmp/vzdumptmp$$";
6066 # disable interrupts (always do cleanups)
6070 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
6072 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6073 POSIX
::mkfifo
($mapfifo, 0600);
6076 my $openfifo = sub {
6077 open($fifofh, '>', $mapfifo) || die $!;
6080 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
6087 my $rpcenv = PVE
::RPCEnvironment
::get
();
6089 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6090 my $tmpfn = "$conffile.$$.tmp";
6092 # Note: $oldconf is undef if VM does not exists
6093 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6094 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6098 my $print_devmap = sub {
6099 my $virtdev_hash = {};
6101 my $cfgfn = "$tmpdir/qemu-server.conf";
6103 # we can read the config - that is already extracted
6104 my $fh = IO
::File-
>new($cfgfn, "r") ||
6105 "unable to read qemu-server.conf - $!\n";
6107 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6109 my $pve_firewall_dir = '/etc/pve/firewall';
6110 mkdir $pve_firewall_dir; # make sure the dir exists
6111 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6114 while (defined(my $line = <$fh>)) {
6115 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6116 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6117 die "archive does not contain data for drive '$virtdev'\n"
6118 if !$devinfo->{$devname};
6119 if (defined($opts->{storage
})) {
6120 $storeid = $opts->{storage
} || 'local';
6121 } elsif (!$storeid) {
6124 $format = 'raw' if !$format;
6125 $devinfo->{$devname}->{devname
} = $devname;
6126 $devinfo->{$devname}->{virtdev
} = $virtdev;
6127 $devinfo->{$devname}->{format
} = $format;
6128 $devinfo->{$devname}->{storeid
} = $storeid;
6130 # check permission on storage
6131 my $pool = $opts->{pool
}; # todo: do we need that?
6132 if ($user ne 'root@pam') {
6133 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6136 $storage_limits{$storeid} = $bwlimit;
6138 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6142 foreach my $key (keys %storage_limits) {
6143 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6145 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6146 $storage_limits{$key} = $limit * 1024;
6149 foreach my $devname (keys %$devinfo) {
6150 die "found no device mapping information for device '$devname'\n"
6151 if !$devinfo->{$devname}->{virtdev
};
6154 # create empty/temp config
6156 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6157 foreach_drive
($oldconf, sub {
6158 my ($ds, $drive) = @_;
6160 return if drive_is_cdrom
($drive);
6162 my $volid = $drive->{file
};
6164 return if !$volid || $volid =~ m
|^/|;
6166 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6167 return if !$path || !$owner || ($owner != $vmid);
6169 # Note: only delete disk we want to restore
6170 # other volumes will become unused
6171 if ($virtdev_hash->{$ds}) {
6172 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6179 # delete vmstate files
6180 # since after the restore we have no snapshots anymore
6181 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6182 my $snap = $oldconf->{snapshots
}->{$snapname};
6183 if ($snap->{vmstate
}) {
6184 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6193 foreach my $virtdev (sort keys %$virtdev_hash) {
6194 my $d = $virtdev_hash->{$virtdev};
6195 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6196 my $storeid = $d->{storeid
};
6197 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6200 if (my $limit = $storage_limits{$storeid}) {
6201 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6204 # test if requested format is supported
6205 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6206 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6207 $d->{format
} = $defFormat if !$supported;
6209 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6210 $d->{format
}, undef, $alloc_size);
6211 print STDERR
"new volume ID is '$volid'\n";
6212 $d->{volid
} = $volid;
6213 my $path = PVE
::Storage
::path
($cfg, $volid);
6215 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6217 my $write_zeros = 1;
6218 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6222 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6224 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6225 $map->{$virtdev} = $volid;
6228 $fh->seek(0, 0) || die "seek failed - $!\n";
6230 my $outfd = new IO
::File
($tmpfn, "w") ||
6231 die "unable to write config for VM $vmid\n";
6233 my $cookie = { netcount
=> 0 };
6234 while (defined(my $line = <$fh>)) {
6235 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6248 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6249 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6251 $oldtimeout = alarm($timeout);
6258 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6259 my ($dev_id, $size, $devname) = ($1, $2, $3);
6260 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6261 } elsif ($line =~ m/^CTIME: /) {
6262 # we correctly received the vma config, so we can disable
6263 # the timeout now for disk allocation (set to 10 minutes, so
6264 # that we always timeout if something goes wrong)
6267 print $fifofh "done\n";
6268 my $tmp = $oldtimeout || 0;
6269 $oldtimeout = undef;
6275 print "restore vma archive: $dbg_cmdstring\n";
6276 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6280 alarm($oldtimeout) if $oldtimeout;
6283 foreach my $devname (keys %$devinfo) {
6284 my $volid = $devinfo->{$devname}->{volid
};
6285 push @$vollist, $volid if $volid;
6288 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6296 foreach my $devname (keys %$devinfo) {
6297 my $volid = $devinfo->{$devname}->{volid
};
6300 if ($volid =~ m
|^/|) {
6301 unlink $volid || die 'unlink failed\n';
6303 PVE
::Storage
::vdisk_free
($cfg, $volid);
6305 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6307 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6314 rename($tmpfn, $conffile) ||
6315 die "unable to commit configuration file '$conffile'\n";
6317 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6319 eval { rescan
($vmid, 1); };
6323 sub restore_tar_archive
{
6324 my ($archive, $vmid, $user, $opts) = @_;
6326 if ($archive ne '-') {
6327 my $firstfile = tar_archive_read_firstfile
($archive);
6328 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6329 if $firstfile ne 'qemu-server.conf';
6332 my $storecfg = PVE
::Storage
::config
();
6334 # destroy existing data - keep empty config
6335 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6336 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6338 my $tocmd = "/usr/lib/qemu-server/qmextract";
6340 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6341 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6342 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6343 $tocmd .= ' --info' if $opts->{info
};
6345 # tar option "xf" does not autodetect compression when read from STDIN,
6346 # so we pipe to zcat
6347 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6348 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6350 my $tmpdir = "/var/tmp/vzdumptmp$$";
6353 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6354 local $ENV{VZDUMP_VMID
} = $vmid;
6355 local $ENV{VZDUMP_USER
} = $user;
6357 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6358 my $tmpfn = "$conffile.$$.tmp";
6360 # disable interrupts (always do cleanups)
6364 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6372 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6374 if ($archive eq '-') {
6375 print "extracting archive from STDIN\n";
6376 run_command
($cmd, input
=> "<&STDIN");
6378 print "extracting archive '$archive'\n";
6382 return if $opts->{info
};
6386 my $statfile = "$tmpdir/qmrestore.stat";
6387 if (my $fd = IO
::File-
>new($statfile, "r")) {
6388 while (defined (my $line = <$fd>)) {
6389 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6390 $map->{$1} = $2 if $1;
6392 print STDERR
"unable to parse line in statfile - $line\n";
6398 my $confsrc = "$tmpdir/qemu-server.conf";
6400 my $srcfd = new IO
::File
($confsrc, "r") ||
6401 die "unable to open file '$confsrc'\n";
6403 my $outfd = new IO
::File
($tmpfn, "w") ||
6404 die "unable to write config for VM $vmid\n";
6406 my $cookie = { netcount
=> 0 };
6407 while (defined (my $line = <$srcfd>)) {
6408 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6420 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6427 rename $tmpfn, $conffile ||
6428 die "unable to commit configuration file '$conffile'\n";
6430 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6432 eval { rescan
($vmid, 1); };
6436 sub foreach_storage_used_by_vm
{
6437 my ($conf, $func) = @_;
6441 foreach_drive
($conf, sub {
6442 my ($ds, $drive) = @_;
6443 return if drive_is_cdrom
($drive);
6445 my $volid = $drive->{file
};
6447 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6448 $sidhash->{$sid} = $sid if $sid;
6451 foreach my $sid (sort keys %$sidhash) {
6456 sub do_snapshots_with_qemu
{
6457 my ($storecfg, $volid) = @_;
6459 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6461 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6462 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6466 if ($volid =~ m/\.(qcow2|qed)$/){
6473 sub qga_check_running
{
6474 my ($vmid, $nowarn) = @_;
6476 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6478 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6484 sub template_create
{
6485 my ($vmid, $conf, $disk) = @_;
6487 my $storecfg = PVE
::Storage
::config
();
6489 foreach_drive
($conf, sub {
6490 my ($ds, $drive) = @_;
6492 return if drive_is_cdrom
($drive);
6493 return if $disk && $ds ne $disk;
6495 my $volid = $drive->{file
};
6496 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6498 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6499 $drive->{file
} = $voliddst;
6500 $conf->{$ds} = print_drive
($vmid, $drive);
6501 PVE
::QemuConfig-
>write_config($vmid, $conf);
6505 sub qemu_img_convert
{
6506 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6508 my $storecfg = PVE
::Storage
::config
();
6509 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6510 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6512 if ($src_storeid && $dst_storeid) {
6514 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6516 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6517 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6519 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6520 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6522 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6523 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6526 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6527 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6528 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6529 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6530 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6531 if ($is_zero_initialized) {
6532 push @$cmd, "zeroinit:$dst_path";
6534 push @$cmd, $dst_path;
6539 if($line =~ m/\((\S+)\/100\
%\)/){
6541 my $transferred = int($size * $percent / 100);
6542 my $remaining = $size - $transferred;
6544 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6549 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6551 die "copy failed: $err" if $err;
6555 sub qemu_img_format
{
6556 my ($scfg, $volname) = @_;
6558 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6565 sub qemu_drive_mirror
{
6566 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6568 $jobs = {} if !$jobs;
6572 $jobs->{"drive-$drive"} = {};
6574 if ($dst_volid =~ /^nbd:/) {
6575 $qemu_target = $dst_volid;
6578 my $storecfg = PVE
::Storage
::config
();
6579 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6581 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6583 $format = qemu_img_format
($dst_scfg, $dst_volname);
6585 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6587 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6590 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6591 $opts->{format
} = $format if $format;
6593 print "drive mirror is starting for drive-$drive\n";
6595 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6598 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6599 die "mirroring error: $err";
6602 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6605 sub qemu_drive_mirror_monitor
{
6606 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6609 my $err_complete = 0;
6612 die "storage migration timed out\n" if $err_complete > 300;
6614 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6616 my $running_mirror_jobs = {};
6617 foreach my $stat (@$stats) {
6618 next if $stat->{type
} ne 'mirror';
6619 $running_mirror_jobs->{$stat->{device
}} = $stat;
6622 my $readycounter = 0;
6624 foreach my $job (keys %$jobs) {
6626 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6627 print "$job : finished\n";
6628 delete $jobs->{$job};
6632 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6634 my $busy = $running_mirror_jobs->{$job}->{busy
};
6635 my $ready = $running_mirror_jobs->{$job}->{ready
};
6636 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6637 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6638 my $remaining = $total - $transferred;
6639 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6641 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6644 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6647 last if scalar(keys %$jobs) == 0;
6649 if ($readycounter == scalar(keys %$jobs)) {
6650 print "all mirroring jobs are ready \n";
6651 last if $skipcomplete; #do the complete later
6653 if ($vmiddst && $vmiddst != $vmid) {
6654 my $agent_running = $qga && qga_check_running
($vmid);
6655 if ($agent_running) {
6656 print "freeze filesystem\n";
6657 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6659 print "suspend vm\n";
6660 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6663 # if we clone a disk for a new target vm, we don't switch the disk
6664 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6666 if ($agent_running) {
6667 print "unfreeze filesystem\n";
6668 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6670 print "resume vm\n";
6671 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6677 foreach my $job (keys %$jobs) {
6678 # try to switch the disk if source and destination are on the same guest
6679 print "$job: Completing block job...\n";
6681 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6682 if ($@ =~ m/cannot be completed/) {
6683 print "$job: Block job cannot be completed, try again.\n";
6686 print "$job: Completed successfully.\n";
6687 $jobs->{$job}->{complete
} = 1;
6698 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6699 die "mirroring error: $err";
6704 sub qemu_blockjobs_cancel
{
6705 my ($vmid, $jobs) = @_;
6707 foreach my $job (keys %$jobs) {
6708 print "$job: Cancelling block job\n";
6709 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6710 $jobs->{$job}->{cancel
} = 1;
6714 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6716 my $running_jobs = {};
6717 foreach my $stat (@$stats) {
6718 $running_jobs->{$stat->{device
}} = $stat;
6721 foreach my $job (keys %$jobs) {
6723 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6724 print "$job: Done.\n";
6725 delete $jobs->{$job};
6729 last if scalar(keys %$jobs) == 0;
6736 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6737 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6742 print "create linked clone of drive $drivename ($drive->{file})\n";
6743 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6744 push @$newvollist, $newvolid;
6747 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6748 $storeid = $storage if $storage;
6750 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6751 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6753 print "create full clone of drive $drivename ($drive->{file})\n";
6755 if (drive_is_cloudinit
($drive)) {
6756 $name = "vm-$newvmid-cloudinit";
6758 # cloudinit only supports raw and qcow2 atm:
6759 if ($dst_format eq 'qcow2') {
6761 } elsif ($dst_format ne 'raw') {
6762 die "clone: unhandled format for cloudinit image\n";
6765 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6766 push @$newvollist, $newvolid;
6768 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6770 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6771 if (!$running || $snapname) {
6772 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6775 my $kvmver = get_running_qemu_version
($vmid);
6776 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6777 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6778 if $drive->{iothread
};
6781 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6785 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6788 $disk->{format
} = undef;
6789 $disk->{file
} = $newvolid;
6790 $disk->{size
} = $size;
6795 # this only works if VM is running
6796 sub get_current_qemu_machine
{
6799 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6800 my $res = vm_qmp_command
($vmid, $cmd);
6802 my ($current, $default);
6803 foreach my $e (@$res) {
6804 $default = $e->{name
} if $e->{'is-default'};
6805 $current = $e->{name
} if $e->{'is-current'};
6808 # fallback to the default machine if current is not supported by qemu
6809 return $current || $default || 'pc';
6812 sub get_running_qemu_version
{
6814 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6815 my $res = vm_qmp_command
($vmid, $cmd);
6816 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6819 sub qemu_machine_feature_enabled
{
6820 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6825 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6827 $current_major = $3;
6828 $current_minor = $4;
6830 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6832 $current_major = $1;
6833 $current_minor = $2;
6836 return 1 if $current_major > $version_major ||
6837 ($current_major == $version_major &&
6838 $current_minor >= $version_minor);
6841 sub qemu_machine_pxe
{
6842 my ($vmid, $conf, $machine) = @_;
6844 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6846 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6853 sub qemu_use_old_bios_files
{
6854 my ($machine_type) = @_;
6856 return if !$machine_type;
6858 my $use_old_bios_files = undef;
6860 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6862 $use_old_bios_files = 1;
6864 my $kvmver = kvm_user_version
();
6865 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6866 # load new efi bios files on migration. So this hack is required to allow
6867 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6868 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6869 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6872 return ($use_old_bios_files, $machine_type);
6875 sub create_efidisk
($$$$$) {
6876 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6878 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6879 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6881 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6882 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6883 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6885 my $path = PVE
::Storage
::path
($storecfg, $volid);
6887 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6889 die "Copying EFI vars image failed: $@" if $@;
6891 return ($volid, $vars_size);
6894 sub vm_iothreads_list
{
6897 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6900 foreach my $iothread (@$res) {
6901 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6908 my ($conf, $drive) = @_;
6912 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6914 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6920 my $controller = int($drive->{index} / $maxdev);
6921 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6923 return ($maxdev, $controller, $controller_prefix);
6926 sub add_hyperv_enlightenments
{
6927 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
6929 return if $winversion < 6;
6930 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6932 if ($gpu_passthrough || defined($hv_vendor_id)) {
6933 $hv_vendor_id //= 'proxmox';
6934 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
6937 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6938 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6939 push @$cpuFlags , 'hv_vapic';
6940 push @$cpuFlags , 'hv_time';
6942 push @$cpuFlags , 'hv_spinlocks=0xffff';
6945 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6946 push @$cpuFlags , 'hv_reset';
6947 push @$cpuFlags , 'hv_vpindex';
6948 push @$cpuFlags , 'hv_runtime';
6951 if ($winversion >= 7) {
6952 push @$cpuFlags , 'hv_relaxed';
6954 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6955 push @$cpuFlags , 'hv_synic';
6956 push @$cpuFlags , 'hv_stimer';
6961 sub windows_version
{
6964 return 0 if !$ostype;
6968 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6970 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6972 } elsif ($ostype =~ m/^win(\d+)$/) {
6979 sub resolve_dst_disk_format
{
6980 my ($storecfg, $storeid, $src_volname, $format) = @_;
6981 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6984 # if no target format is specified, use the source disk format as hint
6986 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6987 $format = qemu_img_format
($scfg, $src_volname);
6993 # test if requested format is supported - else use default
6994 my $supported = grep { $_ eq $format } @$validFormats;
6995 $format = $defFormat if !$supported;
6999 sub resolve_first_disk
{
7001 my @disks = PVE
::QemuServer
::valid_drive_names
();
7003 foreach my $ds (reverse @disks) {
7004 next if !$conf->{$ds};
7005 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
7006 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
7013 my ($uuid, $uuid_str);
7014 UUID
::generate
($uuid);
7015 UUID
::unparse
($uuid, $uuid_str);
7019 sub generate_smbios1_uuid
{
7020 return "uuid=".generate_uuid
();
7026 vm_mon_cmd
($vmid, 'nbd-server-stop');
7029 # bash completion helper
7031 sub complete_backup_archives
{
7032 my ($cmdname, $pname, $cvalue) = @_;
7034 my $cfg = PVE
::Storage
::config
();
7038 if ($cvalue =~ m/^([^:]+):/) {
7042 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
7045 foreach my $id (keys %$data) {
7046 foreach my $item (@{$data->{$id}}) {
7047 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
7048 push @$res, $item->{volid
} if defined($item->{volid
});
7055 my $complete_vmid_full = sub {
7058 my $idlist = vmstatus
();
7062 foreach my $id (keys %$idlist) {
7063 my $d = $idlist->{$id};
7064 if (defined($running)) {
7065 next if $d->{template
};
7066 next if $running && $d->{status
} ne 'running';
7067 next if !$running && $d->{status
} eq 'running';
7076 return &$complete_vmid_full();
7079 sub complete_vmid_stopped
{
7080 return &$complete_vmid_full(0);
7083 sub complete_vmid_running
{
7084 return &$complete_vmid_full(1);
7087 sub complete_storage
{
7089 my $cfg = PVE
::Storage
::config
();
7090 my $ids = $cfg->{ids
};
7093 foreach my $sid (keys %$ids) {
7094 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7095 next if !$ids->{$sid}->{content
}->{images
};